📄 odbc_util.c
字号:
/* FreeTDS - Library of routines accessing Sybase and Microsoft databases * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Brian Bruns * Copyright (C) 2005, 2006 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 */#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 "tdsodbc.h"#ifdef DMALLOC#include <dmalloc.h>#endifTDS_RCSID(var, "$Id: odbc_util.c,v 1.94.2.1 2008/01/29 10:14:31 freddy77 Exp $");/** * \ingroup odbc_api * \defgroup odbc_util ODBC utility * Functions called within \c ODBC driver. *//** * \addtogroup odbc_util * @{ */static intodbc_set_stmt(TDS_STMT * stmt, char **dest, const char *sql, int sql_len){ char *p; assert(dest == &stmt->prepared_query || dest == &stmt->query); if (sql_len == SQL_NTS) sql_len = strlen(sql); else if (sql_len <= 0) return SQL_ERROR; /* TODO already NULL ?? */ tds_free_param_results(stmt->params); stmt->params = NULL; stmt->param_num = 0; stmt->param_count = 0; stmt->prepared_query_is_func = 0; stmt->prepared_query_is_rpc = 0; stmt->prepared_pos = NULL; stmt->curr_param_row = 0; stmt->num_param_rows = 1; if (stmt->prepared_query) TDS_ZERO_FREE(stmt->prepared_query); if (stmt->query) TDS_ZERO_FREE(stmt->query); *dest = p = (char *) malloc(sql_len + 1); if (!p) return SQL_ERROR; if (sql) { memcpy(p, sql, sql_len); p[sql_len] = 0; } else { p[0] = 0; } return SQL_SUCCESS;}intodbc_set_stmt_query(TDS_STMT * stmt, const char *sql, int sql_len){ return odbc_set_stmt(stmt, &stmt->query, sql, sql_len);}intodbc_set_stmt_prepared_query(TDS_STMT * stmt, const char *sql, int sql_len){ return odbc_set_stmt(stmt, &stmt->prepared_query, sql, sql_len);}voidodbc_set_return_status(struct _hstmt *stmt, unsigned int n_row){ TDSSOCKET *tds = stmt->dbc->tds_socket; TDSCONTEXT *context = stmt->dbc->env->tds_ctx; /* TODO handle different type results (functions) on mssql2k */ if (stmt->prepared_query_is_func && tds->has_status) { struct _drecord *drec; int len; const TDS_DESC* axd = stmt->apd; TDS_INTPTR len_offset; char *data_ptr; if (axd->header.sql_desc_count < 1) return; drec = &axd->records[0]; data_ptr = drec->sql_desc_data_ptr; if (axd->header.sql_desc_bind_type != SQL_BIND_BY_COLUMN) { len_offset = axd->header.sql_desc_bind_type * n_row; if (axd->header.sql_desc_bind_offset_ptr) len_offset += *axd->header.sql_desc_bind_offset_ptr; data_ptr += len_offset; } else { len_offset = sizeof(SQLLEN) * n_row; data_ptr += sizeof(SQLINTEGER) * n_row; }#define LEN(ptr) *((SQLLEN*)(((char*)(ptr)) + len_offset)) len = convert_tds2sql(context, SYBINT4, (TDS_CHAR *) & tds->ret_status, sizeof(TDS_INT), drec->sql_desc_concise_type, (void *) data_ptr, drec->sql_desc_octet_length, NULL); if (len < 0) return /* SQL_ERROR */ ; if (drec->sql_desc_indicator_ptr) LEN(drec->sql_desc_indicator_ptr) = 0; if (drec->sql_desc_octet_length_ptr) LEN(drec->sql_desc_octet_length_ptr) = len; }#undef LEN}voidodbc_set_return_params(struct _hstmt *stmt, unsigned int n_row){ TDSSOCKET *tds = stmt->dbc->tds_socket; TDSPARAMINFO *info = tds->current_results; TDSCONTEXT *context = stmt->dbc->env->tds_ctx; int i_begin = stmt->prepared_query_is_func ? 1 : 0; int i; int nparam = i_begin; /* I don't understand why but this happen -- freddy77 */ /* TODO check why, put an assert ? */ if (!info) return; for (i = 0; i < info->num_cols; ++i) { const TDS_DESC* axd = stmt->apd; const struct _drecord *drec_apd, *drec_ipd; TDSCOLUMN *colinfo = info->columns[i]; TDS_CHAR *src; int srclen; SQLINTEGER len; int c_type; char *data_ptr; TDS_INTPTR len_offset; /* find next output parameter */ for (;;) { drec_apd = NULL; /* TODO best way to stop */ if (nparam >= axd->header.sql_desc_count || nparam >= stmt->ipd->header.sql_desc_count) return; drec_apd = &axd->records[nparam]; drec_ipd = &stmt->ipd->records[nparam]; if (stmt->ipd->records[nparam++].sql_desc_parameter_type != SQL_PARAM_INPUT) break; } data_ptr = drec_apd->sql_desc_data_ptr; if (axd->header.sql_desc_bind_type != SQL_BIND_BY_COLUMN) { len_offset = axd->header.sql_desc_bind_type * n_row; if (axd->header.sql_desc_bind_offset_ptr) len_offset += *axd->header.sql_desc_bind_offset_ptr; data_ptr += len_offset; } else { len_offset = sizeof(SQLLEN) * n_row; data_ptr += odbc_get_octet_len(drec_apd->sql_desc_concise_type, drec_apd) * n_row; }#define LEN(ptr) *((SQLLEN*)(((char*)(ptr)) + len_offset)) /* null parameter ? */ if (colinfo->column_cur_size < 0) { /* FIXME error if NULL */ if (drec_apd->sql_desc_indicator_ptr) LEN(drec_apd->sql_desc_indicator_ptr) = SQL_NULL_DATA; continue; } src = (TDS_CHAR *) colinfo->column_data; if (is_blob_type(colinfo->column_type)) src = ((TDSBLOB *) src)->textvalue; srclen = colinfo->column_cur_size; c_type = drec_apd->sql_desc_concise_type; if (c_type == SQL_C_DEFAULT) c_type = odbc_sql_to_c_type_default(drec_ipd->sql_desc_concise_type); /* * TODO why IPD ?? perhaps SQLBindParameter it's not correct ?? * Or tests are wrong ?? */ len = convert_tds2sql(context, tds_get_conversion_type(colinfo->column_type, colinfo->column_size), src, srclen, c_type, (void *) data_ptr, drec_apd->sql_desc_octet_length, drec_ipd); /* TODO error handling */ if (len < 0) return /* SQL_ERROR */ ; if (drec_apd->sql_desc_indicator_ptr) LEN(drec_apd->sql_desc_indicator_ptr) = 0; if (drec_apd->sql_desc_octet_length_ptr) LEN(drec_apd->sql_desc_octet_length_ptr) = len;#undef LEN }}intodbc_get_string_size(int size, SQLCHAR * str){ if (str) { if (size == SQL_NTS) return strlen((const char *) str); if (size >= 0) return size; } /* SQL_NULL_DATA or any other strange value */ return 0;}/** * Convert type from database to ODBC */SQLSMALLINTodbc_server_to_sql_type(int col_type, int col_size){ /* FIXME finish */ switch ((TDS_SERVER_TYPE) col_type) { case XSYBCHAR: case SYBCHAR: return SQL_CHAR; case XSYBVARCHAR: case SYBVARCHAR: return SQL_VARCHAR; case SYBTEXT: return SQL_LONGVARCHAR; case SYBBIT: case SYBBITN: return SQL_BIT;#if (ODBCVER >= 0x0300) case SYBINT8: /* TODO return numeric for odbc2 and convert bigint to numeric */ return SQL_BIGINT;#endif case SYBINT4: return SQL_INTEGER; case SYBINT2: return SQL_SMALLINT; case SYBINT1: return SQL_TINYINT; case SYBINTN: switch (col_size) { case 1: return SQL_TINYINT; case 2: return SQL_SMALLINT; case 4: return SQL_INTEGER;#if (ODBCVER >= 0x0300) case 8: return SQL_BIGINT;#endif } break; case SYBREAL: return SQL_REAL; case SYBFLT8: return SQL_DOUBLE; case SYBFLTN: switch (col_size) { case 4: return SQL_REAL; case 8: return SQL_DOUBLE; } break; case SYBMONEY: case SYBMONEY4: case SYBMONEYN: return SQL_FLOAT; case SYBDATETIME: case SYBDATETIME4: case SYBDATETIMN:#if (ODBCVER >= 0x0300) return SQL_TYPE_TIMESTAMP;#else return SQL_TIMESTAMP;#endif case XSYBBINARY: case SYBBINARY: return SQL_BINARY; case SYBLONGBINARY: case SYBIMAGE: return SQL_LONGVARBINARY; case XSYBVARBINARY: case SYBVARBINARY: return SQL_VARBINARY; case SYBNUMERIC: case SYBDECIMAL: return SQL_NUMERIC; /* TODO this is ODBC 3.5 */ case SYBNTEXT: case SYBNVARCHAR: case XSYBNVARCHAR: case XSYBNCHAR: break;#if (ODBCVER >= 0x0300) case SYBUNIQUE:#ifdef SQL_GUID return SQL_GUID;#else return SQL_CHAR;#endif case SYBVARIANT: break;#endif /* * TODO what should I do with these types ?? * return other types can cause additional problems */ case SYBVOID: case SYBSINT1: case SYBUINT2: case SYBUINT4: case SYBUINT8: case SYBUINT1: case SYBDATE: case SYBDATEN: case SYB5INT8: case SYBINTERVAL: case SYBTIME: case SYBTIMEN: case SYBUINTN: case SYBUNITEXT: case SYBXML: break; } return SQL_UNKNOWN_TYPE;}/** * Pass this an SQL_C_* type and get a SYB* type which most closely corresponds * to the SQL_C_* type. */intodbc_c_to_server_type(int c_type){ switch (c_type) { /* FIXME this should be dependent on size of data !!! */ case SQL_C_BINARY: return SYBBINARY; /* TODO what happen if varchar is more than 255 characters long */ case SQL_C_CHAR: return SYBVARCHAR; case SQL_C_FLOAT: return SYBREAL; case SQL_C_DOUBLE: return SYBFLT8; case SQL_C_BIT: return SYBBIT;#if (ODBCVER >= 0x0300) case SQL_C_SBIGINT: case SQL_C_UBIGINT: return SYBINT8;#ifdef SQL_C_GUID case SQL_C_GUID: return SYBUNIQUE;#endif#endif case SQL_C_LONG: case SQL_C_SLONG: case SQL_C_ULONG: return SYBINT4; case SQL_C_SHORT: case SQL_C_SSHORT: case SQL_C_USHORT: return SYBINT2; case SQL_C_TINYINT: case SQL_C_STINYINT: case SQL_C_UTINYINT: return SYBINT1; /* ODBC date formats are completely differect from SQL one */ case SQL_C_DATE: case SQL_C_TIME: case SQL_C_TIMESTAMP: case SQL_C_TYPE_DATE: case SQL_C_TYPE_TIME: case SQL_C_TYPE_TIMESTAMP: return SYBDATETIME; /* ODBC numeric/decimal formats are completely differect from tds one */ case SQL_C_NUMERIC: return SYBNUMERIC; /* not supported */ case SQL_C_INTERVAL_YEAR: case SQL_C_INTERVAL_MONTH: case SQL_C_INTERVAL_DAY: case SQL_C_INTERVAL_HOUR: case SQL_C_INTERVAL_MINUTE: case SQL_C_INTERVAL_SECOND: case SQL_C_INTERVAL_YEAR_TO_MONTH: case SQL_C_INTERVAL_DAY_TO_HOUR: case SQL_C_INTERVAL_DAY_TO_MINUTE: case SQL_C_INTERVAL_DAY_TO_SECOND: case SQL_C_INTERVAL_HOUR_TO_MINUTE: case SQL_C_INTERVAL_HOUR_TO_SECOND: case SQL_C_INTERVAL_MINUTE_TO_SECOND:#ifdef SQL_C_WCHAR case SQL_C_WCHAR:#endif break; } return TDS_FAIL;}voidodbc_set_sql_type_info(TDSCOLUMN * col, struct _drecord *drec, SQLINTEGER odbc_ver){#define SET_INFO(type, prefix, suffix) \ drec->sql_desc_literal_prefix = prefix; \ drec->sql_desc_literal_suffix = suffix; \ drec->sql_desc_type_name = type; \ return;#define SET_INFO2(type, prefix, suffix, len) \ drec->sql_desc_length = len; \ SET_INFO(type, prefix, suffix) /* FIXME finish, support for N type (nvarchar) */ switch (tds_get_conversion_type(col->column_type, col->column_size)) { case XSYBCHAR: case SYBCHAR: SET_INFO("char", "'", "'"); case XSYBVARCHAR: case SYBVARCHAR: SET_INFO("varchar", "'", "'"); case SYBTEXT: SET_INFO("text", "'", "'"); case SYBBIT: case SYBBITN: SET_INFO2("bit", "", "", 1);#if (ODBCVER >= 0x0300) case SYBINT8: /* TODO return numeric for odbc2 and convert bigint to numeric */ SET_INFO2("bigint", "", "", 19);#endif case SYBINT4: SET_INFO2("int", "", "", 10); case SYBINT2: SET_INFO2("smallint", "", "", 5); case SYBINT1: SET_INFO2("tinyint", "", "", 3); case SYBREAL: SET_INFO2("real", "", "", odbc_ver == SQL_OV_ODBC3 ? 24 : 7); case SYBFLT8: SET_INFO2("float", "", "", odbc_ver == SQL_OV_ODBC3 ? 53 : 15); case SYBMONEY: SET_INFO2("money", "$", "", 19); case SYBMONEY4: SET_INFO2("money", "$", "", 10); case SYBDATETIME: SET_INFO2("datetime", "'", "'", 23); case SYBDATETIME4: SET_INFO2("datetime", "'", "'", 16); case SYBBINARY: /* handle TIMESTAMP using usertype */ if (col->column_usertype == 80) SET_INFO("timestamp", "0x", ""); SET_INFO("binary", "0x", ""); case SYBIMAGE: SET_INFO("image", "0x", ""); case SYBVARBINARY: SET_INFO("varbinary", "0x", ""); case SYBNUMERIC: SET_INFO2("numeric", "", "", col->column_prec); case SYBDECIMAL: SET_INFO2("decimal", "", "", col->column_prec); case SYBINTN: case SYBDATETIMN: case SYBFLTN: case SYBMONEYN: assert(0); case SYBVOID: case SYBNTEXT: case SYBNVARCHAR: case XSYBNVARCHAR: case XSYBNCHAR: break;#if (ODBCVER >= 0x0300) case SYBUNIQUE: /* FIXME for Sybase ?? */ SET_INFO("uniqueidentifier", "'", "'"); case SYBVARIANT: /* SET_INFO("sql_variant", "", ""); */ break;#endif } SET_INFO("", "", "");#undef SET_INFO#undef SET_INFO2}SQLINTEGERodbc_sql_to_displaysize(int sqltype, TDSCOLUMN *col){ SQLINTEGER size = 0; switch (sqltype) { case SQL_CHAR: case SQL_VARCHAR: case SQL_LONGVARCHAR: size = col->column_size; break; case SQL_BINARY:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -