1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
21 #include "apr_strings.h"
22 #include "apr_buckets.h"
24 #include "apr_file_io.h"
25 #include "apr_file_info.h"
26 #include "apr_dbd_internal.h"
27 #include "apr_thread_proc.h"
28 #include "apu_version.h"
30 /* If library is ODBC-V2, use macros for limited ODBC-V2 support
31 * No random access in V2.
34 #define ODBCVER 0x0200
35 #include "apr_dbd_odbc_v2.h"
38 /* standard ODBC include files */
42 #elif defined(HAVE_ODBC_SQL_H)
44 #include <odbc/sqlext.h>
47 /* Driver name is "odbc" and the entry point is 'apr_dbd_odbc_driver'
48 * unless ODBC_DRIVER_NAME is defined and it is linked with another db library which
49 * is ODBC source-compatible. e.g. DB2, Informix, TimesTen, mysql.
51 #ifndef ODBC_DRIVER_NAME
52 #define ODBC_DRIVER_NAME odbc
54 #define STRINGIFY(x) #x
55 #define NAMIFY2(n) apr_dbd_##n##_driver
56 #define NAMIFY1(n) NAMIFY2(n)
57 #define ODBC_DRIVER_STRING STRINGIFY(ODBC_DRIVER_NAME)
58 #define ODBC_DRIVER_ENTRY NAMIFY1(ODBC_DRIVER_NAME)
60 /* Required APR version for this driver */
61 #define DRIVER_APU_VERSION_MAJOR APU_MAJOR_VERSION
62 #define DRIVER_APU_VERSION_MINOR APU_MINOR_VERSION
65 static SQLHANDLE henv
= NULL
; /* ODBC ENV handle is process-wide */
67 /* Use a CHECK_ERROR macro so we can grab the source line numbers
68 * for error reports */
69 static void check_error(apr_dbd_t
*a
, const char *step
, SQLRETURN rc
,
70 SQLSMALLINT type
, SQLHANDLE h
, int line
);
71 #define CHECK_ERROR(a,s,r,t,h) check_error(a,s,r,t,h, __LINE__)
73 #define SOURCE_FILE __FILE__ /* source file for error messages */
74 #define MAX_ERROR_STRING 1024 /* max length of message in dbc */
75 #define MAX_COLUMN_NAME 256 /* longest column name recognized */
76 #define DEFAULT_BUFFER_SIZE 1024 /* value for defaultBufferSize */
79 #define DEFAULTSEPS " \t\r\n,="
80 #define CSINGLEQUOTE '\''
81 #define SSINGLEQUOTE "\'"
83 #define TEXTMODE 1 /* used for text (APR 1.2) mode params */
84 #define BINARYMODE 0 /* used for binary (APR 1.3+) mode params */
86 /* Identify datatypes which are LOBs
87 * - DB2 DRDA driver uses undefined types -98 and -99 for CLOB & BLOB */
88 #define IS_LOB(t) (t == SQL_LONGVARCHAR \
89 || t == SQL_LONGVARBINARY || t == SQL_VARBINARY \
90 || t == -98 || t == -99)
91 /* These types are CLOBs
92 * - DB2 DRDA driver uses undefined type -98 for CLOB */
94 (t == SQL_LONGVARCHAR || t == -98)
96 /* Convert a SQL result to an APR result */
97 #define APR_FROM_SQL_RESULT(rc) \
98 (SQL_SUCCEEDED(rc) ? APR_SUCCESS : APR_EGENERAL)
100 /* DBD opaque structures */
103 SQLHANDLE dbc
; /* SQL connection handle - NULL after close */
104 apr_pool_t
*pool
; /* connection lifetime pool */
105 char *dbname
; /* ODBC datasource */
108 char lastError
[MAX_ERROR_STRING
];
109 int defaultBufferSize
; /* used for CLOBs in text mode,
110 * and when fld size is indeterminate */
111 int transaction_mode
;
112 int dboptions
; /* driver options re SQLGetData */
113 int default_transaction_mode
;
114 int can_commit
; /* controls end_trans behavior */
117 struct apr_dbd_results_t
119 SQLHANDLE stmt
; /* parent sql statement handle */
120 SQLHANDLE dbc
; /* parent sql connection handle */
121 apr_pool_t
*pool
; /* pool from query or select */
122 apr_dbd_t
*apr_dbd
; /* parent DBD connection handle */
123 int random
; /* random access requested */
124 int ncols
; /* number of columns */
125 int isclosed
; /* cursor has been closed */
126 char **colnames
; /* array of column names (NULL until used) */
127 SQLPOINTER
*colptrs
; /* pointers to column data */
128 SQLINTEGER
*colsizes
; /* sizes for columns (enough for txt or bin) */
129 SQLINTEGER
*coltextsizes
; /* max-sizes if converted to text */
130 SQLSMALLINT
*coltypes
; /* array of SQL data types for columns */
131 SQLLEN
*colinds
; /* array of SQL data indicator/strlens */
132 int *colstate
; /* array of column states
133 * - avail, bound, present, unavail
135 int *all_data_fetched
; /* flags data as all fetched, for LOBs */
136 void *data
; /* buffer for all data for one row */
138 enum /* results column states */
140 COL_AVAIL
, /* data may be retrieved with SQLGetData */
141 COL_PRESENT
, /* data has been retrieved with SQLGetData */
142 COL_BOUND
, /* column is bound to colptr */
143 COL_RETRIEVED
, /* all data from column has been returned */
144 COL_UNAVAIL
/* column is unavailable because ODBC driver
145 * requires that columns be retrieved
146 * in ascending order and a higher col
150 struct apr_dbd_row_t
{
151 SQLHANDLE stmt
; /* parent ODBC statement handle */
152 SQLHANDLE dbc
; /* parent ODBC connection handle */
153 apr_pool_t
*pool
; /* pool from get_row */
154 apr_dbd_results_t
*res
;
157 struct apr_dbd_transaction_t
{
158 SQLHANDLE dbc
; /* parent ODBC connection handle */
159 apr_dbd_t
*apr_dbd
; /* parent DBD connection handle */
162 struct apr_dbd_prepared_t
{
163 SQLHANDLE stmt
; /* ODBC statement handle */
164 SQLHANDLE dbc
; /* parent ODBC connection handle */
168 int *types
; /* array of DBD data types */
172 static void odbc_lob_bucket_destroy(void *data
);
173 static apr_status_t
odbc_lob_bucket_setaside(apr_bucket
*e
, apr_pool_t
*pool
);
174 static apr_status_t
odbc_lob_bucket_read(apr_bucket
*e
, const char **str
,
175 apr_size_t
*len
, apr_read_type_e block
);
177 /* the ODBC LOB bucket type */
178 static const apr_bucket_type_t odbc_bucket_type
= {
179 "ODBC_LOB", 5, APR_BUCKET_DATA
,
180 odbc_lob_bucket_destroy
,
181 odbc_lob_bucket_read
,
182 odbc_lob_bucket_setaside
,
183 apr_bucket_shared_split
,
184 apr_bucket_shared_copy
188 /* ODBC LOB bucket data */
190 /** Ref count for shared bucket */
191 apr_bucket_refcount refcount
;
192 const apr_dbd_row_t
*row
;
198 /* SQL datatype mappings to DBD datatypes
199 * These tables must correspond *exactly* to the apr_dbd_type_e enum
200 * in apr_dbd_internal.h
203 /* ODBC "C" types to DBD datatypes */
204 static SQLSMALLINT
const sqlCtype
[] = {
205 SQL_C_DEFAULT
, /* APR_DBD_TYPE_NONE */
206 SQL_C_STINYINT
, /* APR_DBD_TYPE_TINY, \%hhd */
207 SQL_C_UTINYINT
, /* APR_DBD_TYPE_UTINY, \%hhu */
208 SQL_C_SSHORT
, /* APR_DBD_TYPE_SHORT, \%hd */
209 SQL_C_USHORT
, /* APR_DBD_TYPE_USHORT, \%hu */
210 SQL_C_SLONG
, /* APR_DBD_TYPE_INT, \%d */
211 SQL_C_ULONG
, /* APR_DBD_TYPE_UINT, \%u */
212 SQL_C_SLONG
, /* APR_DBD_TYPE_LONG, \%ld */
213 SQL_C_ULONG
, /* APR_DBD_TYPE_ULONG, \%lu */
214 SQL_C_SBIGINT
, /* APR_DBD_TYPE_LONGLONG, \%lld */
215 SQL_C_UBIGINT
, /* APR_DBD_TYPE_ULONGLONG, \%llu */
216 SQL_C_FLOAT
, /* APR_DBD_TYPE_FLOAT, \%f */
217 SQL_C_DOUBLE
, /* APR_DBD_TYPE_DOUBLE, \%lf */
218 SQL_C_CHAR
, /* APR_DBD_TYPE_STRING, \%s */
219 SQL_C_CHAR
, /* APR_DBD_TYPE_TEXT, \%pDt */
220 SQL_C_CHAR
, /*SQL_C_TYPE_TIME, APR_DBD_TYPE_TIME, \%pDi */
221 SQL_C_CHAR
, /*SQL_C_TYPE_DATE, APR_DBD_TYPE_DATE, \%pDd */
222 SQL_C_CHAR
, /*SQL_C_TYPE_TIMESTAMP, APR_DBD_TYPE_DATETIME, \%pDa */
223 SQL_C_CHAR
, /*SQL_C_TYPE_TIMESTAMP, APR_DBD_TYPE_TIMESTAMP, \%pDs */
224 SQL_C_CHAR
, /*SQL_C_TYPE_TIMESTAMP, APR_DBD_TYPE_ZTIMESTAMP, \%pDz */
225 SQL_LONGVARBINARY
, /* APR_DBD_TYPE_BLOB, \%pDb */
226 SQL_LONGVARCHAR
, /* APR_DBD_TYPE_CLOB, \%pDc */
227 SQL_TYPE_NULL
/* APR_DBD_TYPE_NULL \%pDn */
230 /* ODBC Base types to DBD datatypes */
231 static SQLSMALLINT
const sqlBaseType
[] = {
232 SQL_C_DEFAULT
, /* APR_DBD_TYPE_NONE */
233 SQL_TINYINT
, /* APR_DBD_TYPE_TINY, \%hhd */
234 SQL_TINYINT
, /* APR_DBD_TYPE_UTINY, \%hhu */
235 SQL_SMALLINT
, /* APR_DBD_TYPE_SHORT, \%hd */
236 SQL_SMALLINT
, /* APR_DBD_TYPE_USHORT, \%hu */
237 SQL_INTEGER
, /* APR_DBD_TYPE_INT, \%d */
238 SQL_INTEGER
, /* APR_DBD_TYPE_UINT, \%u */
239 SQL_INTEGER
, /* APR_DBD_TYPE_LONG, \%ld */
240 SQL_INTEGER
, /* APR_DBD_TYPE_ULONG, \%lu */
241 SQL_BIGINT
, /* APR_DBD_TYPE_LONGLONG, \%lld */
242 SQL_BIGINT
, /* APR_DBD_TYPE_ULONGLONG, \%llu */
243 SQL_FLOAT
, /* APR_DBD_TYPE_FLOAT, \%f */
244 SQL_DOUBLE
, /* APR_DBD_TYPE_DOUBLE, \%lf */
245 SQL_CHAR
, /* APR_DBD_TYPE_STRING, \%s */
246 SQL_CHAR
, /* APR_DBD_TYPE_TEXT, \%pDt */
247 SQL_CHAR
, /*SQL_TIME, APR_DBD_TYPE_TIME, \%pDi */
248 SQL_CHAR
, /*SQL_DATE, APR_DBD_TYPE_DATE, \%pDd */
249 SQL_CHAR
, /*SQL_TIMESTAMP, APR_DBD_TYPE_DATETIME, \%pDa */
250 SQL_CHAR
, /*SQL_TIMESTAMP, APR_DBD_TYPE_TIMESTAMP, \%pDs */
251 SQL_CHAR
, /*SQL_TIMESTAMP, APR_DBD_TYPE_ZTIMESTAMP, \%pDz */
252 SQL_LONGVARBINARY
, /* APR_DBD_TYPE_BLOB, \%pDb */
253 SQL_LONGVARCHAR
, /* APR_DBD_TYPE_CLOB, \%pDc */
254 SQL_TYPE_NULL
/* APR_DBD_TYPE_NULL \%pDn */
257 /* result sizes for DBD datatypes (-1 for null-terminated) */
258 static int const sqlSizes
[] = {
260 sizeof(char), /**< \%hhd out: char* */
261 sizeof(unsigned char), /**< \%hhu out: unsigned char* */
262 sizeof(short), /**< \%hd out: short* */
263 sizeof(unsigned short), /**< \%hu out: unsigned short* */
264 sizeof(int), /**< \%d out: int* */
265 sizeof(unsigned int), /**< \%u out: unsigned int* */
266 sizeof(long), /**< \%ld out: long* */
267 sizeof(unsigned long), /**< \%lu out: unsigned long* */
268 sizeof(apr_int64_t
), /**< \%lld out: apr_int64_t* */
269 sizeof(apr_uint64_t
), /**< \%llu out: apr_uint64_t* */
270 sizeof(float), /**< \%f out: float* */
271 sizeof(double), /**< \%lf out: double* */
272 -1, /**< \%s out: char** */
273 -1, /**< \%pDt out: char** */
274 -1, /**< \%pDi out: char** */
275 -1, /**< \%pDd out: char** */
276 -1, /**< \%pDa out: char** */
277 -1, /**< \%pDs out: char** */
278 -1, /**< \%pDz out: char** */
279 sizeof(apr_bucket_brigade
), /**< \%pDb out: apr_bucket_brigade* */
280 sizeof(apr_bucket_brigade
), /**< \%pDc out: apr_bucket_brigade* */
281 0 /**< \%pDn : in: void*, out: void** */
288 /* close any open results for the connection */
289 static apr_status_t
odbc_close_results(void *d
)
290 { apr_dbd_results_t
*dbr
= (apr_dbd_results_t
*) d
;
291 SQLRETURN rc
= SQL_SUCCESS
;
293 if (dbr
&& !dbr
->isclosed
) {
294 rc
= SQLCloseCursor(dbr
->stmt
);
297 return APR_FROM_SQL_RESULT(rc
);
300 /* close the ODBC statement handle from a prepare */
301 static apr_status_t
odbc_close_pstmt(void *s
)
303 SQLRETURN rc
= APR_SUCCESS
;
304 apr_dbd_prepared_t
*statement
= s
;
305 SQLHANDLE hstmt
= statement
->stmt
;
306 /* stmt is closed if connection has already been closed */
307 if (hstmt
&& statement
->apr_dbd
&& statement
->apr_dbd
->dbc
) {
308 rc
= SQLFreeHandle(SQL_HANDLE_STMT
, hstmt
);
310 statement
->stmt
= NULL
;
311 return APR_FROM_SQL_RESULT(rc
);
314 /* close: close/release a connection obtained from open() */
315 static apr_status_t
odbc_close(apr_dbd_t
*handle
)
317 SQLRETURN rc
= SQL_SUCCESS
;
320 rc
= SQLDisconnect(handle
->dbc
);
321 CHECK_ERROR(handle
, "SQLDisconnect", rc
, SQL_HANDLE_DBC
, handle
->dbc
);
322 rc
= SQLFreeHandle(SQL_HANDLE_DBC
, handle
->dbc
);
323 CHECK_ERROR(handle
, "SQLFreeHandle (DBC)", rc
, SQL_HANDLE_ENV
, henv
);
326 return APR_FROM_SQL_RESULT(rc
);
329 /* odbc_close re-defined for passing to pool cleanup */
330 static apr_status_t
odbc_close_cleanup(void *handle
)
332 return odbc_close( (apr_dbd_t
*) handle
);
335 /* close the ODBC environment handle at process termination */
336 static apr_status_t
odbc_close_env(SQLHANDLE henv
)
340 rc
= SQLFreeHandle(SQL_HANDLE_ENV
, henv
);
342 return APR_FROM_SQL_RESULT(rc
);
345 /* setup the arrays in results for all the returned columns */
346 static SQLRETURN
odbc_set_result_column(int icol
, apr_dbd_results_t
* res
,
350 int maxsize
, textsize
, realsize
, type
, isunsigned
= 1;
352 /* discover the sql type */
353 rc
= SQLColAttribute(stmt
, icol
+ 1, SQL_DESC_UNSIGNED
, NULL
, 0, NULL
,
354 (SQLPOINTER
) &isunsigned
);
355 isunsigned
= (isunsigned
== SQL_TRUE
);
357 rc
= SQLColAttribute(stmt
, icol
+ 1, SQL_DESC_TYPE
, NULL
, 0, NULL
,
359 if (!SQL_SUCCEEDED(rc
) || type
== SQL_UNKNOWN_TYPE
)
360 /* MANY ODBC v2 datasources only supply CONCISE_TYPE */
361 rc
= SQLColAttribute(stmt
, icol
+ 1, SQL_DESC_CONCISE_TYPE
, NULL
,
362 0, NULL
, (SQLPOINTER
) &type
);
363 if (!SQL_SUCCEEDED(rc
))
364 /* if still unknown make it CHAR */
372 /* fix these numeric binary types up as signed/unsigned for C types */
373 type
+= (isunsigned
) ? SQL_UNSIGNED_OFFSET
: SQL_SIGNED_OFFSET
;
375 /* LOB types are not changed to C types */
376 case SQL_LONGVARCHAR
:
377 type
= SQL_LONGVARCHAR
;
379 case SQL_LONGVARBINARY
:
380 type
= SQL_LONGVARBINARY
;
389 /* DBD wants times as strings */
397 res
->coltypes
[icol
] = type
;
399 /* size if retrieved as text */
400 rc
= SQLColAttribute(stmt
, icol
+ 1, SQL_DESC_DISPLAY_SIZE
, NULL
, 0,
401 NULL
, (SQLPOINTER
) & textsize
);
402 if (!SQL_SUCCEEDED(rc
) || textsize
< 0)
403 textsize
= res
->apr_dbd
->defaultBufferSize
;
404 /* for null-term, which sometimes isn't included */
408 rc
= SQLColAttribute(stmt
, icol
+ 1, SQL_DESC_OCTET_LENGTH
, NULL
, 0,
409 NULL
, (SQLPOINTER
) & realsize
);
410 if (!SQL_SUCCEEDED(rc
))
413 maxsize
= (textsize
> realsize
) ? textsize
: realsize
;
414 if ( IS_LOB(type
) || maxsize
<= 0) {
415 /* LOB types are never bound and have a NULL colptr for binary.
416 * Ingore their real (1-2gb) length & use a default - the larger
417 * of defaultBufferSize or APR_BUCKET_BUFF_SIZE.
418 * If not a LOB, but simply unknown length - always use defaultBufferSize.
420 maxsize
= res
->apr_dbd
->defaultBufferSize
;
421 if ( IS_LOB(type
) && maxsize
< APR_BUCKET_BUFF_SIZE
)
422 maxsize
= APR_BUCKET_BUFF_SIZE
;
424 res
->colptrs
[icol
] = NULL
;
425 res
->colstate
[icol
] = COL_AVAIL
;
426 res
->colsizes
[icol
] = maxsize
;
430 res
->colptrs
[icol
] = apr_pcalloc(res
->pool
, maxsize
);
431 res
->colsizes
[icol
] = maxsize
;
432 if (res
->apr_dbd
->dboptions
& SQL_GD_BOUND
) {
433 /* we are allowed to call SQLGetData if we need to */
434 rc
= SQLBindCol(stmt
, icol
+ 1, res
->coltypes
[icol
],
435 res
->colptrs
[icol
], maxsize
,
436 &(res
->colinds
[icol
]) );
437 CHECK_ERROR(res
->apr_dbd
, "SQLBindCol", rc
, SQL_HANDLE_STMT
,
439 res
->colstate
[icol
] = SQL_SUCCEEDED(rc
) ? COL_BOUND
: COL_AVAIL
;
442 /* this driver won't allow us to call SQLGetData on bound
443 * columns - so don't bind any */
444 res
->colstate
[icol
] = COL_AVAIL
;
451 /* create and populate an apr_dbd_results_t for a select */
452 static SQLRETURN
odbc_create_results(apr_dbd_t
* handle
, SQLHANDLE hstmt
,
453 apr_pool_t
* pool
, const int random
,
454 apr_dbd_results_t
** res
)
459 *res
= apr_pcalloc(pool
, sizeof(apr_dbd_results_t
));
460 (*res
)->stmt
= hstmt
;
461 (*res
)->dbc
= handle
->dbc
;
463 (*res
)->random
= random
;
464 (*res
)->apr_dbd
= handle
;
465 rc
= SQLNumResultCols(hstmt
, &ncols
);
466 CHECK_ERROR(handle
, "SQLNumResultCols", rc
, SQL_HANDLE_STMT
, hstmt
);
467 (*res
)->ncols
= ncols
;
469 if SQL_SUCCEEDED(rc
) {
472 (*res
)->colnames
= apr_pcalloc(pool
, ncols
* sizeof(char *));
473 (*res
)->colptrs
= apr_pcalloc(pool
, ncols
* sizeof(void *));
474 (*res
)->colsizes
= apr_pcalloc(pool
, ncols
* sizeof(SQLINTEGER
));
475 (*res
)->coltypes
= apr_pcalloc(pool
, ncols
* sizeof(SQLSMALLINT
));
476 (*res
)->colinds
= apr_pcalloc(pool
, ncols
* sizeof(SQLLEN
));
477 (*res
)->colstate
= apr_pcalloc(pool
, ncols
* sizeof(int));
478 (*res
)->ncols
= ncols
;
480 for (i
= 0 ; i
< ncols
; i
++)
481 odbc_set_result_column(i
, (*res
), hstmt
);
487 /* bind a parameter - input params only, does not support output parameters */
488 static SQLRETURN
odbc_bind_param(apr_pool_t
* pool
,
489 apr_dbd_prepared_t
* statement
, const int narg
,
490 const SQLSMALLINT type
, int *argp
,
491 const void **args
, const int textmode
)
494 SQLSMALLINT baseType
, cType
;
497 SQLINTEGER
*indicator
;
498 static SQLINTEGER nullValue
= SQL_NULL_DATA
;
499 static SQLSMALLINT inOut
= SQL_PARAM_INPUT
; /* only input params */
501 /* bind a NULL data value */
502 if (args
[*argp
] == NULL
|| type
== APR_DBD_TYPE_NULL
) {
506 len
= sizeof(SQLINTEGER
);
507 indicator
= &nullValue
;
510 /* bind a non-NULL data value */
512 baseType
= sqlBaseType
[type
];
513 cType
= sqlCtype
[type
];
517 ptr
= (void *) args
[*argp
];
518 len
= (SQLUINTEGER
) * (apr_size_t
*) args
[*argp
+ 1];
519 cType
= (IS_CLOB(cType
)) ? SQL_C_CHAR
: SQL_C_DEFAULT
;
520 (*argp
) += 4; /* LOBs consume 4 args (last two are unused) */
529 ptr
= (void *) args
[*argp
];
530 len
= (SQLUINTEGER
) strlen(ptr
);
533 ptr
= apr_palloc(pool
, sizeof(unsigned char));
534 len
= sizeof(unsigned char);
535 *(unsigned char *) ptr
=
537 atoi(args
[*argp
]) : *(unsigned char *) args
[*argp
]);
540 ptr
= apr_palloc(pool
, sizeof(short));
543 (textmode
? atoi(args
[*argp
]) : *(short *) args
[*argp
]);
546 ptr
= apr_palloc(pool
, sizeof(int));
549 (textmode
? atol(args
[*argp
]) : *(long *) args
[*argp
]);
552 ptr
= apr_palloc(pool
, sizeof(float));
556 (float) atof(args
[*argp
]) : *(float *) args
[*argp
]);
559 ptr
= apr_palloc(pool
, sizeof(double));
560 len
= sizeof(double);
562 (textmode
? atof(args
[*argp
]) : *(double *)
566 ptr
= apr_palloc(pool
, sizeof(apr_int64_t
));
567 len
= sizeof(apr_int64_t
);
568 *(apr_int64_t
*) ptr
=
570 apr_atoi64(args
[*argp
]) : *(apr_int64_t
*) args
[*argp
]);
575 (*argp
)++; /* non LOBs consume one argument */
578 rc
= SQLBindParameter(statement
->stmt
, narg
, inOut
, cType
,
579 baseType
, len
, 0, ptr
, len
, indicator
);
580 CHECK_ERROR(statement
->apr_dbd
, "SQLBindParameter", rc
, SQL_HANDLE_STMT
,
585 /* LOB / Bucket Brigade functions */
589 /* bucket type specific destroy */
590 static void odbc_lob_bucket_destroy(void *data
)
592 odbc_bucket
*bd
= data
;
594 if (apr_bucket_shared_destroy(bd
))
598 /* set aside a bucket if possible */
599 static apr_status_t
odbc_lob_bucket_setaside(apr_bucket
*e
, apr_pool_t
*pool
)
601 odbc_bucket
*bd
= (odbc_bucket
*) e
->data
;
603 /* Unlikely - but if the row pool is ancestor of this pool then it is OK */
604 if (apr_pool_is_ancestor(bd
->row
->pool
, pool
))
607 return apr_bucket_setaside_notimpl(e
, pool
);
610 /* split a bucket into a heap bucket followed by a LOB bkt w/remaining data */
611 static apr_status_t
odbc_lob_bucket_read(apr_bucket
*e
, const char **str
,
612 apr_size_t
*len
, apr_read_type_e block
)
615 SQLINTEGER len_indicator
;
617 odbc_bucket
*bd
= (odbc_bucket
*) e
->data
;
620 int bufsize
= bd
->row
->res
->apr_dbd
->defaultBufferSize
;
623 /* C type is CHAR for CLOBs, DEFAULT for BLOBs */
624 type
= bd
->row
->res
->coltypes
[bd
->col
];
625 type
= (type
== SQL_LONGVARCHAR
) ? SQL_C_CHAR
: SQL_C_DEFAULT
;
627 /* LOB buffers are always at least APR_BUCKET_BUFF_SIZE,
628 * but they may be much bigger per the BUFSIZE parameter.
630 if (bufsize
< APR_BUCKET_BUFF_SIZE
)
631 bufsize
= APR_BUCKET_BUFF_SIZE
;
633 buf
= apr_bucket_alloc(bufsize
, e
->list
);
637 rc
= SQLGetData(bd
->row
->res
->stmt
, bd
->col
+ 1,
641 CHECK_ERROR(bd
->row
->res
->apr_dbd
, "SQLGetData", rc
,
642 SQL_HANDLE_STMT
, bd
->row
->res
->stmt
);
644 if (rc
== SQL_NO_DATA
|| len_indicator
== SQL_NULL_DATA
|| len_indicator
< 0)
647 if (SQL_SUCCEEDED(rc
) || rc
== SQL_NO_DATA
) {
649 if (rc
= SQL_SUCCESS_WITH_INFO
650 && ( len_indicator
== SQL_NO_TOTAL
|| len_indicator
>= bufsize
) ) {
651 /* not the last read = a full buffer. CLOBs have a null terminator */
652 *len
= bufsize
- (IS_CLOB(bd
->type
) ? 1 : 0 );
657 /* the last read - len_indicator is supposed to be the length,
658 * but some driver get this wrong and return the total length.
659 * We try to handle both interpretations.
661 *len
= (len_indicator
> bufsize
662 && len_indicator
>= (SQLINTEGER
) e
->start
)
663 ? (len_indicator
- (SQLINTEGER
) e
->start
) : len_indicator
;
669 /* Create a new LOB bucket to append and append it */
670 nxt
= apr_bucket_alloc(sizeof(apr_bucket
*), e
->list
);
671 APR_BUCKET_INIT(nxt
);
674 nxt
->type
= &odbc_bucket_type
;
675 nxt
->free
= apr_bucket_free
;
677 nxt
->start
= e
->start
+ *len
;
678 APR_BUCKET_INSERT_AFTER(e
, nxt
);
681 odbc_lob_bucket_destroy(e
->data
);
683 /* make current bucket into a heap bucket */
684 apr_bucket_heap_make(e
, buf
, *len
, apr_bucket_free
);
687 /* No data is success in this context */
690 return APR_FROM_SQL_RESULT(rc
);
693 /* Create a bucket brigade on the row pool for a LOB column */
694 static apr_status_t
odbc_create_bucket(const apr_dbd_row_t
*row
, const int col
,
695 SQLSMALLINT type
, apr_bucket_brigade
*bb
)
697 apr_bucket_alloc_t
*list
= bb
->bucket_alloc
;
698 apr_bucket
*b
= apr_bucket_alloc(sizeof(*b
), list
);
699 odbc_bucket
*bd
= apr_bucket_alloc(sizeof(odbc_bucket
), list
);
700 apr_bucket
*eos
= apr_bucket_eos_create(list
);
709 b
->type
= &odbc_bucket_type
;
710 b
->free
= apr_bucket_free
;
712 /* LOB lengths are unknown in ODBC */
713 b
= apr_bucket_shared_make(b
, bd
, 0, -1);
715 APR_BRIGADE_INSERT_TAIL(bb
, b
);
716 APR_BRIGADE_INSERT_TAIL(bb
, eos
);
721 /* returns a data pointer for a column, returns NULL for NULL value,
722 * return -1 if data not available */
723 static void *odbc_get(const apr_dbd_row_t
*row
, const int col
,
724 const SQLSMALLINT sqltype
)
727 SQLINTEGER indicator
;
728 int state
= row
->res
->colstate
[col
];
729 int options
= row
->res
->apr_dbd
->dboptions
;
732 case (COL_UNAVAIL
) : return (void *) -1;
733 case (COL_RETRIEVED
) : return NULL
;
737 if (sqltype
== row
->res
->coltypes
[col
]) {
738 /* same type and we already have the data */
739 row
->res
->colstate
[col
] = COL_RETRIEVED
;
740 return (row
->res
->colinds
[col
] == SQL_NULL_DATA
) ?
741 NULL
: row
->res
->colptrs
[col
];
745 /* we need to get the data now */
746 if (!(options
& SQL_GD_ANY_ORDER
)) {
747 /* this ODBC driver requires columns to be retrieved in order,
748 * so we attempt to get every prior un-gotten non-LOB column */
750 for (i
= 0; i
< col
; i
++) {
751 if (row
->res
->colstate
[i
] == COL_AVAIL
) {
752 if (IS_LOB(row
->res
->coltypes
[i
]))
753 row
->res
->colstate
[i
] = COL_UNAVAIL
;
755 odbc_get(row
, i
, row
->res
->coltypes
[i
]);
756 row
->res
->colstate
[i
] = COL_PRESENT
;
762 if ((state
== COL_BOUND
&& !(options
& SQL_GD_BOUND
)))
763 /* this driver won't let us re-get bound columns */
766 /* a LOB might not have a buffer allocated yet - so create one */
767 if (!row
->res
->colptrs
[col
])
768 row
->res
->colptrs
[col
] = apr_pcalloc(row
->pool
, row
->res
->colsizes
[col
]);
770 rc
= SQLGetData(row
->res
->stmt
, col
+ 1, sqltype
, row
->res
->colptrs
[col
],
771 row
->res
->colsizes
[col
], &indicator
);
772 CHECK_ERROR(row
->res
->apr_dbd
, "SQLGetData", rc
, SQL_HANDLE_STMT
,
774 if (indicator
== SQL_NULL_DATA
|| rc
== SQL_NO_DATA
)
777 if (SQL_SUCCEEDED(rc
)) {
778 /* whatever it was originally, it is now this sqltype */
779 row
->res
->coltypes
[col
] = sqltype
;
780 /* this allows getting CLOBs in text mode by calling get_entry
781 * until it returns NULL */
782 row
->res
->colstate
[col
] =
783 (rc
== SQL_SUCCESS_WITH_INFO
) ? COL_AVAIL
: COL_RETRIEVED
;
784 return row
->res
->colptrs
[col
];
786 else return (void *) -1;
789 /* Parse the parameter string for open */
790 static apr_status_t
odbc_parse_params(apr_pool_t
*pool
, const char *params
,
791 int *connect
, SQLCHAR
**datasource
,
792 SQLCHAR
**user
, SQLCHAR
**password
,
793 int *defaultBufferSize
, int *nattrs
,
794 int **attrs
, int **attrvals
)
796 char *seps
, *last
, *name
[MAX_PARAMS
], *val
[MAX_PARAMS
];
799 *attrs
= apr_pcalloc(pool
, MAX_PARAMS
* sizeof(char *));
800 *attrvals
= apr_pcalloc(pool
, MAX_PARAMS
* sizeof(int));
803 name
[nparams
] = apr_strtok(apr_pstrdup(pool
, params
), seps
, &last
);
805 if (last
[strspn(last
, seps
)] == CSINGLEQUOTE
) {
806 last
+= strspn(last
, seps
);
809 val
[nparams
] = apr_strtok(NULL
, seps
, &last
);
811 name
[++nparams
] = apr_strtok(NULL
, seps
, &last
);
812 } while ( nparams
<= MAX_PARAMS
&& name
[nparams
] != NULL
813 && val
[nparams
] != NULL
);
815 for(j
=i
=0 ; i
< nparams
; i
++)
816 { if (!apr_strnatcasecmp(name
[i
], "CONNECT"))
817 { *datasource
= apr_pstrdup(pool
, val
[i
]);
820 else if (!apr_strnatcasecmp(name
[i
], "DATASOURCE"))
821 { *datasource
= apr_pstrdup(pool
, val
[i
]);
824 else if (!apr_strnatcasecmp(name
[i
], "USER"))
825 *user
= apr_pstrdup(pool
, val
[i
]);
826 else if (!apr_strnatcasecmp(name
[i
], "PASSWORD"))
827 *password
= apr_pstrdup(pool
, val
[i
]);
828 else if (!apr_strnatcasecmp(name
[i
], "BUFSIZE"))
829 *defaultBufferSize
= atoi(val
[i
]);
830 else if (!apr_strnatcasecmp(name
[i
], "ACCESS"))
831 { if (!apr_strnatcasecmp(val
[i
], "READ_ONLY"))
832 (*attrvals
)[j
] = SQL_MODE_READ_ONLY
;
833 else if (!apr_strnatcasecmp(val
[i
], "READ_WRITE"))
834 (*attrvals
)[j
] = SQL_MODE_READ_WRITE
;
835 else return SQL_ERROR
;
836 (*attrs
)[j
++] = SQL_ATTR_ACCESS_MODE
;
838 else if (!apr_strnatcasecmp(name
[i
], "CTIMEOUT"))
839 { (*attrvals
)[j
] = atoi(val
[i
]);
840 (*attrs
)[j
++] = SQL_ATTR_LOGIN_TIMEOUT
;
842 else if (!apr_strnatcasecmp(name
[i
], "STIMEOUT"))
843 { (*attrvals
)[j
] = atoi(val
[i
]);
844 (*attrs
)[j
++] = SQL_ATTR_CONNECTION_TIMEOUT
;
846 else if (!apr_strnatcasecmp(name
[i
], "TXMODE"))
847 { if (!apr_strnatcasecmp(val
[i
], "READ_UNCOMMITTED"))
848 (*attrvals
)[j
] = SQL_TXN_READ_UNCOMMITTED
;
849 else if (!apr_strnatcasecmp(val
[i
], "READ_COMMITTED"))
850 (*attrvals
)[j
] = SQL_TXN_READ_COMMITTED
;
851 else if (!apr_strnatcasecmp(val
[i
], "REPEATABLE_READ"))
852 (*attrvals
)[j
] = SQL_TXN_REPEATABLE_READ
;
853 else if (!apr_strnatcasecmp(val
[i
], "SERIALIZABLE"))
854 (*attrvals
)[j
] = SQL_TXN_SERIALIZABLE
;
855 else if (!apr_strnatcasecmp(val
[i
], "DEFAULT"))
857 else return SQL_ERROR
;
858 (*attrs
)[j
++] = SQL_ATTR_TXN_ISOLATION
;
860 else return SQL_ERROR
;
863 return (*datasource
&& *defaultBufferSize
) ? APR_SUCCESS
: SQL_ERROR
;
866 /* common handling after ODBC calls - save error info (code and text) in dbc */
867 static void check_error(apr_dbd_t
*dbc
, const char *step
, SQLRETURN rc
,
868 SQLSMALLINT type
, SQLHANDLE h
, int line
)
871 SQLCHAR sqlstate
[128];
873 SQLSMALLINT reslength
;
874 char *res
, *p
, *end
, *logval
=NULL
;
878 /* set info about last error in dbc - fast return for SQL_SUCCESS */
879 if (rc
== SQL_SUCCESS
) {
880 char successMsg
[] = "[dbd_odbc] SQL_SUCCESS ";
881 dbc
->lasterrorcode
= SQL_SUCCESS
;
882 strcpy(dbc
->lastError
, successMsg
);
883 strcpy(dbc
->lastError
+sizeof(successMsg
)-1, step
);
887 case SQL_INVALID_HANDLE
: { res
= "SQL_INVALID_HANDLE"; break; }
888 case SQL_ERROR
: { res
= "SQL_ERROR"; break; }
889 case SQL_SUCCESS_WITH_INFO
: { res
= "SQL_SUCCESS_WITH_INFO"; break; }
890 case SQL_STILL_EXECUTING
: { res
= "SQL_STILL_EXECUTING"; break; }
891 case SQL_NEED_DATA
: { res
= "SQL_NEED_DATA"; break; }
892 case SQL_NO_DATA
: { res
= "SQL_NO_DATA"; break; }
893 default : { res
= "unrecognized SQL return code"; }
895 /* these two returns are expected during normal execution */
896 if (rc
!= SQL_SUCCESS_WITH_INFO
&& rc
!= SQL_NO_DATA
)
899 end
= p
+ sizeof(dbc
->lastError
);
900 dbc
->lasterrorcode
= rc
;
901 p
+= sprintf(p
, "[dbd_odbc] %.64s returned %.30s (%d) at %.24s:%d ",
902 step
, res
, rc
, SOURCE_FILE
, line
-1);
903 for (i
=1, rc
=0 ; rc
==0 ; i
++) {
904 rc
= SQLGetDiagRec(type
, h
, i
, sqlstate
, &native
, buffer
,
905 sizeof(buffer
), &reslength
);
906 if (SQL_SUCCEEDED(rc
) && (p
< (end
-280)))
907 p
+= sprintf(p
, "%.256s %.20s ", buffer
, sqlstate
);
909 r
= apr_env_get(&logval
, "apr_dbd_odbc_log", dbc
->pool
);
910 /* if env var was set or call was init/open (no dbname) - log to stderr */
911 if (logval
|| !dbc
->dbname
) {
912 char timestamp
[APR_CTIME_LEN
];
914 apr_ctime(timestamp
, apr_time_now());
915 apr_file_open_stderr(&se
, dbc
->pool
);
916 apr_file_printf(se
, "[%s] %s\n", timestamp
, dbc
->lastError
);
921 * public functions per DBD driver API
924 /** init: allow driver to perform once-only initialisation. **/
925 static void odbc_init(apr_pool_t
*pool
)
929 apr_version_t apuver
;
931 apu_version(&apuver
);
932 if (apuver
.major
!= DRIVER_APU_VERSION_MAJOR
933 || apuver
.minor
!= DRIVER_APU_VERSION_MINOR
) {
936 apr_file_open_stderr(&se
, pool
);
937 apr_file_printf(se
, "Incorrect " ODBC_DRIVER_STRING
" dbd driver version\n"
938 "Attempt to load APU version %d.%d driver with APU version %d.%d\n",
939 DRIVER_APU_VERSION_MAJOR
, DRIVER_APU_VERSION_MINOR
,
940 apuver
.major
, apuver
.minor
);
947 step
= "SQLAllocHandle (SQL_HANDLE_ENV)";
948 rc
= SQLAllocHandle(SQL_HANDLE_ENV
, SQL_NULL_HANDLE
, &henv
);
949 apr_pool_cleanup_register(pool
, henv
, odbc_close_env
, apr_pool_cleanup_null
);
950 if (SQL_SUCCEEDED(rc
))
951 { step
= "SQLSetEnvAttr";
952 rc
= SQLSetEnvAttr(henv
,SQL_ATTR_ODBC_VERSION
,
953 (SQLPOINTER
) SQL_OV_ODBC3
, 0);
957 SQLHANDLE err_h
= henv
;
960 tmp_dbc
.dbname
= NULL
;
961 CHECK_ERROR(&tmp_dbc
, step
, rc
, SQL_HANDLE_ENV
, err_h
);
965 /** native_handle: return the native database handle of the underlying db **/
966 static void* odbc_native_handle(apr_dbd_t
*handle
)
967 { return handle
->dbc
;
970 /** open: obtain a database connection from the server rec. **/
972 /* It would be more efficient to allocate a single statement handle
973 here - but SQL_ATTR_CURSOR_SCROLLABLE must be set before
974 SQLPrepare, and we don't know whether random-access is
975 specified until SQLExecute so we cannot.
978 static apr_dbd_t
* odbc_open(apr_pool_t
*pool
, const char *params
, const char **error
)
981 SQLHANDLE hdbc
= NULL
;
985 int defaultBufferSize
=DEFAULT_BUFFER_SIZE
;
986 SQLHANDLE err_h
= NULL
;
987 SQLCHAR
*datasource
="", *user
="", *password
="";
988 int nattrs
=0, *attrs
=NULL
, *attrvals
=NULL
, connect
=0;
990 err_step
="SQLAllocHandle (SQL_HANDLE_DBC)";
991 err_htype
= SQL_HANDLE_ENV
;
993 rc
= SQLAllocHandle(SQL_HANDLE_DBC
, henv
, &hdbc
);
994 if (SQL_SUCCEEDED(rc
)) {
995 err_step
="Invalid DBD Parameters - open";
996 err_htype
= SQL_HANDLE_DBC
;
998 rc
= odbc_parse_params(pool
, params
, &connect
, &datasource
, &user
,
999 &password
, &defaultBufferSize
, &nattrs
, &attrs
,
1002 if (SQL_SUCCEEDED(rc
)) {
1003 for (i
=0 ; i
< nattrs
&& SQL_SUCCEEDED(rc
); i
++) {
1004 err_step
="SQLSetConnectAttr (from DBD Parameters)";
1005 err_htype
= SQL_HANDLE_DBC
;
1007 rc
= SQLSetConnectAttr(hdbc
, attrs
[i
], (void *) attrvals
[i
], 0);
1010 if (SQL_SUCCEEDED(rc
)) {
1014 err_step
="SQLDriverConnect";
1015 err_htype
= SQL_HANDLE_DBC
;
1017 rc
= SQLDriverConnect(hdbc
, NULL
, datasource
,
1018 (SQLSMALLINT
) strlen(datasource
),
1019 out
, sizeof(out
), &outlen
, SQL_DRIVER_NOPROMPT
);
1022 err_step
="SQLConnect";
1023 err_htype
= SQL_HANDLE_DBC
;
1025 rc
= SQLConnect(hdbc
, datasource
, (SQLSMALLINT
) strlen(datasource
),
1026 user
, (SQLSMALLINT
) strlen(user
),
1027 password
, (SQLSMALLINT
) strlen(password
));
1030 if (SQL_SUCCEEDED(rc
)) {
1031 handle
= apr_pcalloc(pool
, sizeof(apr_dbd_t
));
1032 handle
->dbname
= apr_pstrdup(pool
, datasource
);
1034 handle
->pool
= pool
;
1035 handle
->defaultBufferSize
= defaultBufferSize
;
1036 CHECK_ERROR(handle
, "SQLConnect", rc
, SQL_HANDLE_DBC
, handle
->dbc
);
1037 handle
->default_transaction_mode
= 0;
1038 SQLGetInfo(hdbc
, SQL_DEFAULT_TXN_ISOLATION
,
1039 &(handle
->default_transaction_mode
), sizeof(int), NULL
);
1040 handle
->transaction_mode
= handle
->default_transaction_mode
;
1041 SQLGetInfo(hdbc
, SQL_GETDATA_EXTENSIONS
,&(handle
->dboptions
),
1043 apr_pool_cleanup_register(pool
, handle
, odbc_close_cleanup
, apr_pool_cleanup_null
);
1048 tmp_dbc
.pool
= pool
;
1049 tmp_dbc
.dbname
= NULL
;
1050 CHECK_ERROR(&tmp_dbc
, err_step
, rc
, err_htype
, err_h
);
1052 *error
= apr_pstrdup(pool
, tmp_dbc
.lastError
);
1054 SQLFreeHandle(SQL_HANDLE_DBC
, hdbc
);
1059 /** check_conn: check status of a database connection **/
1060 static apr_status_t
odbc_check_conn(apr_pool_t
*pool
, apr_dbd_t
*handle
)
1065 rc
= SQLGetConnectAttr(handle
->dbc
, SQL_ATTR_CONNECTION_DEAD
, &isDead
,
1066 sizeof(SQLUINTEGER
), NULL
);
1067 CHECK_ERROR(handle
, "SQLGetConnectAttr (SQL_ATTR_CONNECTION_DEAD)", rc
,
1068 SQL_HANDLE_DBC
, handle
->dbc
);
1069 /* if driver cannot check connection, say so */
1070 if (rc
!= SQL_SUCCESS
)
1071 return APR_ENOTIMPL
;
1073 return (isDead
== SQL_CD_FALSE
) ? APR_SUCCESS
: APR_EGENERAL
;
1077 /** set_dbname: select database name. May be a no-op if not supported. **/
1078 static int odbc_set_dbname(apr_pool_t
* pool
, apr_dbd_t
*handle
,
1081 if (apr_strnatcmp(name
, handle
->dbname
)) {
1082 return APR_EGENERAL
; /* It's illegal to change dbname in ODBC */
1084 CHECK_ERROR(handle
, "set_dbname (no-op)", SQL_SUCCESS
, SQL_HANDLE_DBC
,
1086 return APR_SUCCESS
; /* OK if it's the same name */
1089 /** transaction: start a transaction. May be a no-op. **/
1090 static int odbc_start_transaction(apr_pool_t
*pool
, apr_dbd_t
*handle
,
1091 apr_dbd_transaction_t
**trans
)
1093 SQLRETURN rc
= SQL_SUCCESS
;
1095 if (handle
->transaction_mode
) {
1096 rc
= SQLSetConnectAttr(handle
->dbc
, SQL_ATTR_TXN_ISOLATION
, (void *)
1097 handle
->transaction_mode
, 0);
1098 CHECK_ERROR(handle
, "SQLSetConnectAttr (SQL_ATTR_TXN_ISOLATION)", rc
,
1099 SQL_HANDLE_DBC
, handle
->dbc
);
1101 if SQL_SUCCEEDED(rc
) {
1102 /* turn off autocommit for transactions */
1103 rc
= SQLSetConnectAttr(handle
->dbc
, SQL_ATTR_AUTOCOMMIT
,
1104 SQL_AUTOCOMMIT_OFF
, 0);
1105 CHECK_ERROR(handle
, "SQLSetConnectAttr (SQL_ATTR_AUTOCOMMIT)", rc
,
1106 SQL_HANDLE_DBC
, handle
->dbc
);
1108 if SQL_SUCCEEDED(rc
) {
1109 *trans
= apr_palloc(pool
, sizeof(apr_dbd_transaction_t
));
1110 (*trans
)->dbc
= handle
->dbc
;
1111 (*trans
)->apr_dbd
= handle
;
1112 handle
->can_commit
= 1;
1114 return APR_FROM_SQL_RESULT(rc
);
1118 /** end_transaction: end a transaction **/
1119 static int odbc_end_transaction(apr_dbd_transaction_t
*trans
)
1122 int action
= trans
->apr_dbd
->can_commit
? SQL_COMMIT
: SQL_ROLLBACK
;
1124 rc
= SQLEndTran(SQL_HANDLE_DBC
, trans
->dbc
, SQL_COMMIT
);
1125 CHECK_ERROR(trans
->apr_dbd
, "SQLEndTran", rc
, SQL_HANDLE_DBC
, trans
->dbc
);
1126 if SQL_SUCCEEDED(rc
) {
1127 rc
= SQLSetConnectAttr(trans
->dbc
, SQL_ATTR_AUTOCOMMIT
,
1128 (SQLPOINTER
) SQL_AUTOCOMMIT_ON
, 0);
1129 CHECK_ERROR(trans
->apr_dbd
, "SQLSetConnectAttr (SQL_ATTR_AUTOCOMMIT)",
1130 rc
, SQL_HANDLE_DBC
, trans
->dbc
);
1132 return APR_FROM_SQL_RESULT(rc
);
1135 /** query: execute an SQL statement which doesn't return a result set **/
1136 static int odbc_query(apr_dbd_t
*handle
, int *nrows
, const char *statement
)
1139 SQLHANDLE hstmt
= NULL
;
1140 size_t len
= strlen(statement
);
1142 rc
= SQLAllocHandle(SQL_HANDLE_STMT
, handle
->dbc
, &hstmt
);
1143 CHECK_ERROR(handle
, "SQLAllocHandle (STMT)", rc
, SQL_HANDLE_DBC
,
1145 if (!SQL_SUCCEEDED(rc
))
1146 return APR_FROM_SQL_RESULT(rc
);
1148 rc
= SQLExecDirect(hstmt
, (SQLCHAR
*) statement
, (SQLINTEGER
) len
);
1149 CHECK_ERROR(handle
, "SQLExecDirect", rc
, SQL_HANDLE_STMT
, hstmt
);
1151 if SQL_SUCCEEDED(rc
) {
1152 rc
= SQLRowCount(hstmt
, (SQLINTEGER
*) nrows
);
1153 CHECK_ERROR(handle
, "SQLRowCount", rc
, SQL_HANDLE_STMT
, hstmt
);
1156 SQLFreeHandle(SQL_HANDLE_STMT
, hstmt
);
1157 return APR_FROM_SQL_RESULT(rc
);
1160 /** select: execute an SQL statement which returns a result set **/
1161 static int odbc_select(apr_pool_t
*pool
, apr_dbd_t
*handle
,
1162 apr_dbd_results_t
**res
, const char *statement
,
1167 apr_dbd_prepared_t
*stmt
;
1168 size_t len
= strlen(statement
);
1170 rc
= SQLAllocHandle(SQL_HANDLE_STMT
, handle
->dbc
, &hstmt
);
1171 CHECK_ERROR(handle
, "SQLAllocHandle (STMT)", rc
, SQL_HANDLE_DBC
,
1173 if (!SQL_SUCCEEDED(rc
))
1174 return APR_FROM_SQL_RESULT(rc
);
1175 /* Prepare an apr_dbd_prepared_t for pool cleanup, even though this
1176 * is not a prepared statement. We want the same cleanup mechanism.
1178 stmt
= apr_pcalloc(pool
, sizeof(apr_dbd_prepared_t
));
1179 stmt
->apr_dbd
= handle
;
1180 stmt
->dbc
= handle
->dbc
;
1182 apr_pool_cleanup_register(pool
, stmt
, odbc_close_pstmt
, apr_pool_cleanup_null
);
1184 rc
= SQLSetStmtAttr(hstmt
, SQL_ATTR_CURSOR_SCROLLABLE
,
1185 (SQLPOINTER
) SQL_SCROLLABLE
, 0);
1186 CHECK_ERROR(handle
, "SQLSetStmtAttr (SQL_ATTR_CURSOR_SCROLLABLE)", rc
,
1187 SQL_HANDLE_STMT
, hstmt
);
1189 if SQL_SUCCEEDED(rc
) {
1190 rc
= SQLExecDirect(hstmt
, (SQLCHAR
*) statement
, (SQLINTEGER
) len
);
1191 CHECK_ERROR(handle
, "SQLExecDirect", rc
, SQL_HANDLE_STMT
, hstmt
);
1193 if SQL_SUCCEEDED(rc
) {
1194 rc
= odbc_create_results(handle
, hstmt
, pool
, random
, res
);
1195 apr_pool_cleanup_register(pool
, *res
,
1196 odbc_close_results
, apr_pool_cleanup_null
);
1198 return APR_FROM_SQL_RESULT(rc
);
1201 /** num_cols: get the number of columns in a results set **/
1202 static int odbc_num_cols(apr_dbd_results_t
*res
)
1207 /** num_tuples: get the number of rows in a results set **/
1208 static int odbc_num_tuples(apr_dbd_results_t
*res
)
1213 rc
= SQLRowCount(res
->stmt
, &nrows
);
1214 CHECK_ERROR(res
->apr_dbd
, "SQLRowCount", rc
, SQL_HANDLE_STMT
, res
->stmt
);
1215 return SQL_SUCCEEDED(rc
) ? (int) nrows
: -1;
1218 /** get_row: get a row from a result set **/
1219 static int odbc_get_row(apr_pool_t
* pool
, apr_dbd_results_t
* res
,
1220 apr_dbd_row_t
** row
, int rownum
)
1226 *row
= apr_pcalloc(pool
, sizeof(apr_dbd_row_t
));
1227 (*row
)->stmt
= res
->stmt
;
1228 (*row
)->dbc
= res
->dbc
;
1230 (*row
)->pool
= res
->pool
;
1232 /* mark all the columns as needing SQLGetData unless they are bound */
1233 for (c
= 0; c
< res
->ncols
; c
++) {
1234 if (res
->colstate
[c
] != COL_BOUND
)
1235 res
->colstate
[c
] = COL_AVAIL
;
1236 /* some drivers do not null-term zero-len CHAR data */
1237 if (res
->colptrs
[c
] )
1238 * (char *) res
->colptrs
[c
] = 0;
1241 if (res
->random
&& (rownum
> 0)) {
1242 fetchtype
= "SQLFetchScroll";
1243 rc
= SQLFetchScroll(res
->stmt
, SQL_FETCH_ABSOLUTE
, rownum
);
1246 fetchtype
= "SQLFetch";
1247 rc
= SQLFetch(res
->stmt
);
1249 CHECK_ERROR(res
->apr_dbd
, fetchtype
, rc
, SQL_HANDLE_STMT
, res
->stmt
);
1250 (*row
)->stmt
= res
->stmt
;
1251 if (!SQL_SUCCEEDED(rc
) && !res
->random
) {
1252 /* early close on any error (usually SQL_NO_DATA) if fetching
1253 * sequentially to release resources ASAP */
1254 odbc_close_results(res
);
1257 return SQL_SUCCEEDED(rc
) ? 0 : -1;
1260 /** datum_get: get a binary entry from a row **/
1261 static apr_status_t
odbc_datum_get(const apr_dbd_row_t
* row
, int col
,
1262 apr_dbd_type_e dbdtype
, void *data
)
1264 SQLSMALLINT sqltype
;
1266 int len
= sqlSizes
[dbdtype
];
1268 if (col
>= row
->res
->ncols
)
1269 return APR_EGENERAL
;
1271 if (dbdtype
< 0 || dbdtype
>= sizeof(sqlCtype
)) {
1272 data
= NULL
; /* invalid type */
1273 return APR_EGENERAL
;
1275 sqltype
= sqlCtype
[dbdtype
];
1277 /* must not memcpy a brigade, sentinals are relative to orig loc */
1278 if (IS_LOB(sqltype
))
1279 return odbc_create_bucket(row
, col
, sqltype
, data
);
1281 p
= odbc_get(row
, col
, sqltype
);
1282 if (p
== (void *) -1)
1283 return APR_EGENERAL
;
1286 return APR_ENOENT
; /* SQL NULL value */
1291 memcpy(data
, p
, len
);
1297 /** get_entry: get an entry from a row (string data) **/
1298 static const char *odbc_get_entry(const apr_dbd_row_t
* row
, int col
)
1302 if (col
>= row
->res
->ncols
)
1305 p
= odbc_get(row
, col
, SQL_C_CHAR
);
1307 if ((signed int) p
> 0)
1308 return apr_pstrdup(row
->pool
, p
); /* row pool lifetime */
1310 return p
; /* NULL or invalid (-1) */
1313 /** error: get current error message (if any) **/
1314 static const char* odbc_error(apr_dbd_t
*handle
, int errnum
)
1316 return (handle
) ? handle
->lastError
: "[dbd_odbc]No error message available";
1319 /** escape: escape a string so it is safe for use in query/select **/
1320 static const char* odbc_escape(apr_pool_t
*pool
, const char *s
,
1323 char *newstr
, *src
, *dst
, *sq
;
1326 /* return the original if there are no single-quotes */
1327 if (!(sq
= strchr(s
, '\'')))
1329 /* count the single-quotes and allocate a new buffer */
1330 for (qcount
= 1; sq
= strchr(sq
+ 1, '\''); )
1332 newstr
= apr_palloc(pool
, strlen(s
) + qcount
+ 1);
1334 /* move chars, doubling all single-quotes */
1336 for (dst
= newstr
; *src
; src
++) {
1337 if ((*dst
++ = *src
) == '\'')
1343 /** prepare: prepare a statement **/
1344 static int odbc_prepare(apr_pool_t
* pool
, apr_dbd_t
* handle
,
1345 const char *query
, const char *label
, int nargs
,
1346 int nvals
, apr_dbd_type_e
* types
,
1347 apr_dbd_prepared_t
** statement
)
1350 size_t len
= strlen(query
);
1352 *statement
= apr_pcalloc(pool
, sizeof(apr_dbd_prepared_t
));
1353 (*statement
)->dbc
= handle
->dbc
;
1354 (*statement
)->apr_dbd
= handle
;
1355 (*statement
)->nargs
= nargs
;
1356 (*statement
)->nvals
= nvals
;
1357 (*statement
)->types
=
1358 apr_pmemdup(pool
, types
, nargs
* sizeof(apr_dbd_type_e
));
1359 rc
= SQLAllocHandle(SQL_HANDLE_STMT
, handle
->dbc
, &((*statement
)->stmt
));
1360 apr_pool_cleanup_register(pool
, *statement
,
1361 odbc_close_pstmt
, apr_pool_cleanup_null
);
1362 CHECK_ERROR(handle
, "SQLAllocHandle (STMT)", rc
,
1363 SQL_HANDLE_DBC
, handle
->dbc
);
1364 rc
= SQLPrepare((*statement
)->stmt
, (SQLCHAR
*) query
, (SQLINTEGER
) len
);
1365 CHECK_ERROR(handle
, "SQLPrepare", rc
, SQL_HANDLE_STMT
,
1366 (*statement
)->stmt
);
1367 return APR_FROM_SQL_RESULT(rc
);
1370 /** pquery: query using a prepared statement + args **/
1371 static int odbc_pquery(apr_pool_t
* pool
, apr_dbd_t
* handle
, int *nrows
,
1372 apr_dbd_prepared_t
* statement
, const char **args
)
1374 SQLRETURN rc
= SQL_SUCCESS
;
1377 for (i
= argp
= 0; i
< statement
->nargs
&& SQL_SUCCEEDED(rc
); i
++) {
1378 rc
= odbc_bind_param(pool
, statement
, i
+ 1, statement
->types
[i
],
1379 &argp
, (const void **) args
, TEXTMODE
);
1381 if (SQL_SUCCEEDED(rc
)) {
1382 rc
= SQLExecute(statement
->stmt
);
1383 CHECK_ERROR(handle
, "SQLExecute", rc
, SQL_HANDLE_STMT
,
1386 if (SQL_SUCCEEDED(rc
)) {
1387 rc
= SQLRowCount(statement
->stmt
, (SQLINTEGER
*) nrows
);
1388 CHECK_ERROR(handle
, "SQLRowCount", rc
, SQL_HANDLE_STMT
,
1391 return APR_FROM_SQL_RESULT(rc
);
1394 /** pvquery: query using a prepared statement + args **/
1395 static int odbc_pvquery(apr_pool_t
* pool
, apr_dbd_t
* handle
, int *nrows
,
1396 apr_dbd_prepared_t
* statement
, va_list args
)
1398 const char **values
;
1400 values
= apr_palloc(pool
, sizeof(*values
) * statement
->nvals
);
1401 for (i
= 0; i
< statement
->nvals
; i
++)
1402 values
[i
] = va_arg(args
, const char *);
1403 return odbc_pquery(pool
, handle
, nrows
, statement
, values
);
1406 /** pselect: select using a prepared statement + args **/
1407 int odbc_pselect(apr_pool_t
* pool
, apr_dbd_t
* handle
,
1408 apr_dbd_results_t
** res
, apr_dbd_prepared_t
* statement
,
1409 int random
, const char **args
)
1411 SQLRETURN rc
= SQL_SUCCESS
;
1415 rc
= SQLSetStmtAttr(statement
->stmt
, SQL_ATTR_CURSOR_SCROLLABLE
,
1416 (SQLPOINTER
) SQL_SCROLLABLE
, 0);
1417 CHECK_ERROR(handle
, "SQLSetStmtAttr (SQL_ATTR_CURSOR_SCROLLABLE)",
1418 rc
, SQL_HANDLE_STMT
, statement
->stmt
);
1420 if (SQL_SUCCEEDED(rc
)) {
1421 for (i
= argp
= 0; i
< statement
->nargs
&& SQL_SUCCEEDED(rc
); i
++)
1422 rc
= odbc_bind_param(pool
, statement
, i
+ 1, statement
->types
[i
],
1423 &argp
, (const void **) args
, TEXTMODE
);
1425 if (SQL_SUCCEEDED(rc
)) {
1426 rc
= SQLExecute(statement
->stmt
);
1427 CHECK_ERROR(handle
, "SQLExecute", rc
, SQL_HANDLE_STMT
,
1430 if (SQL_SUCCEEDED(rc
)) {
1431 rc
= odbc_create_results(handle
, statement
->stmt
, pool
, random
, res
);
1432 apr_pool_cleanup_register(pool
, *res
,
1433 odbc_close_results
, apr_pool_cleanup_null
);
1435 return APR_FROM_SQL_RESULT(rc
);
1438 /** pvselect: select using a prepared statement + args **/
1439 static int odbc_pvselect(apr_pool_t
* pool
, apr_dbd_t
* handle
,
1440 apr_dbd_results_t
** res
,
1441 apr_dbd_prepared_t
* statement
, int random
,
1444 const char **values
;
1447 values
= apr_palloc(pool
, sizeof(*values
) * statement
->nvals
);
1448 for (i
= 0; i
< statement
->nvals
; i
++)
1449 values
[i
] = va_arg(args
, const char *);
1450 return odbc_pselect(pool
, handle
, res
, statement
, random
, values
);
1453 /** get_name: get a column title from a result set **/
1454 static const char *odbc_get_name(const apr_dbd_results_t
* res
, int col
)
1457 char buffer
[MAX_COLUMN_NAME
];
1458 SQLSMALLINT colnamelength
, coltype
, coldecimal
, colnullable
;
1459 SQLUINTEGER colsize
;
1461 if (col
>= res
->ncols
)
1462 return NULL
; /* bogus column number */
1463 if (res
->colnames
[col
] != NULL
)
1464 return res
->colnames
[col
]; /* we already retrieved it */
1465 rc
= SQLDescribeCol(res
->stmt
, col
+ 1,
1466 buffer
, sizeof(buffer
), &colnamelength
,
1467 &coltype
, &colsize
, &coldecimal
, &colnullable
);
1468 CHECK_ERROR(res
->apr_dbd
, "SQLDescribeCol", rc
,
1469 SQL_HANDLE_STMT
, res
->stmt
);
1470 res
->colnames
[col
] = apr_pstrdup(res
->pool
, buffer
);
1471 return res
->colnames
[col
];
1474 /** transaction_mode_get: get the mode of transaction **/
1475 static int odbc_transaction_mode_get(apr_dbd_transaction_t
* trans
)
1477 return (int) trans
->apr_dbd
->transaction_mode
;
1480 /** transaction_mode_set: set the mode of transaction **/
1481 static int odbc_transaction_mode_set(apr_dbd_transaction_t
* trans
, int mode
)
1485 int legal
= (SQL_TXN_READ_UNCOMMITTED
| SQL_TXN_READ_COMMITTED
1486 | SQL_TXN_REPEATABLE_READ
| SQL_TXN_SERIALIZABLE
);
1488 if ((mode
& legal
) != mode
)
1489 return APR_EGENERAL
;
1491 trans
->apr_dbd
->transaction_mode
= mode
;
1492 rc
= SQLSetConnectAttr(trans
->dbc
, SQL_ATTR_TXN_ISOLATION
,
1494 CHECK_ERROR(trans
->apr_dbd
, "SQLSetConnectAttr (SQL_ATTR_TXN_ISOLATION)",
1495 rc
, SQL_HANDLE_DBC
, trans
->dbc
);
1496 return APR_FROM_SQL_RESULT(rc
);
1499 /** pbquery: query using a prepared statement + binary args **/
1500 static int odbc_pbquery(apr_pool_t
* pool
, apr_dbd_t
* handle
, int *nrows
,
1501 apr_dbd_prepared_t
* statement
, const void **args
)
1503 SQLRETURN rc
= SQL_SUCCESS
;
1506 for (i
= argp
= 0; i
< statement
->nargs
&& SQL_SUCCEEDED(rc
); i
++)
1507 rc
= odbc_bind_param(pool
, statement
, i
+ 1, statement
->types
[i
],
1508 &argp
, args
, BINARYMODE
);
1510 if (SQL_SUCCEEDED(rc
)) {
1511 rc
= SQLExecute(statement
->stmt
);
1512 CHECK_ERROR(handle
, "SQLExecute", rc
, SQL_HANDLE_STMT
,
1515 if (SQL_SUCCEEDED(rc
)) {
1516 rc
= SQLRowCount(statement
->stmt
, (SQLINTEGER
*) nrows
);
1517 CHECK_ERROR(handle
, "SQLRowCount", rc
, SQL_HANDLE_STMT
,
1520 return APR_FROM_SQL_RESULT(rc
);
1523 /** pbselect: select using a prepared statement + binary args **/
1524 static int odbc_pbselect(apr_pool_t
* pool
, apr_dbd_t
* handle
,
1525 apr_dbd_results_t
** res
,
1526 apr_dbd_prepared_t
* statement
,
1527 int random
, const void **args
)
1529 SQLRETURN rc
= SQL_SUCCESS
;
1533 rc
= SQLSetStmtAttr(statement
->stmt
, SQL_ATTR_CURSOR_SCROLLABLE
,
1534 (SQLPOINTER
) SQL_SCROLLABLE
, 0);
1535 CHECK_ERROR(handle
, "SQLSetStmtAttr (SQL_ATTR_CURSOR_SCROLLABLE)",
1536 rc
, SQL_HANDLE_STMT
, statement
->stmt
);
1538 if (SQL_SUCCEEDED(rc
)) {
1539 for (i
= argp
= 0; i
< statement
->nargs
&& SQL_SUCCEEDED(rc
); i
++) {
1540 rc
= odbc_bind_param(pool
, statement
, i
+ 1, statement
->types
[i
],
1541 &argp
, args
, BINARYMODE
);
1544 if (SQL_SUCCEEDED(rc
)) {
1545 rc
= SQLExecute(statement
->stmt
);
1546 CHECK_ERROR(handle
, "SQLExecute", rc
, SQL_HANDLE_STMT
,
1549 if (SQL_SUCCEEDED(rc
)) {
1550 rc
= odbc_create_results(handle
, statement
->stmt
, pool
, random
, res
);
1551 apr_pool_cleanup_register(pool
, *res
,
1552 odbc_close_results
, apr_pool_cleanup_null
);
1555 return APR_FROM_SQL_RESULT(rc
);
1558 /** pvbquery: query using a prepared statement + binary args **/
1559 static int odbc_pvbquery(apr_pool_t
* pool
, apr_dbd_t
* handle
, int *nrows
,
1560 apr_dbd_prepared_t
* statement
, va_list args
)
1562 const char **values
;
1565 values
= apr_palloc(pool
, sizeof(*values
) * statement
->nvals
);
1566 for (i
= 0; i
< statement
->nvals
; i
++)
1567 values
[i
] = va_arg(args
, const char *);
1568 return odbc_pbquery(pool
, handle
, nrows
, statement
, (const void **) values
);
1571 /** pvbselect: select using a prepared statement + binary args **/
1572 static int odbc_pvbselect(apr_pool_t
* pool
, apr_dbd_t
* handle
,
1573 apr_dbd_results_t
** res
,
1574 apr_dbd_prepared_t
* statement
,
1575 int random
, va_list args
)
1577 const char **values
;
1580 values
= apr_palloc(pool
, sizeof(*values
) * statement
->nvals
);
1581 for (i
= 0; i
< statement
->nvals
; i
++)
1582 values
[i
] = va_arg(args
, const char *);
1583 return odbc_pbselect(pool
, handle
, res
, statement
, random
, (const void **) values
);
1586 APU_MODULE_DECLARE_DATA
const apr_dbd_driver_t ODBC_DRIVER_ENTRY
= {
1594 odbc_start_transaction
,
1595 odbc_end_transaction
,
1610 odbc_transaction_mode_get
,
1611 odbc_transaction_mode_set
,