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 + -
显示快捷键?