Annotation of embedaddon/php/ext/pdo_odbc/odbc_stmt.c, revision 1.1.1.4
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) {
1.1.1.4 ! misho 289: case PDO_PARAM_EVT_FETCH_PRE:
! 290: case PDO_PARAM_EVT_FETCH_POST:
! 291: case PDO_PARAM_EVT_NORMALIZE:
! 292: /* Do nothing */
! 293: break;
! 294:
1.1 misho 295: case PDO_PARAM_EVT_FREE:
296: P = param->driver_data;
297: if (P) {
298: efree(P);
299: }
300: break;
301:
302: case PDO_PARAM_EVT_ALLOC:
303: {
304: /* figure out what we're doing */
305: switch (PDO_PARAM_TYPE(param->param_type)) {
306: case PDO_PARAM_LOB:
307: break;
308:
309: case PDO_PARAM_STMT:
310: return 0;
311:
312: default:
313: break;
314: }
315:
316: rc = SQLDescribeParam(S->stmt, (SQLUSMALLINT) param->paramno+1, &sqltype, &precision, &scale, &nullable);
317: if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
318: /* MS Access, for instance, doesn't support SQLDescribeParam,
319: * so we need to guess */
320: sqltype = PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB ?
321: SQL_LONGVARBINARY :
322: SQL_LONGVARCHAR;
323: precision = 4000;
324: scale = 5;
325: nullable = 1;
326:
327: if (param->max_value_len > 0) {
328: precision = param->max_value_len;
329: }
330: }
331: if (sqltype == SQL_BINARY || sqltype == SQL_VARBINARY || sqltype == SQL_LONGVARBINARY) {
332: ctype = SQL_C_BINARY;
333: } else {
334: ctype = SQL_C_CHAR;
335: }
336:
337: P = emalloc(sizeof(*P));
338: param->driver_data = P;
339:
340: P->len = 0; /* is re-populated each EXEC_PRE */
341: P->outbuf = NULL;
342:
343: P->is_unicode = pdo_odbc_sqltype_is_unicode(S, sqltype);
344: if (P->is_unicode) {
345: /* avoid driver auto-translation: we'll do it ourselves */
346: ctype = SQL_C_BINARY;
347: }
348:
349: if ((param->param_type & PDO_PARAM_INPUT_OUTPUT) == PDO_PARAM_INPUT_OUTPUT) {
350: P->paramtype = SQL_PARAM_INPUT_OUTPUT;
351: } else if (param->max_value_len <= 0) {
352: P->paramtype = SQL_PARAM_INPUT;
353: } else {
354: P->paramtype = SQL_PARAM_OUTPUT;
355: }
356:
357: if (P->paramtype != SQL_PARAM_INPUT) {
358: if (PDO_PARAM_TYPE(param->param_type) != PDO_PARAM_NULL) {
359: /* need an explicit buffer to hold result */
360: P->len = param->max_value_len > 0 ? param->max_value_len : precision;
361: if (P->is_unicode) {
362: P->len *= 2;
363: }
364: P->outbuf = emalloc(P->len + (P->is_unicode ? 2:1));
365: }
366: }
367:
368: if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB && P->paramtype != SQL_PARAM_INPUT) {
369: pdo_odbc_stmt_error("Can't bind a lob for output");
370: return 0;
371: }
372:
373: rc = SQLBindParameter(S->stmt, (SQLUSMALLINT) param->paramno+1,
374: P->paramtype, ctype, sqltype, precision, scale,
375: P->paramtype == SQL_PARAM_INPUT ?
376: (SQLPOINTER)param :
377: P->outbuf,
378: P->len,
379: &P->len
380: );
381:
382: if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) {
383: return 1;
384: }
385: pdo_odbc_stmt_error("SQLBindParameter");
386: return 0;
387: }
388:
389: case PDO_PARAM_EVT_EXEC_PRE:
390: P = param->driver_data;
391: if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB) {
392: if (Z_TYPE_P(param->parameter) == IS_RESOURCE) {
393: php_stream *stm;
394: php_stream_statbuf sb;
395:
396: php_stream_from_zval_no_verify(stm, ¶m->parameter);
397:
398: if (!stm) {
399: return 0;
400: }
401:
402: if (0 == php_stream_stat(stm, &sb)) {
403: if (P->outbuf) {
404: int len, amount;
405: char *ptr = P->outbuf;
406: char *end = P->outbuf + P->len;
407:
408: P->len = 0;
409: do {
410: amount = end - ptr;
411: if (amount == 0) {
412: break;
413: }
414: if (amount > 8192)
415: amount = 8192;
416: len = php_stream_read(stm, ptr, amount);
417: if (len == 0) {
418: break;
419: }
420: ptr += len;
421: P->len += len;
422: } while (1);
423:
424: } else {
425: P->len = SQL_LEN_DATA_AT_EXEC(sb.sb.st_size);
426: }
427: } else {
428: if (P->outbuf) {
429: P->len = 0;
430: } else {
431: P->len = SQL_LEN_DATA_AT_EXEC(0);
432: }
433: }
434: } else {
435: convert_to_string(param->parameter);
436: if (P->outbuf) {
437: P->len = Z_STRLEN_P(param->parameter);
438: memcpy(P->outbuf, Z_STRVAL_P(param->parameter), P->len);
439: } else {
440: P->len = SQL_LEN_DATA_AT_EXEC(Z_STRLEN_P(param->parameter));
441: }
442: }
443: } else if (Z_TYPE_P(param->parameter) == IS_NULL || PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_NULL) {
444: P->len = SQL_NULL_DATA;
445: } else {
446: convert_to_string(param->parameter);
447: if (P->outbuf) {
448: unsigned long ulen;
449: switch (pdo_odbc_utf82ucs2(stmt, P->is_unicode,
450: Z_STRVAL_P(param->parameter),
451: Z_STRLEN_P(param->parameter),
452: &ulen)) {
453: case PDO_ODBC_CONV_FAIL:
454: case PDO_ODBC_CONV_NOT_REQUIRED:
455: P->len = Z_STRLEN_P(param->parameter);
456: memcpy(P->outbuf, Z_STRVAL_P(param->parameter), P->len);
457: break;
458: case PDO_ODBC_CONV_OK:
459: P->len = ulen;
460: memcpy(P->outbuf, S->convbuf, P->len);
461: break;
462: }
463: } else {
464: P->len = SQL_LEN_DATA_AT_EXEC(Z_STRLEN_P(param->parameter));
465: }
466: }
467: return 1;
468:
469: case PDO_PARAM_EVT_EXEC_POST:
470: P = param->driver_data;
471: if (P->outbuf) {
472: if (P->outbuf) {
473: unsigned long ulen;
474: char *srcbuf;
475: unsigned long srclen;
476:
477: switch (P->len) {
478: case SQL_NULL_DATA:
479: zval_dtor(param->parameter);
480: ZVAL_NULL(param->parameter);
481: break;
482: default:
483: convert_to_string(param->parameter);
484: switch (pdo_odbc_ucs22utf8(stmt, P->is_unicode, P->outbuf, P->len, &ulen)) {
485: case PDO_ODBC_CONV_FAIL:
486: /* something fishy, but allow it to come back as binary */
487: case PDO_ODBC_CONV_NOT_REQUIRED:
488: srcbuf = P->outbuf;
489: srclen = P->len;
490: break;
491: case PDO_ODBC_CONV_OK:
492: srcbuf = S->convbuf;
493: srclen = ulen;
494: break;
495: }
496:
497: Z_STRVAL_P(param->parameter) = erealloc(Z_STRVAL_P(param->parameter), srclen+1);
498: memcpy(Z_STRVAL_P(param->parameter), srcbuf, srclen);
499: Z_STRLEN_P(param->parameter) = srclen;
500: Z_STRVAL_P(param->parameter)[srclen] = '\0';
501: }
502: }
503: }
504: return 1;
505: }
506: }
507: return 1;
508: }
509:
510: static int odbc_stmt_fetch(pdo_stmt_t *stmt,
511: enum pdo_fetch_orientation ori, long offset TSRMLS_DC)
512: {
513: RETCODE rc;
514: SQLSMALLINT odbcori;
515: pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
516:
517: switch (ori) {
518: case PDO_FETCH_ORI_NEXT: odbcori = SQL_FETCH_NEXT; break;
519: case PDO_FETCH_ORI_PRIOR: odbcori = SQL_FETCH_PRIOR; break;
520: case PDO_FETCH_ORI_FIRST: odbcori = SQL_FETCH_FIRST; break;
521: case PDO_FETCH_ORI_LAST: odbcori = SQL_FETCH_LAST; break;
522: case PDO_FETCH_ORI_ABS: odbcori = SQL_FETCH_ABSOLUTE; break;
523: case PDO_FETCH_ORI_REL: odbcori = SQL_FETCH_RELATIVE; break;
524: default:
525: strcpy(stmt->error_code, "HY106");
526: return 0;
527: }
528: rc = SQLFetchScroll(S->stmt, odbcori, offset);
529:
530: if (rc == SQL_SUCCESS) {
531: return 1;
532: }
533: if (rc == SQL_SUCCESS_WITH_INFO) {
534: pdo_odbc_stmt_error("SQLFetchScroll");
535: return 1;
536: }
537:
538: if (rc == SQL_NO_DATA) {
539: /* pdo_odbc_stmt_error("SQLFetchScroll"); */
540: return 0;
541: }
542:
543: pdo_odbc_stmt_error("SQLFetchScroll");
544:
545: return 0;
546: }
547:
548: static int odbc_stmt_describe(pdo_stmt_t *stmt, int colno TSRMLS_DC)
549: {
550: pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
551: struct pdo_column_data *col = &stmt->columns[colno];
552: RETCODE rc;
553: SWORD colnamelen;
554: SDWORD colsize, displaysize;
555:
556: rc = SQLDescribeCol(S->stmt, colno+1, S->cols[colno].colname,
557: sizeof(S->cols[colno].colname)-1, &colnamelen,
558: &S->cols[colno].coltype, &colsize, NULL, NULL);
559:
560: if (rc != SQL_SUCCESS) {
561: pdo_odbc_stmt_error("SQLDescribeCol");
562: if (rc != SQL_SUCCESS_WITH_INFO) {
563: return 0;
564: }
565: }
566:
567: rc = SQLColAttribute(S->stmt, colno+1,
568: SQL_DESC_DISPLAY_SIZE,
569: NULL, 0, NULL, &displaysize);
570:
571: if (rc != SQL_SUCCESS) {
572: pdo_odbc_stmt_error("SQLColAttribute");
573: if (rc != SQL_SUCCESS_WITH_INFO) {
574: return 0;
575: }
576: }
577: colsize = displaysize;
578:
579: col->maxlen = S->cols[colno].datalen = colsize;
580: col->namelen = colnamelen;
581: col->name = estrdup(S->cols[colno].colname);
582: S->cols[colno].is_unicode = pdo_odbc_sqltype_is_unicode(S, S->cols[colno].coltype);
583:
584: /* returning data as a string */
585: col->param_type = PDO_PARAM_STR;
586:
587: /* tell ODBC to put it straight into our buffer, but only if it
588: * isn't "long" data, and only if we haven't already bound a long
589: * column. */
590: if (colsize < 256 && !S->going_long) {
591: S->cols[colno].data = emalloc(colsize+1);
592: S->cols[colno].is_long = 0;
593:
594: rc = SQLBindCol(S->stmt, colno+1,
595: S->cols[colno].is_unicode ? SQL_C_BINARY : SQL_C_CHAR,
596: S->cols[colno].data,
597: S->cols[colno].datalen+1, &S->cols[colno].fetched_len);
598:
599: if (rc != SQL_SUCCESS) {
600: pdo_odbc_stmt_error("SQLBindCol");
601: return 0;
602: }
603: } else {
604: /* allocate a smaller buffer to keep around for smaller
605: * "long" columns */
606: S->cols[colno].data = emalloc(256);
607: S->going_long = 1;
608: S->cols[colno].is_long = 1;
609: }
610:
611: return 1;
612: }
613:
614: static int odbc_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, unsigned long *len, int *caller_frees TSRMLS_DC)
615: {
616: pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
617: pdo_odbc_column *C = &S->cols[colno];
618: unsigned long ulen;
619:
620: /* if it is a column containing "long" data, perform late binding now */
621: if (C->is_long) {
622: unsigned long used = 0;
623: char *buf;
624: RETCODE rc;
625:
626: /* fetch it into C->data, which is allocated with a length
627: * of 256 bytes; if there is more to be had, we then allocate
628: * bigger buffer for the caller to free */
629:
630: rc = SQLGetData(S->stmt, colno+1, C->is_unicode ? SQL_C_BINARY : SQL_C_CHAR, C->data,
631: 256, &C->fetched_len);
632:
633: if (rc == SQL_SUCCESS) {
634: /* all the data fit into our little buffer;
635: * jump down to the generic bound data case */
636: goto in_data;
637: }
638:
639: if (rc == SQL_SUCCESS_WITH_INFO) {
1.1.1.3 misho 640: /* this is a 'long column'
641:
642: read the column in 255 byte blocks until the end of the column is reached, reassembling those blocks
643: in order into the output buffer
644:
645: this loop has to work whether or not SQLGetData() provides the total column length.
646: calling SQLDescribeCol() or other, specifically to get the column length, then doing a single read
647: for that size would be slower except maybe for extremely long columns.*/
648: char *buf2;
649:
650: buf2 = emalloc(256);
651: buf = estrndup(C->data, 256);
652: used = 255; /* not 256; the driver NUL terminated the buffer */
653:
1.1 misho 654: do {
655: C->fetched_len = 0;
1.1.1.3 misho 656: /* read block. 256 bytes => 255 bytes are actually read, the last 1 is NULL */
657: rc = SQLGetData(S->stmt, colno+1, SQL_C_CHAR, buf2, 256, &C->fetched_len);
658:
659: /* resize output buffer and reassemble block */
660: if (rc==SQL_SUCCESS_WITH_INFO) {
661: /* point 5, in section "Retrieving Data with SQLGetData" in http://msdn.microsoft.com/en-us/library/windows/desktop/ms715441(v=vs.85).aspx
662: states that if SQL_SUCCESS_WITH_INFO, fetched_len will be > 255 (greater than buf2's size)
663: (if a driver fails to follow that and wrote less than 255 bytes to buf2, this will AV or read garbage into buf) */
664: buf = erealloc(buf, used + 255+1);
665: memcpy(buf + used, buf2, 255);
666: used = used + 255;
667: } else if (rc==SQL_SUCCESS) {
668: buf = erealloc(buf, used + C->fetched_len+1);
669: memcpy(buf + used, buf2, C->fetched_len);
670: used = used + C->fetched_len;
1.1 misho 671: } else {
1.1.1.3 misho 672: /* includes SQL_NO_DATA */
1.1 misho 673: break;
674: }
1.1.1.3 misho 675:
1.1 misho 676: } while (1);
1.1.1.3 misho 677:
678: efree(buf2);
679:
680: /* NULL terminate the buffer once, when finished, for use with the rest of PHP */
1.1 misho 681: buf[used] = '\0';
1.1.1.3 misho 682:
1.1 misho 683: *ptr = buf;
684: *caller_frees = 1;
685: *len = used;
686: if (C->is_unicode) {
687: goto unicode_conv;
688: }
689: return 1;
690: }
691:
692: /* something went caca */
693: *ptr = NULL;
694: *len = 0;
695: return 1;
696: }
697:
698: in_data:
699: /* check the indicator to ensure that the data is intact */
700: if (C->fetched_len == SQL_NULL_DATA) {
701: /* A NULL value */
702: *ptr = NULL;
703: *len = 0;
704: return 1;
705: } else if (C->fetched_len >= 0) {
706: /* it was stored perfectly */
707: *ptr = C->data;
708: *len = C->fetched_len;
709: if (C->is_unicode) {
710: goto unicode_conv;
711: }
712: return 1;
713: } else {
714: /* no data? */
715: *ptr = NULL;
716: *len = 0;
717: return 1;
718: }
719:
720: unicode_conv:
721: switch (pdo_odbc_ucs22utf8(stmt, C->is_unicode, *ptr, *len, &ulen)) {
722: case PDO_ODBC_CONV_FAIL:
723: /* oh well. They can have the binary version of it */
724: case PDO_ODBC_CONV_NOT_REQUIRED:
725: /* shouldn't happen... */
726: return 1;
727:
728: case PDO_ODBC_CONV_OK:
729: if (*caller_frees) {
730: efree(*ptr);
731: }
732: *ptr = emalloc(ulen + 1);
733: *len = ulen;
734: memcpy(*ptr, S->convbuf, ulen+1);
735: *caller_frees = 1;
736: return 1;
737: }
738: return 1;
739: }
740:
741: static int odbc_stmt_set_param(pdo_stmt_t *stmt, long attr, zval *val TSRMLS_DC)
742: {
743: SQLRETURN rc;
744: pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
745:
746: switch (attr) {
747: case PDO_ATTR_CURSOR_NAME:
748: convert_to_string(val);
749: rc = SQLSetCursorName(S->stmt, Z_STRVAL_P(val), Z_STRLEN_P(val));
750:
751: if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) {
752: return 1;
753: }
754: pdo_odbc_stmt_error("SQLSetCursorName");
755: return 0;
756:
757: case PDO_ODBC_ATTR_ASSUME_UTF8:
758: S->assume_utf8 = zval_is_true(val);
759: return 0;
760: default:
761: strcpy(S->einfo.last_err_msg, "Unknown Attribute");
762: S->einfo.what = "setAttribute";
763: strcpy(S->einfo.last_state, "IM001");
764: return -1;
765: }
766: }
767:
768: static int odbc_stmt_get_attr(pdo_stmt_t *stmt, long attr, zval *val TSRMLS_DC)
769: {
770: SQLRETURN rc;
771: pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
772:
773: switch (attr) {
774: case PDO_ATTR_CURSOR_NAME:
775: {
776: char buf[256];
777: SQLSMALLINT len = 0;
778: rc = SQLGetCursorName(S->stmt, buf, sizeof(buf), &len);
779:
780: if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) {
781: ZVAL_STRINGL(val, buf, len, 1);
782: return 1;
783: }
784: pdo_odbc_stmt_error("SQLGetCursorName");
785: return 0;
786: }
787:
788: case PDO_ODBC_ATTR_ASSUME_UTF8:
789: ZVAL_BOOL(val, S->assume_utf8 ? 1 : 0);
790: return 0;
791:
792: default:
793: strcpy(S->einfo.last_err_msg, "Unknown Attribute");
794: S->einfo.what = "getAttribute";
795: strcpy(S->einfo.last_state, "IM001");
796: return -1;
797: }
798: }
799:
800: static int odbc_stmt_next_rowset(pdo_stmt_t *stmt TSRMLS_DC)
801: {
802: SQLRETURN rc;
803: SQLSMALLINT colcount;
804: pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
805:
806: /* NOTE: can't guarantee that output or input/output parameters
807: * are set until this fella returns SQL_NO_DATA, according to
808: * MSDN ODBC docs */
809: rc = SQLMoreResults(S->stmt);
810:
811: if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
812: return 0;
813: }
814:
815: free_cols(stmt, S TSRMLS_CC);
816: /* how many columns do we have ? */
817: SQLNumResultCols(S->stmt, &colcount);
818: stmt->column_count = (int)colcount;
819: S->cols = ecalloc(colcount, sizeof(pdo_odbc_column));
820: S->going_long = 0;
821:
822: return 1;
823: }
824:
825: struct pdo_stmt_methods odbc_stmt_methods = {
826: odbc_stmt_dtor,
827: odbc_stmt_execute,
828: odbc_stmt_fetch,
829: odbc_stmt_describe,
830: odbc_stmt_get_col,
831: odbc_stmt_param_hook,
832: odbc_stmt_set_param,
833: odbc_stmt_get_attr, /* get attr */
834: NULL, /* get column meta */
835: odbc_stmt_next_rowset
836: };
837:
838: /*
839: * Local variables:
840: * tab-width: 4
841: * c-basic-offset: 4
842: * End:
843: * vim600: noet sw=4 ts=4 fdm=marker
844: * vim<600: noet sw=4 ts=4
845: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>