Annotation of embedaddon/php/ext/pdo_odbc/odbc_stmt.c, revision 1.1.1.3
1.1 misho 1: /*
2: +----------------------------------------------------------------------+
3: | PHP Version 5 |
4: +----------------------------------------------------------------------+
1.1.1.3 ! misho 5: | Copyright (c) 1997-2013 The PHP Group |
1.1 misho 6: +----------------------------------------------------------------------+
7: | This source file is subject to version 3.0 of the PHP license, |
8: | that is bundled with this package in the file LICENSE, and is |
9: | available through the world-wide-web at the following url: |
10: | http://www.php.net/license/3_0.txt. |
11: | If you did not receive a copy of the PHP license and are unable to |
12: | obtain it through the world-wide-web, please send a note to |
13: | license@php.net so we can mail you a copy immediately. |
14: +----------------------------------------------------------------------+
15: | Author: Wez Furlong <wez@php.net> |
16: +----------------------------------------------------------------------+
17: */
18:
1.1.1.2 misho 19: /* $Id$ */
1.1 misho 20:
21: #ifdef HAVE_CONFIG_H
22: #include "config.h"
23: #endif
24:
25: #include "php.h"
26: #include "php_ini.h"
27: #include "ext/standard/info.h"
28: #include "pdo/php_pdo.h"
29: #include "pdo/php_pdo_driver.h"
30: #include "php_pdo_odbc.h"
31: #include "php_pdo_odbc_int.h"
32:
33: enum pdo_odbc_conv_result {
34: PDO_ODBC_CONV_NOT_REQUIRED,
35: PDO_ODBC_CONV_OK,
36: PDO_ODBC_CONV_FAIL
37: };
38:
39: static int pdo_odbc_sqltype_is_unicode(pdo_odbc_stmt *S, SWORD sqltype)
40: {
41: if (!S->assume_utf8) return 0;
42: switch (sqltype) {
43: #ifdef SQL_WCHAR
44: case SQL_WCHAR:
45: return 1;
46: #endif
47: #ifdef SQL_WLONGVARCHAR
48: case SQL_WLONGVARCHAR:
49: return 1;
50: #endif
51: #ifdef SQL_WVARCHAR
52: case SQL_WVARCHAR:
53: return 1;
54: #endif
55: default:
56: return 0;
57: }
58: }
59:
60: static int pdo_odbc_utf82ucs2(pdo_stmt_t *stmt, int is_unicode, const char *buf,
61: unsigned long buflen, unsigned long *outlen)
62: {
63: #ifdef PHP_WIN32
64: if (is_unicode && buflen) {
65: pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
66: DWORD ret;
67:
68: ret = MultiByteToWideChar(CP_UTF8, 0, buf, buflen, NULL, 0);
69: if (ret == 0) {
70: /*printf("%s:%d %d [%d] %.*s\n", __FILE__, __LINE__, GetLastError(), buflen, buflen, buf);*/
71: return PDO_ODBC_CONV_FAIL;
72: }
73:
74: ret *= sizeof(WCHAR);
75:
76: if (S->convbufsize <= ret) {
77: S->convbufsize = ret + sizeof(WCHAR);
78: S->convbuf = erealloc(S->convbuf, S->convbufsize);
79: }
80:
81: ret = MultiByteToWideChar(CP_UTF8, 0, buf, buflen, (LPWSTR)S->convbuf, S->convbufsize / sizeof(WCHAR));
82: if (ret == 0) {
83: /*printf("%s:%d %d [%d] %.*s\n", __FILE__, __LINE__, GetLastError(), buflen, buflen, buf);*/
84: return PDO_ODBC_CONV_FAIL;
85: }
86:
87: ret *= sizeof(WCHAR);
88: *outlen = ret;
89: return PDO_ODBC_CONV_OK;
90: }
91: #endif
92: return PDO_ODBC_CONV_NOT_REQUIRED;
93: }
94:
95: static int pdo_odbc_ucs22utf8(pdo_stmt_t *stmt, int is_unicode, const char *buf,
96: unsigned long buflen, unsigned long *outlen)
97: {
98: #ifdef PHP_WIN32
99: if (is_unicode && buflen) {
100: pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
101: DWORD ret;
102:
103: ret = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)buf, buflen/sizeof(WCHAR), NULL, 0, NULL, NULL);
104: if (ret == 0) {
105: return PDO_ODBC_CONV_FAIL;
106: }
107:
108: if (S->convbufsize <= ret) {
109: S->convbufsize = ret + 1;
110: S->convbuf = erealloc(S->convbuf, S->convbufsize);
111: }
112:
113: ret = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)buf, buflen/sizeof(WCHAR), S->convbuf, S->convbufsize, NULL, NULL);
114: if (ret == 0) {
115: return PDO_ODBC_CONV_FAIL;
116: }
117:
118: *outlen = ret;
119: S->convbuf[*outlen] = '\0';
120: return PDO_ODBC_CONV_OK;
121: }
122: #endif
123: return PDO_ODBC_CONV_NOT_REQUIRED;
124: }
125:
126: static void free_cols(pdo_stmt_t *stmt, pdo_odbc_stmt *S TSRMLS_DC)
127: {
128: if (S->cols) {
129: int i;
130:
131: for (i = 0; i < stmt->column_count; i++) {
132: if (S->cols[i].data) {
133: efree(S->cols[i].data);
134: }
135: }
136: efree(S->cols);
137: S->cols = NULL;
138: }
139: }
140:
141: static int odbc_stmt_dtor(pdo_stmt_t *stmt TSRMLS_DC)
142: {
143: pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
144:
145: if (S->stmt != SQL_NULL_HANDLE) {
146: if (stmt->executed) {
147: SQLCloseCursor(S->stmt);
148: }
149: SQLFreeHandle(SQL_HANDLE_STMT, S->stmt);
150: S->stmt = SQL_NULL_HANDLE;
151: }
152:
153: free_cols(stmt, S TSRMLS_CC);
154: if (S->convbuf) {
155: efree(S->convbuf);
156: }
157: efree(S);
158:
159: return 1;
160: }
161:
162: static int odbc_stmt_execute(pdo_stmt_t *stmt TSRMLS_DC)
163: {
164: RETCODE rc;
165: pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
166: char *buf = NULL;
167: SQLLEN row_count = -1;
168:
169: if (stmt->executed) {
170: SQLCloseCursor(S->stmt);
171: }
172:
173: rc = SQLExecute(S->stmt);
174:
175: while (rc == SQL_NEED_DATA) {
176: struct pdo_bound_param_data *param;
177:
178: rc = SQLParamData(S->stmt, (SQLPOINTER*)¶m);
179: if (rc == SQL_NEED_DATA) {
180: php_stream *stm;
181: int len;
182: pdo_odbc_param *P;
183:
184: P = (pdo_odbc_param*)param->driver_data;
185: if (Z_TYPE_P(param->parameter) != IS_RESOURCE) {
186: /* they passed in a string */
187: unsigned long ulen;
188: convert_to_string(param->parameter);
189:
190: switch (pdo_odbc_utf82ucs2(stmt, P->is_unicode,
191: Z_STRVAL_P(param->parameter),
192: Z_STRLEN_P(param->parameter),
193: &ulen)) {
194: case PDO_ODBC_CONV_NOT_REQUIRED:
195: SQLPutData(S->stmt, Z_STRVAL_P(param->parameter),
196: Z_STRLEN_P(param->parameter));
197: break;
198: case PDO_ODBC_CONV_OK:
199: SQLPutData(S->stmt, S->convbuf, ulen);
200: break;
201: case PDO_ODBC_CONV_FAIL:
202: pdo_odbc_stmt_error("error converting input string");
203: SQLCloseCursor(S->stmt);
204: if (buf) {
205: efree(buf);
206: }
207: return 0;
208: }
209: continue;
210: }
211:
212: /* we assume that LOBs are binary and don't need charset
213: * conversion */
214:
215: php_stream_from_zval_no_verify(stm, ¶m->parameter);
216: if (!stm) {
217: /* shouldn't happen either */
218: pdo_odbc_stmt_error("input LOB is no longer a stream");
219: SQLCloseCursor(S->stmt);
220: if (buf) {
221: efree(buf);
222: }
223: return 0;
224: }
225:
226: /* now suck data from the stream and stick it into the database */
227: if (buf == NULL) {
228: buf = emalloc(8192);
229: }
230:
231: do {
232: len = php_stream_read(stm, buf, 8192);
233: if (len == 0) {
234: break;
235: }
236: SQLPutData(S->stmt, buf, len);
237: } while (1);
238: }
239: }
240:
241: if (buf) {
242: efree(buf);
243: }
244:
245: switch (rc) {
246: case SQL_SUCCESS:
247: break;
248: case SQL_NO_DATA_FOUND:
249: case SQL_SUCCESS_WITH_INFO:
250: pdo_odbc_stmt_error("SQLExecute");
251: break;
252:
253: default:
254: pdo_odbc_stmt_error("SQLExecute");
255: return 0;
256: }
257:
258: SQLRowCount(S->stmt, &row_count);
259: stmt->row_count = row_count;
260:
261: if (!stmt->executed) {
262: /* do first-time-only definition of bind/mapping stuff */
263: SQLSMALLINT colcount;
264:
265: /* how many columns do we have ? */
266: SQLNumResultCols(S->stmt, &colcount);
267:
268: stmt->column_count = (int)colcount;
269: S->cols = ecalloc(colcount, sizeof(pdo_odbc_column));
270: S->going_long = 0;
271: }
272:
273: return 1;
274: }
275:
276: static int odbc_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data *param,
277: enum pdo_param_event event_type TSRMLS_DC)
278: {
279: pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
280: RETCODE rc;
281: SWORD sqltype = 0, ctype = 0, scale = 0, nullable = 0;
282: UDWORD precision = 0;
283: pdo_odbc_param *P;
284:
285: /* we're only interested in parameters for prepared SQL right now */
286: if (param->is_param) {
287:
288: switch (event_type) {
289: case PDO_PARAM_EVT_FREE:
290: P = param->driver_data;
291: if (P) {
292: efree(P);
293: }
294: break;
295:
296: case PDO_PARAM_EVT_ALLOC:
297: {
298: /* figure out what we're doing */
299: switch (PDO_PARAM_TYPE(param->param_type)) {
300: case PDO_PARAM_LOB:
301: break;
302:
303: case PDO_PARAM_STMT:
304: return 0;
305:
306: default:
307: break;
308: }
309:
310: rc = SQLDescribeParam(S->stmt, (SQLUSMALLINT) param->paramno+1, &sqltype, &precision, &scale, &nullable);
311: if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
312: /* MS Access, for instance, doesn't support SQLDescribeParam,
313: * so we need to guess */
314: sqltype = PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB ?
315: SQL_LONGVARBINARY :
316: SQL_LONGVARCHAR;
317: precision = 4000;
318: scale = 5;
319: nullable = 1;
320:
321: if (param->max_value_len > 0) {
322: precision = param->max_value_len;
323: }
324: }
325: if (sqltype == SQL_BINARY || sqltype == SQL_VARBINARY || sqltype == SQL_LONGVARBINARY) {
326: ctype = SQL_C_BINARY;
327: } else {
328: ctype = SQL_C_CHAR;
329: }
330:
331: P = emalloc(sizeof(*P));
332: param->driver_data = P;
333:
334: P->len = 0; /* is re-populated each EXEC_PRE */
335: P->outbuf = NULL;
336:
337: P->is_unicode = pdo_odbc_sqltype_is_unicode(S, sqltype);
338: if (P->is_unicode) {
339: /* avoid driver auto-translation: we'll do it ourselves */
340: ctype = SQL_C_BINARY;
341: }
342:
343: if ((param->param_type & PDO_PARAM_INPUT_OUTPUT) == PDO_PARAM_INPUT_OUTPUT) {
344: P->paramtype = SQL_PARAM_INPUT_OUTPUT;
345: } else if (param->max_value_len <= 0) {
346: P->paramtype = SQL_PARAM_INPUT;
347: } else {
348: P->paramtype = SQL_PARAM_OUTPUT;
349: }
350:
351: if (P->paramtype != SQL_PARAM_INPUT) {
352: if (PDO_PARAM_TYPE(param->param_type) != PDO_PARAM_NULL) {
353: /* need an explicit buffer to hold result */
354: P->len = param->max_value_len > 0 ? param->max_value_len : precision;
355: if (P->is_unicode) {
356: P->len *= 2;
357: }
358: P->outbuf = emalloc(P->len + (P->is_unicode ? 2:1));
359: }
360: }
361:
362: if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB && P->paramtype != SQL_PARAM_INPUT) {
363: pdo_odbc_stmt_error("Can't bind a lob for output");
364: return 0;
365: }
366:
367: rc = SQLBindParameter(S->stmt, (SQLUSMALLINT) param->paramno+1,
368: P->paramtype, ctype, sqltype, precision, scale,
369: P->paramtype == SQL_PARAM_INPUT ?
370: (SQLPOINTER)param :
371: P->outbuf,
372: P->len,
373: &P->len
374: );
375:
376: if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) {
377: return 1;
378: }
379: pdo_odbc_stmt_error("SQLBindParameter");
380: return 0;
381: }
382:
383: case PDO_PARAM_EVT_EXEC_PRE:
384: P = param->driver_data;
385: if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB) {
386: if (Z_TYPE_P(param->parameter) == IS_RESOURCE) {
387: php_stream *stm;
388: php_stream_statbuf sb;
389:
390: php_stream_from_zval_no_verify(stm, ¶m->parameter);
391:
392: if (!stm) {
393: return 0;
394: }
395:
396: if (0 == php_stream_stat(stm, &sb)) {
397: if (P->outbuf) {
398: int len, amount;
399: char *ptr = P->outbuf;
400: char *end = P->outbuf + P->len;
401:
402: P->len = 0;
403: do {
404: amount = end - ptr;
405: if (amount == 0) {
406: break;
407: }
408: if (amount > 8192)
409: amount = 8192;
410: len = php_stream_read(stm, ptr, amount);
411: if (len == 0) {
412: break;
413: }
414: ptr += len;
415: P->len += len;
416: } while (1);
417:
418: } else {
419: P->len = SQL_LEN_DATA_AT_EXEC(sb.sb.st_size);
420: }
421: } else {
422: if (P->outbuf) {
423: P->len = 0;
424: } else {
425: P->len = SQL_LEN_DATA_AT_EXEC(0);
426: }
427: }
428: } else {
429: convert_to_string(param->parameter);
430: if (P->outbuf) {
431: P->len = Z_STRLEN_P(param->parameter);
432: memcpy(P->outbuf, Z_STRVAL_P(param->parameter), P->len);
433: } else {
434: P->len = SQL_LEN_DATA_AT_EXEC(Z_STRLEN_P(param->parameter));
435: }
436: }
437: } else if (Z_TYPE_P(param->parameter) == IS_NULL || PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_NULL) {
438: P->len = SQL_NULL_DATA;
439: } else {
440: convert_to_string(param->parameter);
441: if (P->outbuf) {
442: unsigned long ulen;
443: switch (pdo_odbc_utf82ucs2(stmt, P->is_unicode,
444: Z_STRVAL_P(param->parameter),
445: Z_STRLEN_P(param->parameter),
446: &ulen)) {
447: case PDO_ODBC_CONV_FAIL:
448: case PDO_ODBC_CONV_NOT_REQUIRED:
449: P->len = Z_STRLEN_P(param->parameter);
450: memcpy(P->outbuf, Z_STRVAL_P(param->parameter), P->len);
451: break;
452: case PDO_ODBC_CONV_OK:
453: P->len = ulen;
454: memcpy(P->outbuf, S->convbuf, P->len);
455: break;
456: }
457: } else {
458: P->len = SQL_LEN_DATA_AT_EXEC(Z_STRLEN_P(param->parameter));
459: }
460: }
461: return 1;
462:
463: case PDO_PARAM_EVT_EXEC_POST:
464: P = param->driver_data;
465: if (P->outbuf) {
466: if (P->outbuf) {
467: unsigned long ulen;
468: char *srcbuf;
469: unsigned long srclen;
470:
471: switch (P->len) {
472: case SQL_NULL_DATA:
473: zval_dtor(param->parameter);
474: ZVAL_NULL(param->parameter);
475: break;
476: default:
477: convert_to_string(param->parameter);
478: switch (pdo_odbc_ucs22utf8(stmt, P->is_unicode, P->outbuf, P->len, &ulen)) {
479: case PDO_ODBC_CONV_FAIL:
480: /* something fishy, but allow it to come back as binary */
481: case PDO_ODBC_CONV_NOT_REQUIRED:
482: srcbuf = P->outbuf;
483: srclen = P->len;
484: break;
485: case PDO_ODBC_CONV_OK:
486: srcbuf = S->convbuf;
487: srclen = ulen;
488: break;
489: }
490:
491: Z_STRVAL_P(param->parameter) = erealloc(Z_STRVAL_P(param->parameter), srclen+1);
492: memcpy(Z_STRVAL_P(param->parameter), srcbuf, srclen);
493: Z_STRLEN_P(param->parameter) = srclen;
494: Z_STRVAL_P(param->parameter)[srclen] = '\0';
495: }
496: }
497: }
498: return 1;
499: }
500: }
501: return 1;
502: }
503:
504: static int odbc_stmt_fetch(pdo_stmt_t *stmt,
505: enum pdo_fetch_orientation ori, long offset TSRMLS_DC)
506: {
507: RETCODE rc;
508: SQLSMALLINT odbcori;
509: pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
510:
511: switch (ori) {
512: case PDO_FETCH_ORI_NEXT: odbcori = SQL_FETCH_NEXT; break;
513: case PDO_FETCH_ORI_PRIOR: odbcori = SQL_FETCH_PRIOR; break;
514: case PDO_FETCH_ORI_FIRST: odbcori = SQL_FETCH_FIRST; break;
515: case PDO_FETCH_ORI_LAST: odbcori = SQL_FETCH_LAST; break;
516: case PDO_FETCH_ORI_ABS: odbcori = SQL_FETCH_ABSOLUTE; break;
517: case PDO_FETCH_ORI_REL: odbcori = SQL_FETCH_RELATIVE; break;
518: default:
519: strcpy(stmt->error_code, "HY106");
520: return 0;
521: }
522: rc = SQLFetchScroll(S->stmt, odbcori, offset);
523:
524: if (rc == SQL_SUCCESS) {
525: return 1;
526: }
527: if (rc == SQL_SUCCESS_WITH_INFO) {
528: pdo_odbc_stmt_error("SQLFetchScroll");
529: return 1;
530: }
531:
532: if (rc == SQL_NO_DATA) {
533: /* pdo_odbc_stmt_error("SQLFetchScroll"); */
534: return 0;
535: }
536:
537: pdo_odbc_stmt_error("SQLFetchScroll");
538:
539: return 0;
540: }
541:
542: static int odbc_stmt_describe(pdo_stmt_t *stmt, int colno TSRMLS_DC)
543: {
544: pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
545: struct pdo_column_data *col = &stmt->columns[colno];
546: zend_bool dyn = FALSE;
547: RETCODE rc;
548: SWORD colnamelen;
549: SDWORD colsize, displaysize;
550:
551: rc = SQLDescribeCol(S->stmt, colno+1, S->cols[colno].colname,
552: sizeof(S->cols[colno].colname)-1, &colnamelen,
553: &S->cols[colno].coltype, &colsize, NULL, NULL);
554:
555: if (rc != SQL_SUCCESS) {
556: pdo_odbc_stmt_error("SQLDescribeCol");
557: if (rc != SQL_SUCCESS_WITH_INFO) {
558: return 0;
559: }
560: }
561:
562: rc = SQLColAttribute(S->stmt, colno+1,
563: SQL_DESC_DISPLAY_SIZE,
564: NULL, 0, NULL, &displaysize);
565:
566: if (rc != SQL_SUCCESS) {
567: pdo_odbc_stmt_error("SQLColAttribute");
568: if (rc != SQL_SUCCESS_WITH_INFO) {
569: return 0;
570: }
571: }
572: colsize = displaysize;
573:
574: col->maxlen = S->cols[colno].datalen = colsize;
575: col->namelen = colnamelen;
576: col->name = estrdup(S->cols[colno].colname);
577: S->cols[colno].is_unicode = pdo_odbc_sqltype_is_unicode(S, S->cols[colno].coltype);
578:
579: /* returning data as a string */
580: col->param_type = PDO_PARAM_STR;
581:
582: /* tell ODBC to put it straight into our buffer, but only if it
583: * isn't "long" data, and only if we haven't already bound a long
584: * column. */
585: if (colsize < 256 && !S->going_long) {
586: S->cols[colno].data = emalloc(colsize+1);
587: S->cols[colno].is_long = 0;
588:
589: rc = SQLBindCol(S->stmt, colno+1,
590: S->cols[colno].is_unicode ? SQL_C_BINARY : SQL_C_CHAR,
591: S->cols[colno].data,
592: S->cols[colno].datalen+1, &S->cols[colno].fetched_len);
593:
594: if (rc != SQL_SUCCESS) {
595: pdo_odbc_stmt_error("SQLBindCol");
596: return 0;
597: }
598: } else {
599: /* allocate a smaller buffer to keep around for smaller
600: * "long" columns */
601: S->cols[colno].data = emalloc(256);
602: S->going_long = 1;
603: S->cols[colno].is_long = 1;
604: }
605:
606: return 1;
607: }
608:
609: static int odbc_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, unsigned long *len, int *caller_frees TSRMLS_DC)
610: {
611: pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
612: pdo_odbc_column *C = &S->cols[colno];
613: unsigned long ulen;
614:
615: /* if it is a column containing "long" data, perform late binding now */
616: if (C->is_long) {
617: unsigned long alloced = 4096;
618: unsigned long used = 0;
619: char *buf;
620: RETCODE rc;
621:
622: /* fetch it into C->data, which is allocated with a length
623: * of 256 bytes; if there is more to be had, we then allocate
624: * bigger buffer for the caller to free */
625:
626: rc = SQLGetData(S->stmt, colno+1, C->is_unicode ? SQL_C_BINARY : SQL_C_CHAR, C->data,
627: 256, &C->fetched_len);
628:
629: if (rc == SQL_SUCCESS) {
630: /* all the data fit into our little buffer;
631: * jump down to the generic bound data case */
632: goto in_data;
633: }
634:
635: if (rc == SQL_SUCCESS_WITH_INFO) {
1.1.1.3 ! misho 636: /* this is a 'long column'
! 637:
! 638: read the column in 255 byte blocks until the end of the column is reached, reassembling those blocks
! 639: in order into the output buffer
! 640:
! 641: this loop has to work whether or not SQLGetData() provides the total column length.
! 642: calling SQLDescribeCol() or other, specifically to get the column length, then doing a single read
! 643: for that size would be slower except maybe for extremely long columns.*/
! 644: char *buf2;
! 645:
! 646: buf2 = emalloc(256);
! 647: buf = estrndup(C->data, 256);
! 648: used = 255; /* not 256; the driver NUL terminated the buffer */
! 649:
1.1 misho 650: do {
651: C->fetched_len = 0;
1.1.1.3 ! misho 652: /* read block. 256 bytes => 255 bytes are actually read, the last 1 is NULL */
! 653: rc = SQLGetData(S->stmt, colno+1, SQL_C_CHAR, buf2, 256, &C->fetched_len);
! 654:
! 655: /* resize output buffer and reassemble block */
! 656: if (rc==SQL_SUCCESS_WITH_INFO) {
! 657: /* point 5, in section "Retrieving Data with SQLGetData" in http://msdn.microsoft.com/en-us/library/windows/desktop/ms715441(v=vs.85).aspx
! 658: states that if SQL_SUCCESS_WITH_INFO, fetched_len will be > 255 (greater than buf2's size)
! 659: (if a driver fails to follow that and wrote less than 255 bytes to buf2, this will AV or read garbage into buf) */
! 660: buf = erealloc(buf, used + 255+1);
! 661: memcpy(buf + used, buf2, 255);
! 662: used = used + 255;
! 663: } else if (rc==SQL_SUCCESS) {
! 664: buf = erealloc(buf, used + C->fetched_len+1);
! 665: memcpy(buf + used, buf2, C->fetched_len);
! 666: used = used + C->fetched_len;
1.1 misho 667: } else {
1.1.1.3 ! misho 668: /* includes SQL_NO_DATA */
1.1 misho 669: break;
670: }
1.1.1.3 ! misho 671:
1.1 misho 672: } while (1);
1.1.1.3 ! misho 673:
! 674: efree(buf2);
! 675:
! 676: /* NULL terminate the buffer once, when finished, for use with the rest of PHP */
1.1 misho 677: buf[used] = '\0';
1.1.1.3 ! misho 678:
1.1 misho 679: *ptr = buf;
680: *caller_frees = 1;
681: *len = used;
682: if (C->is_unicode) {
683: goto unicode_conv;
684: }
685: return 1;
686: }
687:
688: /* something went caca */
689: *ptr = NULL;
690: *len = 0;
691: return 1;
692: }
693:
694: in_data:
695: /* check the indicator to ensure that the data is intact */
696: if (C->fetched_len == SQL_NULL_DATA) {
697: /* A NULL value */
698: *ptr = NULL;
699: *len = 0;
700: return 1;
701: } else if (C->fetched_len >= 0) {
702: /* it was stored perfectly */
703: *ptr = C->data;
704: *len = C->fetched_len;
705: if (C->is_unicode) {
706: goto unicode_conv;
707: }
708: return 1;
709: } else {
710: /* no data? */
711: *ptr = NULL;
712: *len = 0;
713: return 1;
714: }
715:
716: unicode_conv:
717: switch (pdo_odbc_ucs22utf8(stmt, C->is_unicode, *ptr, *len, &ulen)) {
718: case PDO_ODBC_CONV_FAIL:
719: /* oh well. They can have the binary version of it */
720: case PDO_ODBC_CONV_NOT_REQUIRED:
721: /* shouldn't happen... */
722: return 1;
723:
724: case PDO_ODBC_CONV_OK:
725: if (*caller_frees) {
726: efree(*ptr);
727: }
728: *ptr = emalloc(ulen + 1);
729: *len = ulen;
730: memcpy(*ptr, S->convbuf, ulen+1);
731: *caller_frees = 1;
732: return 1;
733: }
734: return 1;
735: }
736:
737: static int odbc_stmt_set_param(pdo_stmt_t *stmt, long attr, zval *val TSRMLS_DC)
738: {
739: SQLRETURN rc;
740: pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
741:
742: switch (attr) {
743: case PDO_ATTR_CURSOR_NAME:
744: convert_to_string(val);
745: rc = SQLSetCursorName(S->stmt, Z_STRVAL_P(val), Z_STRLEN_P(val));
746:
747: if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) {
748: return 1;
749: }
750: pdo_odbc_stmt_error("SQLSetCursorName");
751: return 0;
752:
753: case PDO_ODBC_ATTR_ASSUME_UTF8:
754: S->assume_utf8 = zval_is_true(val);
755: return 0;
756: default:
757: strcpy(S->einfo.last_err_msg, "Unknown Attribute");
758: S->einfo.what = "setAttribute";
759: strcpy(S->einfo.last_state, "IM001");
760: return -1;
761: }
762: }
763:
764: static int odbc_stmt_get_attr(pdo_stmt_t *stmt, long attr, zval *val TSRMLS_DC)
765: {
766: SQLRETURN rc;
767: pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
768:
769: switch (attr) {
770: case PDO_ATTR_CURSOR_NAME:
771: {
772: char buf[256];
773: SQLSMALLINT len = 0;
774: rc = SQLGetCursorName(S->stmt, buf, sizeof(buf), &len);
775:
776: if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) {
777: ZVAL_STRINGL(val, buf, len, 1);
778: return 1;
779: }
780: pdo_odbc_stmt_error("SQLGetCursorName");
781: return 0;
782: }
783:
784: case PDO_ODBC_ATTR_ASSUME_UTF8:
785: ZVAL_BOOL(val, S->assume_utf8 ? 1 : 0);
786: return 0;
787:
788: default:
789: strcpy(S->einfo.last_err_msg, "Unknown Attribute");
790: S->einfo.what = "getAttribute";
791: strcpy(S->einfo.last_state, "IM001");
792: return -1;
793: }
794: }
795:
796: static int odbc_stmt_next_rowset(pdo_stmt_t *stmt TSRMLS_DC)
797: {
798: SQLRETURN rc;
799: SQLSMALLINT colcount;
800: pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
801:
802: /* NOTE: can't guarantee that output or input/output parameters
803: * are set until this fella returns SQL_NO_DATA, according to
804: * MSDN ODBC docs */
805: rc = SQLMoreResults(S->stmt);
806:
807: if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
808: return 0;
809: }
810:
811: free_cols(stmt, S TSRMLS_CC);
812: /* how many columns do we have ? */
813: SQLNumResultCols(S->stmt, &colcount);
814: stmt->column_count = (int)colcount;
815: S->cols = ecalloc(colcount, sizeof(pdo_odbc_column));
816: S->going_long = 0;
817:
818: return 1;
819: }
820:
821: struct pdo_stmt_methods odbc_stmt_methods = {
822: odbc_stmt_dtor,
823: odbc_stmt_execute,
824: odbc_stmt_fetch,
825: odbc_stmt_describe,
826: odbc_stmt_get_col,
827: odbc_stmt_param_hook,
828: odbc_stmt_set_param,
829: odbc_stmt_get_attr, /* get attr */
830: NULL, /* get column meta */
831: odbc_stmt_next_rowset
832: };
833:
834: /*
835: * Local variables:
836: * tab-width: 4
837: * c-basic-offset: 4
838: * End:
839: * vim600: noet sw=4 ts=4 fdm=marker
840: * vim<600: noet sw=4 ts=4
841: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>