apr_dbd_odbc.c
来自「Apache官方在今天放出产品系列2.2的最新版本2.2.11的源码包 最流行」· C语言 代码 · 共 1,629 行 · 第 1/4 页
C
1,629 行
/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */#include "apu.h"#if APU_HAVE_ODBC#include "apr.h"#include "apr_strings.h"#include "apr_buckets.h"#include "apr_env.h"#include "apr_file_io.h"#include "apr_file_info.h"#include "apr_dbd_internal.h"#include "apr_thread_proc.h"#include "apu_version.h"#include "apu_config.h"#include <stdlib.h>/* If library is ODBC-V2, use macros for limited ODBC-V2 support * No random access in V2. */#ifdef ODBCV2#define ODBCVER 0x0200#include "apr_dbd_odbc_v2.h"#endif/* standard ODBC include files */#ifdef HAVE_SQL_H#include <sql.h>#include <sqlext.h>#elif defined(HAVE_ODBC_SQL_H)#include <odbc/sql.h>#include <odbc/sqlext.h>#endif /* Driver name is "odbc" and the entry point is 'apr_dbd_odbc_driver' * unless ODBC_DRIVER_NAME is defined and it is linked with another db library which * is ODBC source-compatible. e.g. DB2, Informix, TimesTen, mysql. */#ifndef ODBC_DRIVER_NAME#define ODBC_DRIVER_NAME odbc#endif#define STRINGIFY(x) #x#define NAMIFY2(n) apr_dbd_##n##_driver#define NAMIFY1(n) NAMIFY2(n)#define ODBC_DRIVER_STRING STRINGIFY(ODBC_DRIVER_NAME)#define ODBC_DRIVER_ENTRY NAMIFY1(ODBC_DRIVER_NAME)/* Required APR version for this driver */#define DRIVER_APU_VERSION_MAJOR APU_MAJOR_VERSION#define DRIVER_APU_VERSION_MINOR APU_MINOR_VERSIONstatic SQLHANDLE henv = NULL; /* ODBC ENV handle is process-wide *//* Use a CHECK_ERROR macro so we can grab the source line numbers * for error reports */static void check_error(apr_dbd_t *a, const char *step, SQLRETURN rc, SQLSMALLINT type, SQLHANDLE h, int line);#define CHECK_ERROR(a,s,r,t,h) check_error(a,s,r,t,h, __LINE__)#define SOURCE_FILE __FILE__ /* source file for error messages */#define MAX_ERROR_STRING 1024 /* max length of message in dbc */#define MAX_COLUMN_NAME 256 /* longest column name recognized */#define DEFAULT_BUFFER_SIZE 1024 /* value for defaultBufferSize */#define MAX_PARAMS 20#define DEFAULTSEPS " \t\r\n,="#define CSINGLEQUOTE '\''#define SSINGLEQUOTE "\'"#define TEXTMODE 1 /* used for text (APR 1.2) mode params */#define BINARYMODE 0 /* used for binary (APR 1.3+) mode params *//* Identify datatypes which are LOBs * - DB2 DRDA driver uses undefined types -98 and -99 for CLOB & BLOB */#define IS_LOB(t) (t == SQL_LONGVARCHAR \ || t == SQL_LONGVARBINARY || t == SQL_VARBINARY \ || t == -98 || t == -99)/* These types are CLOBs * - DB2 DRDA driver uses undefined type -98 for CLOB */#define IS_CLOB(t) \ (t == SQL_LONGVARCHAR || t == -98)/* Convert a SQL result to an APR result */#define APR_FROM_SQL_RESULT(rc) \ (SQL_SUCCEEDED(rc) ? APR_SUCCESS : APR_EGENERAL)/* DBD opaque structures */struct apr_dbd_t{ SQLHANDLE dbc; /* SQL connection handle - NULL after close */ apr_pool_t *pool; /* connection lifetime pool */ char *dbname; /* ODBC datasource */ int lasterrorcode; int lineNumber; char lastError[MAX_ERROR_STRING]; int defaultBufferSize; /* used for CLOBs in text mode, * and when fld size is indeterminate */ int transaction_mode; int dboptions; /* driver options re SQLGetData */ int default_transaction_mode; int can_commit; /* controls end_trans behavior */};struct apr_dbd_results_t{ SQLHANDLE stmt; /* parent sql statement handle */ SQLHANDLE dbc; /* parent sql connection handle */ apr_pool_t *pool; /* pool from query or select */ apr_dbd_t *apr_dbd; /* parent DBD connection handle */ int random; /* random access requested */ int ncols; /* number of columns */ int isclosed; /* cursor has been closed */ char **colnames; /* array of column names (NULL until used) */ SQLPOINTER *colptrs; /* pointers to column data */ SQLINTEGER *colsizes; /* sizes for columns (enough for txt or bin) */ SQLINTEGER *coltextsizes; /* max-sizes if converted to text */ SQLSMALLINT *coltypes; /* array of SQL data types for columns */ SQLLEN *colinds; /* array of SQL data indicator/strlens */ int *colstate; /* array of column states * - avail, bound, present, unavail */ int *all_data_fetched; /* flags data as all fetched, for LOBs */ void *data; /* buffer for all data for one row */};enum /* results column states */{ COL_AVAIL, /* data may be retrieved with SQLGetData */ COL_PRESENT, /* data has been retrieved with SQLGetData */ COL_BOUND, /* column is bound to colptr */ COL_RETRIEVED, /* all data from column has been returned */ COL_UNAVAIL /* column is unavailable because ODBC driver * requires that columns be retrieved * in ascending order and a higher col * was accessed */};struct apr_dbd_row_t { SQLHANDLE stmt; /* parent ODBC statement handle */ SQLHANDLE dbc; /* parent ODBC connection handle */ apr_pool_t *pool; /* pool from get_row */ apr_dbd_results_t *res;};struct apr_dbd_transaction_t { SQLHANDLE dbc; /* parent ODBC connection handle */ apr_dbd_t *apr_dbd; /* parent DBD connection handle */};struct apr_dbd_prepared_t { SQLHANDLE stmt; /* ODBC statement handle */ SQLHANDLE dbc; /* parent ODBC connection handle */ apr_dbd_t *apr_dbd; int nargs; int nvals; int *types; /* array of DBD data types */};static void odbc_lob_bucket_destroy(void *data);static apr_status_t odbc_lob_bucket_setaside(apr_bucket *e, apr_pool_t *pool);static apr_status_t odbc_lob_bucket_read(apr_bucket *e, const char **str, apr_size_t *len, apr_read_type_e block);/* the ODBC LOB bucket type */static const apr_bucket_type_t odbc_bucket_type = { "ODBC_LOB", 5, APR_BUCKET_DATA, odbc_lob_bucket_destroy, odbc_lob_bucket_read, odbc_lob_bucket_setaside, apr_bucket_shared_split, apr_bucket_shared_copy};/* ODBC LOB bucket data */typedef struct { /** Ref count for shared bucket */ apr_bucket_refcount refcount; const apr_dbd_row_t *row; int col; SQLSMALLINT type;} odbc_bucket;/* SQL datatype mappings to DBD datatypes * These tables must correspond *exactly* to the apr_dbd_type_e enum * in apr_dbd_internal.h *//* ODBC "C" types to DBD datatypes */static SQLSMALLINT const sqlCtype[] = { SQL_C_DEFAULT, /* APR_DBD_TYPE_NONE */ SQL_C_STINYINT, /* APR_DBD_TYPE_TINY, \%hhd */ SQL_C_UTINYINT, /* APR_DBD_TYPE_UTINY, \%hhu */ SQL_C_SSHORT, /* APR_DBD_TYPE_SHORT, \%hd */ SQL_C_USHORT, /* APR_DBD_TYPE_USHORT, \%hu */ SQL_C_SLONG, /* APR_DBD_TYPE_INT, \%d */ SQL_C_ULONG, /* APR_DBD_TYPE_UINT, \%u */ SQL_C_SLONG, /* APR_DBD_TYPE_LONG, \%ld */ SQL_C_ULONG, /* APR_DBD_TYPE_ULONG, \%lu */ SQL_C_SBIGINT, /* APR_DBD_TYPE_LONGLONG, \%lld */ SQL_C_UBIGINT, /* APR_DBD_TYPE_ULONGLONG, \%llu */ SQL_C_FLOAT, /* APR_DBD_TYPE_FLOAT, \%f */ SQL_C_DOUBLE, /* APR_DBD_TYPE_DOUBLE, \%lf */ SQL_C_CHAR, /* APR_DBD_TYPE_STRING, \%s */ SQL_C_CHAR, /* APR_DBD_TYPE_TEXT, \%pDt */ SQL_C_CHAR, /*SQL_C_TYPE_TIME, APR_DBD_TYPE_TIME, \%pDi */ SQL_C_CHAR, /*SQL_C_TYPE_DATE, APR_DBD_TYPE_DATE, \%pDd */ SQL_C_CHAR, /*SQL_C_TYPE_TIMESTAMP, APR_DBD_TYPE_DATETIME, \%pDa */ SQL_C_CHAR, /*SQL_C_TYPE_TIMESTAMP, APR_DBD_TYPE_TIMESTAMP, \%pDs */ SQL_C_CHAR, /*SQL_C_TYPE_TIMESTAMP, APR_DBD_TYPE_ZTIMESTAMP, \%pDz */ SQL_LONGVARBINARY, /* APR_DBD_TYPE_BLOB, \%pDb */ SQL_LONGVARCHAR, /* APR_DBD_TYPE_CLOB, \%pDc */ SQL_TYPE_NULL /* APR_DBD_TYPE_NULL \%pDn */};/* ODBC Base types to DBD datatypes */static SQLSMALLINT const sqlBaseType[] = { SQL_C_DEFAULT, /* APR_DBD_TYPE_NONE */ SQL_TINYINT, /* APR_DBD_TYPE_TINY, \%hhd */ SQL_TINYINT, /* APR_DBD_TYPE_UTINY, \%hhu */ SQL_SMALLINT, /* APR_DBD_TYPE_SHORT, \%hd */ SQL_SMALLINT, /* APR_DBD_TYPE_USHORT, \%hu */ SQL_INTEGER, /* APR_DBD_TYPE_INT, \%d */ SQL_INTEGER, /* APR_DBD_TYPE_UINT, \%u */ SQL_INTEGER, /* APR_DBD_TYPE_LONG, \%ld */ SQL_INTEGER, /* APR_DBD_TYPE_ULONG, \%lu */ SQL_BIGINT, /* APR_DBD_TYPE_LONGLONG, \%lld */ SQL_BIGINT, /* APR_DBD_TYPE_ULONGLONG, \%llu */ SQL_FLOAT, /* APR_DBD_TYPE_FLOAT, \%f */ SQL_DOUBLE, /* APR_DBD_TYPE_DOUBLE, \%lf */ SQL_CHAR, /* APR_DBD_TYPE_STRING, \%s */ SQL_CHAR, /* APR_DBD_TYPE_TEXT, \%pDt */ SQL_CHAR, /*SQL_TIME, APR_DBD_TYPE_TIME, \%pDi */ SQL_CHAR, /*SQL_DATE, APR_DBD_TYPE_DATE, \%pDd */ SQL_CHAR, /*SQL_TIMESTAMP, APR_DBD_TYPE_DATETIME, \%pDa */ SQL_CHAR, /*SQL_TIMESTAMP, APR_DBD_TYPE_TIMESTAMP, \%pDs */ SQL_CHAR, /*SQL_TIMESTAMP, APR_DBD_TYPE_ZTIMESTAMP, \%pDz */ SQL_LONGVARBINARY, /* APR_DBD_TYPE_BLOB, \%pDb */ SQL_LONGVARCHAR, /* APR_DBD_TYPE_CLOB, \%pDc */ SQL_TYPE_NULL /* APR_DBD_TYPE_NULL \%pDn */};/* result sizes for DBD datatypes (-1 for null-terminated) */static int const sqlSizes[] = { 0, sizeof(char), /**< \%hhd out: char* */ sizeof(unsigned char), /**< \%hhu out: unsigned char* */ sizeof(short), /**< \%hd out: short* */ sizeof(unsigned short), /**< \%hu out: unsigned short* */ sizeof(int), /**< \%d out: int* */ sizeof(unsigned int), /**< \%u out: unsigned int* */ sizeof(long), /**< \%ld out: long* */ sizeof(unsigned long), /**< \%lu out: unsigned long* */ sizeof(apr_int64_t), /**< \%lld out: apr_int64_t* */ sizeof(apr_uint64_t), /**< \%llu out: apr_uint64_t* */ sizeof(float), /**< \%f out: float* */ sizeof(double), /**< \%lf out: double* */ -1, /**< \%s out: char** */ -1, /**< \%pDt out: char** */ -1, /**< \%pDi out: char** */ -1, /**< \%pDd out: char** */ -1, /**< \%pDa out: char** */ -1, /**< \%pDs out: char** */ -1, /**< \%pDz out: char** */ sizeof(apr_bucket_brigade), /**< \%pDb out: apr_bucket_brigade* */ sizeof(apr_bucket_brigade), /**< \%pDc out: apr_bucket_brigade* */ 0 /**< \%pDn : in: void*, out: void** */};/** local functions*//* close any open results for the connection */static apr_status_t odbc_close_results(void *d){ apr_dbd_results_t *dbr = (apr_dbd_results_t *) d; SQLRETURN rc = SQL_SUCCESS; if (dbr && dbr->apr_dbd && dbr->apr_dbd->dbc) { if (!dbr->isclosed) rc = SQLCloseCursor(dbr->stmt); dbr->isclosed = 1; } return APR_FROM_SQL_RESULT(rc);}/* close the ODBC statement handle from a prepare */static apr_status_t odbc_close_pstmt(void *s){ SQLRETURN rc = APR_SUCCESS; apr_dbd_prepared_t *statement = s; /* stmt is closed if connection has already been closed */ if (statement) { SQLHANDLE hstmt = statement->stmt; if (hstmt && statement->apr_dbd && statement->apr_dbd->dbc) { rc = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); } statement->stmt = NULL; } return APR_FROM_SQL_RESULT(rc);}/* close: close/release a connection obtained from open() */static apr_status_t odbc_close(apr_dbd_t *handle){ SQLRETURN rc = SQL_SUCCESS; if (handle->dbc) { rc = SQLDisconnect(handle->dbc); CHECK_ERROR(handle, "SQLDisconnect", rc, SQL_HANDLE_DBC, handle->dbc); rc = SQLFreeHandle(SQL_HANDLE_DBC, handle->dbc); CHECK_ERROR(handle, "SQLFreeHandle (DBC)", rc, SQL_HANDLE_ENV, henv); handle->dbc = NULL; } return APR_FROM_SQL_RESULT(rc);}/* odbc_close re-defined for passing to pool cleanup */static apr_status_t odbc_close_cleanup(void *handle){ return odbc_close( (apr_dbd_t *) handle);}/* close the ODBC environment handle at process termination */static apr_status_t odbc_close_env(SQLHANDLE henv){ SQLRETURN rc; rc = SQLFreeHandle(SQL_HANDLE_ENV, henv); henv = NULL; return APR_FROM_SQL_RESULT(rc);}/* setup the arrays in results for all the returned columns */static SQLRETURN odbc_set_result_column(int icol, apr_dbd_results_t * res, SQLHANDLE stmt){ SQLRETURN rc; int maxsize, textsize, realsize, type, isunsigned = 1; /* discover the sql type */ rc = SQLColAttribute(stmt, icol + 1, SQL_DESC_UNSIGNED, NULL, 0, NULL, (SQLPOINTER) &isunsigned); isunsigned = (isunsigned == SQL_TRUE); rc = SQLColAttribute(stmt, icol + 1, SQL_DESC_TYPE, NULL, 0, NULL, (SQLPOINTER) &type); if (!SQL_SUCCEEDED(rc) || type == SQL_UNKNOWN_TYPE) /* MANY ODBC v2 datasources only supply CONCISE_TYPE */ rc = SQLColAttribute(stmt, icol + 1, SQL_DESC_CONCISE_TYPE, NULL, 0, NULL, (SQLPOINTER) &type); if (!SQL_SUCCEEDED(rc)) /* if still unknown make it CHAR */ type = SQL_C_CHAR; switch (type) { case SQL_INTEGER: case SQL_SMALLINT: case SQL_TINYINT: case SQL_BIGINT: /* fix these numeric binary types up as signed/unsigned for C types */ type += (isunsigned) ? SQL_UNSIGNED_OFFSET : SQL_SIGNED_OFFSET; break; /* LOB types are not changed to C types */ case SQL_LONGVARCHAR: type = SQL_LONGVARCHAR; break; case SQL_LONGVARBINARY: type = SQL_LONGVARBINARY; break; case SQL_FLOAT : type = SQL_C_FLOAT; break; case SQL_DOUBLE : type = SQL_C_DOUBLE; break; /* DBD wants times as strings */ case SQL_TIMESTAMP: case SQL_DATE: case SQL_TIME: default: type = SQL_C_CHAR; } res->coltypes[icol] = type; /* size if retrieved as text */ rc = SQLColAttribute(stmt, icol + 1, SQL_DESC_DISPLAY_SIZE, NULL, 0, NULL, (SQLPOINTER) & textsize);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?