📄 dblib.c
字号:
/* FreeTDS - Library of routines accessing Sybase and Microsoft databases * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Brian Bruns * Copyright (C) 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. */#if HAVE_CONFIG_H#include <config.h>#endif /* HAVE_CONFIG_H */#include <stdarg.h>#if TIME_WITH_SYS_TIME# include <sys/time.h># include <time.h>#else# if HAVE_SYS_TIME_H# include <sys/time.h># else# include <time.h># endif#endif#include <assert.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 */#if HAVE_ERRNO_H# include <errno.h>#else static int errno=0;#endif /* HAVE_ERRNO_H *//** * \ingroup dblib_core * \remarks Either SYBDBLIB or MSDBLIB (not both) must be defined. * This affects how certain application-addressable * strucures are defined. */#define SYBDBLIB 1#include "tds.h"#include "tdsthread.h"#include "sybfront.h"#include "sybdb.h"#include "syberror.h"#include "dblib.h"#include "tdsconvert.h"#include "replacements.h"#ifdef DMALLOC#include <dmalloc.h>#endifTDS_RCSID(var, "$Id: dblib.c,v 1.320 2008/01/01 23:09:46 freddy77 Exp $");static RETCODE _dbresults(DBPROCESS * dbproc);static int _db_get_server_type(int bindtype);static int _get_printable_size(TDSCOLUMN * colinfo);static char *_dbprdate(char *timestr);static int _dbnullable(DBPROCESS * dbproc, int column);static char *tds_prdatatype(TDS_SERVER_TYPE datatype_token);static void copy_data_to_host_var(DBPROCESS *, int, const BYTE *, DBINT, int, BYTE *, DBINT, int, DBSMALLINT *);static int default_err_handler(DBPROCESS * dbproc, int severity, int dberr, int oserr, char *dberrstr, char *oserrstr);static RETCODE dbgetnull(DBPROCESS *dbproc, int bindtype, int varlen, BYTE* varaddr);/** * \file dblib.c * Main implementation file for \c db-lib. *//** * \file bcp.c * Implementation of \c db-lib bulk copy functions. *//** * \defgroup dblib_api The db-lib API * Functions callable by \c db-lib client programs * * The \c db_lib interface is implemented by both Sybase and Microsoft. FreeTDS seeks to implement * first the intersection of the functions defined by the vendors. */ /** * \ingroup dblib_api * \defgroup dblib_core Primary functions * Core functions needed by most db-lib programs. *//** * \ingroup dblib_api * \defgroup dblib_rpc Remote Procedure functions * Functions used with stored procedures. * Especially useful for OUTPUT parameters, because modern Microsoft servers do not * return output parameter data to the client unless the procedure was invoked * with dbrpcsend(). *//** * \ingroup dblib_api * \defgroup dblib_bcp Bulk copy functions * Functions to bulk-copy (a/k/a \em bcp) data to/from the database. *//** * \ingroup dblib_bcp * \defgroup dblib_bcp_internal Internal bcp functions * Static functions internal to the bcp library. *//** * \ingroup dblib_api * \defgroup dblib_money Money functions * Functions to manipulate the MONEY datatype. *//** * \ingroup dblib_api * \defgroup dblib_datetime Datetime functions * Functions to manipulate DBDATETIME structures. Defined by Sybase only. * These are not implemented: * - dbdate4cmp() * - dbdate4zero() * - dbdatechar() * - dbdatename() * - dbdateorder() * - dbdatepart() * - dbdatezero() * - dbdayname() *//** * \ingroup dblib_api * \defgroup dblib_internal Internals * Functions called within \c db-lib for self-help. * These functions are of interest only to people hacking on the FreeTDS db-lib implementation. *//** * \ingroup dblib_api * \defgroup dblib_unimplemented Unimplemented * Functions thus far not implemented in the FreeTDS db-lib implementation. * While some of these are simply awaiting someone with time and skill (and inclination) * it might be noted here that the old browse functions (e.g. dbcolbrowse()) * are on the never-to-do list. * They were defined by Sybase and were superseded long ago, although they're still * present in Microsoft's implementation. * They were never popular and today better alternatives are available. * For completeness, they are: * - dbcolbrowse() * - dbcolsource() * - dbfreequal() * - dbqual() * - dbtabbrowse() * - dbtabcount() * - dbtabname() * - dbtabsource() * - dbtsnewlen() * - dbtsnewval() * - dbtsput() *//* info/err message handler functions (or rather pointers to them) */MHANDLEFUNC _dblib_msg_handler = NULL;EHANDLEFUNC _dblib_err_handler = default_err_handler;/** \internal * \dblib_internal * \remarks A db-lib connection has an implicit TDS context. */typedef struct dblib_context{ /** reference count, time dbinit called */ int ref_count; /** libTDS context */ TDSCONTEXT *tds_ctx; /** libTDS context reference counter */ int tds_ctx_ref_count; /* save all connection in a list */ TDSSOCKET **connection_list; int connection_list_size; int connection_list_size_represented; char *recftos_filename; int recftos_filenum; int login_timeout; /**< not used unless positive */ int query_timeout; /**< not used unless positive */}DBLIBCONTEXT;static DBLIBCONTEXT g_dblib_ctx;static TDS_MUTEX_DECLARE(dblib_mutex);static int g_dblib_version =#ifdef TDS42 DBVERSION_42;#endif#ifdef TDS50DBVERSION_100;#endif#ifdef TDS46DBVERSION_46;#endif#ifdef TDS70DBVERSION_70;#endif#ifdef TDS80DBVERSION_80;#endifstatic intdblib_add_connection(DBLIBCONTEXT * ctx, TDSSOCKET * tds){ int i = 0; const int list_size = ctx->connection_list_size_represented; tdsdump_log(TDS_DBG_FUNC, "dblib_add_connection(%p, %p)\n", ctx, tds); while (i < list_size && ctx->connection_list[i]) i++; if (i == list_size) { fprintf(stderr, "Max connections reached, increase value of TDS_MAX_CONN\n"); return 1; } else { ctx->connection_list[i] = tds; return 0; }}static voiddblib_del_connection(DBLIBCONTEXT * ctx, TDSSOCKET * tds){ int i = 0; const int list_size = ctx->connection_list_size; tdsdump_log(TDS_DBG_FUNC, "dblib_del_connection(%p, %p)\n", ctx, tds); while (i < list_size && ctx->connection_list[i] != tds) i++; if (i == list_size) { /* connection wasn't on the free list...now what */ } else { /* remove it */ ctx->connection_list[i] = NULL; }}static TDSCONTEXT*dblib_get_tds_ctx(void){ tdsdump_log(TDS_DBG_FUNC, "dblib_get_tds_ctx(void)\n"); TDS_MUTEX_LOCK(&dblib_mutex); ++g_dblib_ctx.tds_ctx_ref_count; if (g_dblib_ctx.tds_ctx == NULL) { g_dblib_ctx.tds_ctx = tds_alloc_context(&g_dblib_ctx); /* * Set the functions in the TDS layer to point to the correct handler functions */ g_dblib_ctx.tds_ctx->msg_handler = _dblib_handle_info_message; g_dblib_ctx.tds_ctx->err_handler = _dblib_handle_err_message; g_dblib_ctx.tds_ctx->int_handler = _dblib_check_and_handle_interrupt; if (g_dblib_ctx.tds_ctx->locale && !g_dblib_ctx.tds_ctx->locale->date_fmt) { /* set default in case there's no locale file */ const static char date_format[] = #ifndef WIN32 "%b %e %Y %I:%M:%S:%z%p";#else "%b %d %Y %I:%M:%S:%z%p";#endif g_dblib_ctx.tds_ctx->locale->date_fmt = strdup(date_format); } } TDS_MUTEX_UNLOCK(&dblib_mutex); return g_dblib_ctx.tds_ctx;}static voiddblib_release_tds_ctx(int count){ tdsdump_log(TDS_DBG_FUNC, "dblib_release_tds_ctx(%d)\n", count); TDS_MUTEX_LOCK(&dblib_mutex); g_dblib_ctx.tds_ctx_ref_count -= count; if (g_dblib_ctx.tds_ctx_ref_count <= 0) { tds_free_context(g_dblib_ctx.tds_ctx); g_dblib_ctx.tds_ctx = NULL; } TDS_MUTEX_UNLOCK(&dblib_mutex);}#include "buffering.h"static voiddb_env_chg(TDSSOCKET * tds, int type, char *oldval, char *newval){ DBPROCESS *dbproc; assert(oldval != NULL && newval != NULL); if (strlen(oldval) == 1 && *oldval == 1) oldval = "(0x1)"; tdsdump_log(TDS_DBG_FUNC, "db_env_chg(%p, %d, %s, %s)\n", tds, type, oldval, newval); if (tds == NULL || tds->parent == NULL ) { return; } dbproc = (DBPROCESS *) tds->parent; dbproc->envchange_rcv |= (1 << (type - 1)); switch (type) { case TDS_ENV_DATABASE: tds_strlcpy(dbproc->dbcurdb, newval, sizeof(dbproc->dbcurdb)); break; case TDS_ENV_CHARSET: tds_strlcpy(dbproc->servcharset, newval, sizeof(dbproc->servcharset)); break; default: break; } return;}/** \internal * \ingroup dblib_internal * \brief Sanity checks for column-oriented functions. * * \param dbproc contains all information needed by db-lib to manage communications with the server. * \param pcolinfo address of pointer to a TDSCOLUMN structure. * \remarks Makes sure dbproc and the requested column are valid. * Calls dbperror() if not. * \returns appropriate error or SUCCEED */static TDSCOLUMN*dbcolptr(DBPROCESS* dbproc, int column){ if (!dbproc) { dbperror(dbproc, SYBENULL, 0); return NULL; } if (IS_TDSDEAD(dbproc->tds_socket)) { dbperror(dbproc, SYBEDDNE, 0); return NULL; } if (!dbproc->tds_socket->res_info) return NULL; if (column < 1 || column > dbproc->tds_socket->res_info->num_cols) { dbperror(dbproc, SYBECNOR, 0); return NULL; } return dbproc->tds_socket->res_info->columns[column - 1];}static TDSCOLUMN*dbacolptr(DBPROCESS* dbproc, int computeid, int column, int is_bind){ int i; TDSSOCKET *tds; TDSCOMPUTEINFO *info; if (!dbproc) { dbperror(dbproc, SYBENULL, 0); return NULL; } tds = dbproc->tds_socket; if (IS_TDSDEAD(tds)) { dbperror(dbproc, SYBEDDNE, 0); return NULL; } for (i = 0;; ++i) { if (i >= tds->num_comp_info) { /* Attempt to bind user variable to a non-existent compute row */ if (is_bind) dbperror(dbproc, SYBEBNCR, 0); return NULL; } info = tds->comp_info[i]; info = dbproc->tds_socket->comp_info[i]; if (info->computeid == computeid) break; } /* Fail if either the compute id or the column number is invalid. */ if (column < 1 || column > info->num_cols) { dbperror(dbproc, is_bind ? SYBEABNC : SYBECNOR, 0); return NULL; } return info->columns[column - 1];}/* * Default null substitution values * Binding Type Null Substitution Value * TINYBIND 0 * SMALLBIND 0 * INTBIND 0 * CHARBIND Empty string (padded with blanks) * STRINGBIND Empty string (padded with blanks, null-terminated) * NTBSTRINGBIND Empty string (null-terminated) * VARYCHARBIND Empty string * BINARYBIND Empty array (padded with zeros) * VARYBINBIND Empty array * DATETIMEBIND 8 bytes of zeros * SMALLDATETIMEBIND 8 bytes of zeros * MONEYBIND $0.00 * SMALLMONEYBIND $0.00 * FLT8BIND 0.0 * REALBIND 0.0 * DECIMALBIND 0.0 (with default scale and precision) * NUMERICBIND 0.0 (with default scale and precision) * BOUNDARYBIND Empty string (null-terminated) * SENSITIVITYBIND Empty string (null-terminated) */static const DBBIT null_BIT = 0;static const DBTINYINT null_TINYINT = 0;static const DBSMALLINT null_SMALLINT = 0;static const DBINT null_INT = 0;static const DBFLT8 null_FLT8 = 0;static const DBREAL null_REAL = 0;static const DBCHAR null_CHAR = '\0';static const DBVARYCHAR null_VARYCHAR = { 0, {0} };static const DBBINARY null_BINARY = 0;static const DBDATETIME null_DATETIME = { 0, 0 };static const DBDATETIME4 null_SMALLDATETIME = { 0, 0 };static const DBMONEY null_MONEY = { 0, 0 };static const DBMONEY4 null_SMALLMONEY = {0};static const DBNUMERIC null_NUMERIC = { 0, 0, {0} };static NULLREP default_null_representations[MAXBINDTYPES] = { /* CHARBIND 0 */ { NULL, 0 } /* STRINGBIND 1 */ , { NULL, 0 } /* NTBSTRINGBIND 2 */ , { (BYTE*) &null_CHAR, sizeof(null_CHAR) } /* VARYCHARBIND 3 */ , { (BYTE*) &null_VARYCHAR, sizeof(null_VARYCHAR) } /* VARYBINBIND 4 */ , { &null_BINARY, sizeof(null_BINARY) } /* no such bind 5 */ , { NULL, 0 } /* TINYBIND 6 */ , { &null_TINYINT, sizeof(null_TINYINT) } /* SMALLBIND 7 */ , { (BYTE*) &null_SMALLINT, sizeof(null_SMALLINT) } /* INTBIND 8 */ , { (BYTE*) &null_INT, sizeof(null_INT) } /* FLT8BIND 9 */ , { (BYTE*) &null_FLT8, sizeof(null_FLT8) } /* REALBIND 10 */ , { (BYTE*) &null_REAL, sizeof(null_REAL) } /* DATETIMEBIND 11 */ , { (BYTE*) &null_DATETIME, sizeof(null_DATETIME) } /* SMALLDATETIMEBIND 12 */ , { (BYTE*) &null_SMALLDATETIME, sizeof(null_SMALLDATETIME) } /* MONEYBIND 13 */ , { (BYTE*) &null_MONEY, sizeof(null_MONEY) } /* SMALLMONEYBIND 14 */ , { (BYTE*) &null_SMALLMONEY, sizeof(null_SMALLMONEY) } /* BINARYBIND 15 */ , { NULL, 0 } /* BITBIND 16 */ , { &null_BIT, sizeof(null_BIT) } /* NUMERICBIND 17 */ , { (BYTE*) &null_NUMERIC, sizeof(null_NUMERIC) } /* DECIMALBIND 18 */ , { (BYTE*) &null_NUMERIC, sizeof(null_NUMERIC) } /* MAXBINDTYPES 19 */};static intdbbindtype(int datatype){ switch (datatype) { case SYBIMAGE: case SYBVARBINARY: case SYBBINARY: return BINARYBIND; case SYBBIT: return BITBIND; case SYBTEXT: case SYBVARCHAR: case SYBCHAR: return NTBSTRINGBIND;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -