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

📄 odbc.c

📁 在Linux/Unix下面访问WINDOWS SQLSERVER 的ODBC驱动程序
💻 C
📖 第 1 页 / 共 5 页
字号:
/* FreeTDS - Library of routines accessing Sybase and Microsoft databases * Copyright (C) 1998, 1999, 2000, 2001  Brian Bruns * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007  Frediano Ziglio * * 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. *//* * PROGRAMMER   NAME            CONTACT *============================================================== * BSB          Brian Bruns     camber@ais.org * PAH          Peter Harvey    pharvey@codebydesign.com * SMURPH       Steve Murphree  smurph@smcomp.com * *************************************************************** * DATE         PROGRAMMER  CHANGE *============================================================== *                          Original. * 03.FEB.02    PAH         Started adding use of SQLGetPrivateProfileString(). * 04.FEB.02	PAH         Fixed small error preventing SQLBindParameter from being called */#if HAVE_CONFIG_H#include <config.h>#endif /* HAVE_CONFIG_H */#include <stdarg.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 */#include <assert.h>#include <ctype.h>#include "tdsodbc.h"#include "tdsstring.h"#include "tdsconvert.h"#include "replacements.h"#ifdef DMALLOC#include <dmalloc.h>#endifTDS_RCSID(var, "$Id: odbc.c,v 1.464.2.9 2008/03/11 08:25:30 freddy77 Exp $");static SQLRETURN _SQLAllocConnect(SQLHENV henv, SQLHDBC FAR * phdbc);static SQLRETURN _SQLAllocEnv(SQLHENV FAR * phenv);static SQLRETURN _SQLAllocStmt(SQLHDBC hdbc, SQLHSTMT FAR * phstmt);static SQLRETURN _SQLAllocDesc(SQLHDBC hdbc, SQLHDESC FAR * phdesc);static SQLRETURN _SQLFreeConnect(SQLHDBC hdbc);static SQLRETURN _SQLFreeEnv(SQLHENV henv);static SQLRETURN _SQLFreeStmt(SQLHSTMT hstmt, SQLUSMALLINT fOption, int force);static SQLRETURN _SQLFreeDesc(SQLHDESC hdesc);static SQLRETURN _SQLExecute(TDS_STMT * stmt);static SQLRETURN _SQLGetConnectAttr(SQLHDBC hdbc, SQLINTEGER Attribute, SQLPOINTER Value, SQLINTEGER BufferLength,					    SQLINTEGER * StringLength);static SQLRETURN _SQLSetConnectAttr(SQLHDBC hdbc, SQLINTEGER Attribute, SQLPOINTER ValuePtr, SQLINTEGER StringLength);static SQLRETURN _SQLSetStmtAttr(SQLHSTMT hstmt, SQLINTEGER Attribute, SQLPOINTER ValuePtr, SQLINTEGER StringLength);static SQLRETURN _SQLGetStmtAttr(SQLHSTMT hstmt, SQLINTEGER Attribute, SQLPOINTER Value, SQLINTEGER BufferLength,					 SQLINTEGER * StringLength);static SQLRETURN _SQLColAttribute(SQLHSTMT hstmt, SQLUSMALLINT icol, SQLUSMALLINT fDescType, SQLPOINTER rgbDesc,					  SQLSMALLINT cbDescMax, SQLSMALLINT FAR * pcbDesc, SQLLEN FAR * pfDesc);static SQLRETURN _SQLFetch(TDS_STMT * stmt, SQLSMALLINT FetchOrientation, SQLLEN FetchOffset);static SQLRETURN odbc_populate_ird(TDS_STMT * stmt);static int odbc_errmsg_handler(const TDSCONTEXT * ctx, TDSSOCKET * tds, TDSMESSAGE * msg);static void odbc_log_unimplemented_type(const char function_name[], int fType);static void odbc_upper_column_names(TDS_STMT * stmt);static void odbc_col_setname(TDS_STMT * stmt, int colpos, const char *name);static SQLRETURN odbc_stat_execute(TDS_STMT * stmt, const char *begin, int nparams, ...);static SQLRETURN odbc_free_dynamic(TDS_STMT * stmt);static SQLRETURN odbc_free_cursor(TDS_STMT * stmt);static SQLSMALLINT odbc_swap_datetime_sql_type(SQLSMALLINT sql_type);static int odbc_process_tokens(TDS_STMT * stmt, unsigned flag);static int odbc_lock_statement(TDS_STMT* stmt);#if ENABLE_EXTRA_CHECKSstatic void odbc_ird_check(TDS_STMT * stmt);#define IRD_CHECK odbc_ird_check(stmt)#else#define IRD_CHECK#endif/** * \defgroup odbc_api ODBC API * Functions callable by \c ODBC client programs *//* utils to check handles */#define CHECK_HDBC  if ( SQL_NULL_HDBC  == hdbc || !IS_HDBC(hdbc) ) return SQL_INVALID_HANDLE;#define CHECK_HSTMT if ( SQL_NULL_HSTMT == hstmt || !IS_HSTMT(hstmt) ) return SQL_INVALID_HANDLE;#define CHECK_HENV  if ( SQL_NULL_HENV  == henv || !IS_HENV(henv) ) return SQL_INVALID_HANDLE;#define CHECK_HDESC if ( SQL_NULL_HDESC == hdesc || !IS_HDESC(hdesc) ) return SQL_INVALID_HANDLE;#define INIT_HSTMT \	TDS_STMT *stmt = (TDS_STMT*)hstmt; \	CHECK_HSTMT; \	CHECK_STMT_EXTRA(stmt); \	odbc_errs_reset(&stmt->errs); \#define INIT_HDBC \	TDS_DBC *dbc = (TDS_DBC*)hdbc; \	CHECK_HDBC; \	CHECK_DBC_EXTRA(dbc); \	odbc_errs_reset(&dbc->errs); \#define INIT_HENV \	TDS_ENV *env = (TDS_ENV*)henv; \	CHECK_HENV; \	CHECK_ENV_EXTRA(env); \	odbc_errs_reset(&env->errs); \#define INIT_HDESC \	TDS_DESC *desc = (TDS_DESC*)hdesc; \	CHECK_HDESC; \	CHECK_DESC_EXTRA(desc); \	odbc_errs_reset(&desc->errs); \#define IS_VALID_LEN(len) ((len) >= 0 || (len) == SQL_NTS || (len) == SQL_NULL_DATA)#define ODBC_SAFE_ERROR(stmt) \	do { \		if (!stmt->errs.num_errors) \			odbc_errs_add(&stmt->errs, "HY000", "Unknown error"); \	} while(0)#define DEFAULT_QUERY_TIMEOUT (~((SQLUINTEGER) 0))/* * Note: I *HATE* hungarian notation, it has to be the most idiotic thing * I've ever seen. So, you will note it is avoided other than in the function * declarations. "Gee, let's make our code totally hard to read and they'll * beg for GUI tools" * Bah! */static voidodbc_col_setname(TDS_STMT * stmt, int colpos, const char *name){#if ENABLE_EXTRA_CHECKS	TDSRESULTINFO *resinfo;#endif	IRD_CHECK;#if ENABLE_EXTRA_CHECKS	if (colpos > 0 && stmt->dbc->tds_socket != NULL && (resinfo = stmt->dbc->tds_socket->current_results) != NULL) {		if (colpos <= resinfo->num_cols) {			/* no overflow possible, name is always shorter */			strcpy(resinfo->columns[colpos - 1]->column_name, name);			resinfo->columns[colpos - 1]->column_namelen = strlen(name);			if (resinfo->columns[colpos - 1]->table_column_name)				TDS_ZERO_FREE(resinfo->columns[colpos - 1]->table_column_name);		}	}#endif	if (colpos > 0 && colpos <= stmt->ird->header.sql_desc_count) {		--colpos;		tds_dstr_copy(&stmt->ird->records[colpos].sql_desc_label, name);		tds_dstr_copy(&stmt->ird->records[colpos].sql_desc_name, name);	}}/* spinellia@acm.org : copied shamelessly from change_database */static SQLRETURNchange_autocommit(TDS_DBC * dbc, int state){	TDSSOCKET *tds = dbc->tds_socket;	char query[80];	/*	 * We may not be connected yet and dbc->tds_socket	 * may not initialized.	 */	if (tds) {		/*		 * mssql: SET IMPLICIT_TRANSACTION ON		 * sybase: SET CHAINED ON		 */		/* implicit transactions are on if autocommit is off :-| */		if (TDS_IS_MSSQL(tds))			sprintf(query, "SET IMPLICIT_TRANSACTIONS %s", (state == SQL_AUTOCOMMIT_ON) ? "OFF" : "ON");		else {			/* Sybase, do not use SET CHAINED but emulate for compatility */			if (state == SQL_AUTOCOMMIT_ON)				strcpy(query, "WHILE @@TRANCOUNT > 0 COMMIT");			else				strcpy(query, "BEGIN TRANSACTION");		}		tdsdump_log(TDS_DBG_INFO1, "change_autocommit: executing %s\n", query);		/* TODO better idle check, not thread safe */		if (tds->state == TDS_IDLE)			tds->query_timeout = dbc->default_query_timeout;		if (tds_submit_query(tds, query) != TDS_SUCCEED) {			odbc_errs_add(&dbc->errs, "HY000", "Could not change transaction status");			ODBC_RETURN(dbc, SQL_ERROR);		}		if (tds_process_simple_query(tds) != TDS_SUCCEED) {			odbc_errs_add(&dbc->errs, "HY000", "Could not change transaction status");			ODBC_RETURN(dbc, SQL_ERROR);		}		dbc->attr.autocommit = state;	} else {		/* if not connected we will change auto-commit after login */		dbc->attr.autocommit = state;	}	ODBC_RETURN_(dbc);}static SQLRETURNchange_database(TDS_DBC * dbc, char *database, int database_len){	TDSSOCKET *tds = dbc->tds_socket;	/* 	 * We may not be connected yet and dbc->tds_socket	 * may not initialized.	 */	if (tds) {		/* build query */		char *query = (char *) malloc(6 + tds_quote_id(tds, NULL, database, database_len));		if (!query) {			odbc_errs_add(&dbc->errs, "HY001", NULL);			ODBC_RETURN(dbc, SQL_ERROR);		}		strcpy(query, "USE ");		tds_quote_id(tds, query + 4, database, database_len);		tdsdump_log(TDS_DBG_INFO1, "change_database: executing %s\n", query);		/* TODO better idle check, not thread safe */		if (tds->state == TDS_IDLE)			tds->query_timeout = dbc->default_query_timeout;		if (tds_submit_query(tds, query) != TDS_SUCCEED) {			free(query);			odbc_errs_add(&dbc->errs, "HY000", "Could not change database");			ODBC_RETURN(dbc, SQL_ERROR);		}		free(query);		if (tds_process_simple_query(tds) != TDS_SUCCEED) {			odbc_errs_add(&dbc->errs, "HY000", "Could not change database");			ODBC_RETURN(dbc, SQL_ERROR);		}	} else {		tds_dstr_copyn(&dbc->attr.current_catalog, database, database_len);	}	ODBC_RETURN_(dbc);}static voidodbc_env_change(TDSSOCKET * tds, int type, char *oldval, char *newval){	TDS_DBC *dbc;	if (tds == NULL) {		return;	}	dbc = (TDS_DBC *) tds->parent;	if (!dbc)		return;	switch (type) {	case TDS_ENV_DATABASE:		tds_dstr_copy(&dbc->attr.current_catalog, newval);		break;	case TDS_ENV_PACKSIZE:		dbc->attr.packet_size = atoi(newval);		break;	}}static SQLRETURNodbc_connect(TDS_DBC * dbc, TDSCONNECTION * connection){	TDS_ENV *env = dbc->env;	dbc->tds_socket = tds_alloc_socket(env->tds_ctx, 512);	if (!dbc->tds_socket) {		odbc_errs_add(&dbc->errs, "HY001", NULL);		ODBC_RETURN(dbc, SQL_ERROR);	}	tds_set_parent(dbc->tds_socket, (void *) dbc);	/* Set up our environment change hook */	dbc->tds_socket->env_chg_func = odbc_env_change;	tds_fix_connection(connection);	connection->connect_timeout = dbc->attr.connection_timeout;	if (tds_connect(dbc->tds_socket, connection) == TDS_FAIL) {		tds_free_socket(dbc->tds_socket);		dbc->tds_socket = NULL;		odbc_errs_add(&dbc->errs, "08001", NULL);		ODBC_RETURN(dbc, SQL_ERROR);	}	dbc->default_query_timeout = dbc->tds_socket->query_timeout;	if (IS_TDS7_PLUS(dbc->tds_socket))		dbc->cursor_support = 1;	if (dbc->attr.autocommit != SQL_AUTOCOMMIT_ON)		if (!SQL_SUCCEEDED(change_autocommit(dbc, dbc->attr.autocommit)))			ODBC_RETURN_(dbc);	/* this overwrite any error arrived (wanted behavior, Sybase return error for conversion errors) */	ODBC_RETURN(dbc, SQL_SUCCESS);}SQLRETURN ODBC_APISQLDriverConnect(SQLHDBC hdbc, SQLHWND hwnd, SQLCHAR FAR * szConnStrIn, SQLSMALLINT cbConnStrIn, SQLCHAR FAR * szConnStrOut,		 SQLSMALLINT cbConnStrOutMax, SQLSMALLINT FAR * pcbConnStrOut, SQLUSMALLINT fDriverCompletion){	TDSCONNECTION *connection;	int conlen = odbc_get_string_size(cbConnStrIn, szConnStrIn);	INIT_HDBC;	tdsdump_log(TDS_DBG_FUNC, "SQLDriverConnect(%p, %p, %s, %d, %p, %d, %p, %d)\n", 			hdbc, hwnd, szConnStrIn, cbConnStrIn, szConnStrOut, cbConnStrOutMax, pcbConnStrOut, fDriverCompletion);#ifdef TDS_NO_DM	/* Check string length */	if (!IS_VALID_LEN(conlen) || conlen == 0) {		odbc_errs_add(&dbc->errs, "HY090", NULL);		ODBC_RETURN(dbc, SQL_ERROR);	}	/* Check completion param */	switch (fDriverCompletion) {	case SQL_DRIVER_NOPROMPT:	case SQL_DRIVER_COMPLETE:	case SQL_DRIVER_PROMPT:	case SQL_DRIVER_COMPLETE_REQUIRED:		break;	default:		odbc_errs_add(&dbc->errs, "HY110", NULL);		ODBC_RETURN(dbc, SQL_ERROR);	}#endif	connection = tds_alloc_connection(dbc->env->tds_ctx->locale);	if (!connection) {		odbc_errs_add(&dbc->errs, "HY001", NULL);		ODBC_RETURN(dbc, SQL_ERROR);	}	if (!tds_dstr_isempty(&dbc->attr.current_catalog))		tds_dstr_dup(&connection->database, &dbc->attr.current_catalog);	/* parse the DSN string */	odbc_parse_connect_string((const char *) szConnStrIn, (const char *) szConnStrIn + conlen, connection);	/* add login info */	if (hwnd) {#ifdef WIN32		/* prompt for login information */		if (!get_login_info(hwnd, connection)) {			tds_free_connection(connection);			odbc_errs_add(&dbc->errs, "08001", "User canceled login");			ODBC_RETURN(dbc, SQL_ERROR);		}#else		/* we dont support a dialog box */		odbc_errs_add(&dbc->errs, "HYC00", NULL);#endif	}	/* TODO what should be correct behavior for output string?? -- freddy77 */	if (szConnStrOut)		odbc_set_string(szConnStrOut, cbConnStrOutMax, pcbConnStrOut, (const char *) szConnStrIn, conlen);	if (tds_dstr_isempty(&connection->server_name)) {		tds_free_connection(connection);		odbc_errs_add(&dbc->errs, "IM007", "Could not find Servername or server parameter");		ODBC_RETURN(dbc, SQL_ERROR);	}	if (tds_dstr_isempty(&connection->user_name)) {		tds_free_connection(connection);		odbc_errs_add(&dbc->errs, "IM007", "Could not find UID parameter");		ODBC_RETURN(dbc, SQL_ERROR);	}	if (odbc_connect(dbc, connection) != SQL_SUCCESS) {		tds_free_connection(connection);		ODBC_RETURN_(dbc);	}	tds_free_connection(connection);	ODBC_RETURN_(dbc);}#if 0SQLRETURN ODBC_APISQLBrowseConnect(SQLHDBC hdbc, SQLCHAR FAR * szConnStrIn, SQLSMALLINT cbConnStrIn, SQLCHAR FAR * szConnStrOut,		 SQLSMALLINT cbConnStrOutMax, SQLSMALLINT FAR * pcbConnStrOut){	tdsdump_log(TDS_DBG_FUNC, "SQLBrowseConnect(%p, %s, %d, %p, %d, %p)\n", 			hdbc, szConnStrIn, cbConnStrIn, szConnStrOut, cbConnStrOutMax, pcbConnStrOut);	INIT_HDBC;	odbc_errs_add(&dbc->errs, "HYC00", "SQLBrowseConnect: function not implemented");	ODBC_RETURN(dbc, SQL_ERROR);}#endifSQLRETURN ODBC_API

⌨️ 快捷键说明

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