⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 util.c

📁 在Linux/Unix下面访问WINDOWS SQLSERVER 的ODBC驱动程序
💻 C
字号:
/* FreeTDS - Library of routines accessing Sybase and Microsoft databases * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005  Brian Bruns * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */#if HAVE_CONFIG_H#include <config.h>#endif /* HAVE_CONFIG_H */#include <stdarg.h>#if TIME_WITH_SYS_TIME# if HAVE_SYS_TIME_H#  include <sys/time.h>#endif# include <time.h>#else# if HAVE_SYS_TIME_H#  include <sys/time.h># else#  include <time.h># endif#endif#include <assert.h>#include <ctype.h>#include <limits.h>#include <stdio.h>#if HAVE_STDLIB_H#include <stdlib.h>#endif /* HAVE_STDLIB_H */#if HAVE_STRING_H#include <string.h>#endif /* HAVE_STRING_H */#if HAVE_UNISTD_H#include <unistd.h>#endif /* HAVE_UNISTD_H */#ifdef WIN32#include <process.h>#endif#include "tds.h"#include "tds_checks.h"#include "tdsthread.h"#ifdef DMALLOC#include <dmalloc.h>#endifTDS_RCSID(var, "$Id: util.c,v 1.83 2007/12/07 05:27:55 jklowden Exp $");voidtds_set_parent(TDSSOCKET * tds, void *the_parent){	if (tds)		tds->parent = the_parent;}void *tds_get_parent(TDSSOCKET * tds){	return (tds->parent);}/** * Set state of TDS connection, with logging and checking. * \param tds	  state information for the socket and the TDS protocol * \param state	  the new state of the connection, cf. TDS_STATE. * \return 	  the new state, which might not be \a state. */TDS_STATEtds_set_state(TDSSOCKET * tds, TDS_STATE state){	const TDS_STATE prior_state = tds->state;	static const char state_names[][10] = {		"IDLE",	        "QUERYING",	        "PENDING",	        "READING",	        "DEAD"	};	assert(state < TDS_VECTOR_SIZE(state_names));	assert(tds->state < TDS_VECTOR_SIZE(state_names));		if (state == tds->state)		return state;		switch(state) {		/* transition to READING are valid only from PENDING */	case TDS_PENDING:		if (tds->state != TDS_READING && tds->state != TDS_QUERYING) {			tdsdump_log(TDS_DBG_ERROR, "logic error: cannot change query state from %s to %s\n", 							state_names[prior_state], state_names[state]);			return tds->state;		}		tds->state = state;		break;	case TDS_READING:		if (tds->state != TDS_PENDING) {			tdsdump_log(TDS_DBG_ERROR, "logic error: cannot change query state from %s to %s\n", 							state_names[prior_state], state_names[state]);			return tds->state;		}		tds->state = state;		break;	case TDS_IDLE:		if (tds->state == TDS_DEAD && TDS_IS_SOCKET_INVALID(tds->s)) {			tdsdump_log(TDS_DBG_ERROR, "logic error: cannot change query state from %s to %s\n",				state_names[prior_state], state_names[state]);			return tds->state;		}	case TDS_DEAD:		tds->state = state;		break;	case TDS_QUERYING:		CHECK_TDS_EXTRA(tds);		if (tds->state == TDS_DEAD) {			tdsdump_log(TDS_DBG_ERROR, "logic error: cannot change query state from %s to %s\n", 							state_names[prior_state], state_names[state]);			tdserror(tds->tds_ctx, tds, TDSEWRIT, 0);			break;		} else if (tds->state != TDS_IDLE) {			tdsdump_log(TDS_DBG_ERROR, "logic error: cannot change query state from %s to %s\n", 							state_names[prior_state], state_names[state]);			tdserror(tds->tds_ctx, tds, TDSERPND, 0);			break;		}		/* TODO check this code, copied from tds_submit_prepare */		tds_free_all_results(tds);		tds->rows_affected = TDS_NO_COUNT;		tds_release_cursor(tds, tds->cur_cursor);		tds->cur_cursor = NULL;		tds->internal_sp_called = 0;		tds->state = state;		break;	default:		assert(0);		break;	}		tdsdump_log(TDS_DBG_ERROR, "Changed query state from %s to %s\n", state_names[prior_state], state_names[state]);	CHECK_TDS_EXTRA(tds);		return tds->state; }inttds_swap_bytes(unsigned char *buf, int bytes){	unsigned char tmp;	int i;	/* if (bytes % 2) { return 0 }; */	for (i = 0; i < bytes / 2; i++) {		tmp = buf[i];		buf[i] = buf[bytes - i - 1];		buf[bytes - i - 1] = tmp;	}	return bytes;}/** * Returns the version of the TDS protocol in effect for the link * as a decimal integer.   *	Typical returned values are 42, 50, 70, 80. * Also fills pversion_string unless it is null. * 	Typical pversion_string values are "4.2" and "7.0". */inttds_version(TDSSOCKET * tds_socket, char *pversion_string){	int iversion = 0;	if (tds_socket) {		iversion = 10 * tds_socket->major_version + tds_socket->minor_version;		if (pversion_string) {			sprintf(pversion_string, "%d.%d", tds_socket->major_version, tds_socket->minor_version);		}	}	return iversion;}unsigned inttds_gettime_ms(void){#ifdef WIN32	return GetTickCount();#elif defined(HAVE_GETHRTIME)	return (unsigned int) (gethrtime() / 1000000u);#elif defined(HAVE_CLOCK_GETTIME) && defined(TDS_GETTIMEMILLI_CONST)	struct timespec ts;	clock_gettime(TDS_GETTIMEMILLI_CONST, &ts);	return (unsigned int) (ts.tv_sec * 1000u + ts.tv_nsec / 1000000u);#elif defined(HAVE_GETTIMEOFDAY)	struct timeval tv;	gettimeofday(&tv, NULL);	return (unsigned int) (tv.tv_sec * 1000u + tv.tv_usec / 1000u);#else#error How to implement tds_gettime_ms ??#endif}/* * Call the client library's error handler */#define EXINFO         1#define EXUSER         2#define EXNONFATAL     3#define EXCONVERSION   4#define EXSERVER       5#define EXTIME         6#define EXPROGRAM      7#define EXRESOURCE     8#define EXCOMM         9#define EXFATAL       10#define EXCONSISTENCY 11typedef struct _tds_error_message {	TDSERRNO msgno;	int severity;	char *msgtext;} TDS_ERROR_MESSAGE;static const TDS_ERROR_MESSAGE tds_error_messages[] = 	{ { TDSEICONVIU,     EXCONVERSION,	"Buffer exhausted converting characters from client into server's character set" }	, { TDSEICONVAVAIL,  EXCONVERSION,	"Character set conversion is not available between client character set '%.*s' and "						"server character set '%.*s'" }	, { TDSEICONVO,      EXCONVERSION,	"Error converting characters into server's character set. Some character(s) could "						"not be converted" }	, { TDSEICONVI,      EXCONVERSION,	"Some character(s) could not be converted into client's character set.  "						"Unconverted bytes were changed to question marks ('?')" }	, { TDSEICONV2BIG,   EXCONVERSION,	"Some character(s) could not be converted into client's character set" }	, { TDSERPND,           EXPROGRAM,	"Attempt to initiate a new Adaptive Server operation with results pending" }	, { TDSEBTOK,              EXCOMM,	"Bad token from the server: Datastream processing out of sync" }	, { TDSECAP,               EXCOMM,	"DB-Library capabilities not accepted by the Server" }	, { TDSECAPTYP,            EXCOMM,	"Unexpected capability type in CAPABILITY datastream" }	, { TDSECLOS,              EXCOMM,	"Error in closing network connection" }	, { TDSECONN,              EXCOMM,	"Unable to connect: Adaptive Server is unavailable or does not exist" }	, { TDSEEUNR,              EXCOMM,	"Unsolicited event notification received" }	, { TDSEFCON,              EXCOMM,	"Adaptive Server connection failed" }	, { TDSENEG,               EXCOMM,	"Negotiated login attempt failed" }	, { TDSEOOB,               EXCOMM,	"Error in sending out-of-band data to the server" }	, { TDSEREAD,              EXCOMM,	"Read from the server failed" }	, { TDSETIME,              EXTIME,	"Adaptive Server connection timed out" }	, { TDSESEOF,              EXCOMM,	"Unexpected EOF from the server" }	, { TDSESOCK,              EXCOMM,	"Unable to open socket" }	, { TDSESYNC,              EXCOMM,	"Read attempted while out of synchronization with Adaptive Server" }	, { TDSEUMSG,              EXCOMM,	"Unknown message-id in MSG datastream" }	, { TDSEUSCT,              EXCOMM,	"Unable to set communications timer" }	, { TDSEUTDS,              EXCOMM,	"Unrecognized TDS version received from the server" }	, { TDSEWRIT,              EXCOMM,	"Write to the server failed" }	/* last, with masgno == 0 */	, { 0,              EXCONSISTENCY,	"unrecognized msgno" }	};	staticconst char * retname(int retcode){	switch(retcode) {	case TDS_INT_CONTINUE:		return "TDS_INT_CONTINUE";	case TDS_INT_CANCEL:		return "TDS_INT_CANCEL";	case TDS_INT_TIMEOUT:		return "TDS_INT_TIMEOUT";	}	assert(0);	return "nonesuch";}/** * \brief Call the client library's error handler (for library-generated errors only) * * The client library error handler may return:  * TDS_INT_CANCEL -- Return TDS_FAIL to the calling function.  For TDSETIME, closes the connection first.  * TDS_INT_CONTINUE -- For TDSETIME only, retry the network read/write operation. Else invalid. * TDS_INT_TIMEOUT -- For TDSETIME only, send a TDSCANCEL packet. Else invalid. * * These are Sybase semantics, but they serve all purposes.   * The application tells the library to quit, fail, retry, or attempt to cancel.  In the event of a network timeout,  * a failed operation necessarily means the connection becomes unusable, because no cancellation dialog was  * concluded with the server.   * * It is the client library's duty to call the error handler installed by the application, if any, and to interpret the * installed handler's return code.  It may return to this function one of the above codes only.  This function will not  * check the return code because there's nothing that can be done here except abort.  It is merely passed to the  * calling function, which will (we hope) DTRT.   * * \param tds_ctx	points to a TDSCONTEXT structure * \param tds		the connection structure, may be NULL if not connected * \param msgno		an enumerated libtds msgno, cf. tds.h * \param errnum	the OS errno, if it matters, else zero *  * \returns client library function's return code */inttdserror (const TDSCONTEXT * tds_ctx, TDSSOCKET * tds, int msgno, int errnum){#if 0	static const char int_exit_text[] = "FreeTDS: libtds: exiting because client error handler returned %d for msgno %d\n";	static const char int_invalid_text[] = "%s (%d) received from client library error handler for nontimeout for error %d."					       "  Treating as INT_EXIT\n";#endif	const TDS_ERROR_MESSAGE *err;	TDSMESSAGE msg;	int rc = TDS_INT_CANCEL;	tdsdump_log(TDS_DBG_FUNC, "tdserror(%p, %p, %d, %d)\n", tds_ctx, tds, msgno, errnum);	/* look up the error message */	for (err = tds_error_messages; err->msgno; ++err) {		if (err->msgno == msgno)			break;	}	CHECK_CONTEXT_EXTRA(tds_ctx);	if (tds)		CHECK_TDS_EXTRA(tds);	if (tds_ctx && tds_ctx->err_handler) {		memset(&msg, 0, sizeof(TDSMESSAGE));		msg.msgno = msgno;		msg.severity = err->severity;		msg.state = -1;		msg.server = "OpenClient";		msg.line_number = -1;		msg.message = err->msgtext;		msg.sql_state = tds_alloc_client_sqlstate(msg.msgno);				msg.oserr = errnum;		/*		 * Call client library handler.		 * The client library must return a valid code.  It is not checked again here.		 */		rc = tds_ctx->err_handler(tds_ctx, tds, &msg);		TDS_ZERO_FREE(msg.sql_state);	} 	tdsdump_log(TDS_DBG_FUNC, "tdserror: client library returned %s(%d)\n", retname(rc), rc);    	assert(!(msgno != TDSETIME && rc == TDS_INT_TIMEOUT));   /* client library should prevent */	assert(!(msgno != TDSETIME && rc == TDS_INT_CONTINUE));  /* client library should prevent */		if (msgno != TDSETIME) {		switch(rc) {		case TDS_INT_TIMEOUT:		case TDS_INT_CONTINUE:		 	tdsdump_log(TDS_DBG_FUNC, "exit: %s(%d) valid only for TDSETIME\n", retname(rc), rc);			exit(1);		default:			break;		}	} 	if (rc == TDS_INT_TIMEOUT) { 		tds_send_cancel(tds); 		rc = TDS_INT_CONTINUE; 	}  	tdsdump_log(TDS_DBG_FUNC, "tdserror: returning %s(%d)\n", retname(rc), rc);  	return rc;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -