Annotation of embedaddon/php/ext/pdo_odbc/odbc_stmt.c, revision 1.1.1.5
1.1 misho 1: /*
2: +----------------------------------------------------------------------+
3: | PHP Version 5 |
4: +----------------------------------------------------------------------+
1.1.1.5 ! misho 5: | Copyright (c) 1997-2014 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;
1.1.1.5 ! misho 475: unsigned long srclen = 0;
1.1 misho 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;
1.1.1.5 ! misho 554: SDWORD colsize;
! 555: SQLLEN displaysize;
1.1 misho 556:
557: rc = SQLDescribeCol(S->stmt, colno+1, S->cols[colno].colname,
558: sizeof(S->cols[colno].colname)-1, &colnamelen,
559: &S->cols[colno].coltype, &colsize, NULL, NULL);
560:
561: if (rc != SQL_SUCCESS) {
562: pdo_odbc_stmt_error("SQLDescribeCol");
563: if (rc != SQL_SUCCESS_WITH_INFO) {
564: return 0;
565: }
566: }
567:
568: rc = SQLColAttribute(S->stmt, colno+1,
569: SQL_DESC_DISPLAY_SIZE,
570: NULL, 0, NULL, &displaysize);
571:
572: if (rc != SQL_SUCCESS) {
573: pdo_odbc_stmt_error("SQLColAttribute");
574: if (rc != SQL_SUCCESS_WITH_INFO) {
575: return 0;
576: }
577: }
578: colsize = displaysize;
579:
580: col->maxlen = S->cols[colno].datalen = colsize;
581: col->namelen = colnamelen;
582: col->name = estrdup(S->cols[colno].colname);
583: S->cols[colno].is_unicode = pdo_odbc_sqltype_is_unicode(S, S->cols[colno].coltype);
584:
585: /* returning data as a string */
586: col->param_type = PDO_PARAM_STR;
587:
588: /* tell ODBC to put it straight into our buffer, but only if it
589: * isn't "long" data, and only if we haven't already bound a long
590: * column. */
591: if (colsize < 256 && !S->going_long) {
592: S->cols[colno].data = emalloc(colsize+1);
593: S->cols[colno].is_long = 0;
594:
595: rc = SQLBindCol(S->stmt, colno+1,
596: S->cols[colno].is_unicode ? SQL_C_BINARY : SQL_C_CHAR,
597: S->cols[colno].data,
598: S->cols[colno].datalen+1, &S->cols[colno].fetched_len);
599:
600: if (rc != SQL_SUCCESS) {
601: pdo_odbc_stmt_error("SQLBindCol");
602: return 0;
603: }
604: } else {
605: /* allocate a smaller buffer to keep around for smaller
606: * "long" columns */
607: S->cols[colno].data = emalloc(256);
608: S->going_long = 1;
609: S->cols[colno].is_long = 1;
610: }
611:
612: return 1;
613: }
614:
615: static int odbc_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, unsigned long *len, int *caller_frees TSRMLS_DC)
616: {
617: pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
618: pdo_odbc_column *C = &S->cols[colno];
619: unsigned long ulen;
620:
621: /* if it is a column containing "long" data, perform late binding now */
622: if (C->is_long) {
623: unsigned long used = 0;
624: char *buf;
625: RETCODE rc;
626:
627: /* fetch it into C->data, which is allocated with a length
628: * of 256 bytes; if there is more to be had, we then allocate
629: * bigger buffer for the caller to free */
630:
631: rc = SQLGetData(S->stmt, colno+1, C->is_unicode ? SQL_C_BINARY : SQL_C_CHAR, C->data,
632: 256, &C->fetched_len);
633:
634: if (rc == SQL_SUCCESS) {
635: /* all the data fit into our little buffer;
636: * jump down to the generic bound data case */
637: goto in_data;
638: }
639:
640: if (rc == SQL_SUCCESS_WITH_INFO) {
1.1.1.3 misho 641: /* this is a 'long column'
642:
643: read the column in 255 byte blocks until the end of the column is reached, reassembling those blocks
644: in order into the output buffer
645:
646: this loop has to work whether or not SQLGetData() provides the total column length.
647: calling SQLDescribeCol() or other, specifically to get the column length, then doing a single read
648: for that size would be slower except maybe for extremely long columns.*/
649: char *buf2;
650:
651: buf2 = emalloc(256);
652: buf = estrndup(C->data, 256);
653: used = 255; /* not 256; the driver NUL terminated the buffer */
654:
1.1 misho 655: do {
656: C->fetched_len = 0;
1.1.1.3 misho 657: /* read block. 256 bytes => 255 bytes are actually read, the last 1 is NULL */
658: rc = SQLGetData(S->stmt, colno+1, SQL_C_CHAR, buf2, 256, &C->fetched_len);
659:
660: /* resize output buffer and reassemble block */
661: if (rc==SQL_SUCCESS_WITH_INFO) {
662: /* point 5, in section "Retrieving Data with SQLGetData" in http://msdn.microsoft.com/en-us/library/windows/desktop/ms715441(v=vs.85).aspx
663: states that if SQL_SUCCESS_WITH_INFO, fetched_len will be > 255 (greater than buf2's size)
664: (if a driver fails to follow that and wrote less than 255 bytes to buf2, this will AV or read garbage into buf) */
665: buf = erealloc(buf, used + 255+1);
666: memcpy(buf + used, buf2, 255);
667: used = used + 255;
668: } else if (rc==SQL_SUCCESS) {
669: buf = erealloc(buf, used + C->fetched_len+1);
670: memcpy(buf + used, buf2, C->fetched_len);
671: used = used + C->fetched_len;
1.1 misho 672: } else {
1.1.1.3 misho 673: /* includes SQL_NO_DATA */
1.1 misho 674: break;
675: }
1.1.1.3 misho 676:
1.1 misho 677: } while (1);
1.1.1.3 misho 678:
679: efree(buf2);
680:
681: /* NULL terminate the buffer once, when finished, for use with the rest of PHP */
1.1 misho 682: buf[used] = '\0';
1.1.1.3 misho 683:
1.1 misho 684: *ptr = buf;
685: *caller_frees = 1;
686: *len = used;
687: if (C->is_unicode) {
688: goto unicode_conv;
689: }
690: return 1;
691: }
692:
693: /* something went caca */
694: *ptr = NULL;
695: *len = 0;
696: return 1;
697: }
698:
699: in_data:
700: /* check the indicator to ensure that the data is intact */
701: if (C->fetched_len == SQL_NULL_DATA) {
702: /* A NULL value */
703: *ptr = NULL;
704: *len = 0;
705: return 1;
706: } else if (C->fetched_len >= 0) {
707: /* it was stored perfectly */
708: *ptr = C->data;
709: *len = C->fetched_len;
710: if (C->is_unicode) {
711: goto unicode_conv;
712: }
713: return 1;
714: } else {
715: /* no data? */
716: *ptr = NULL;
717: *len = 0;
718: return 1;
719: }
720:
721: unicode_conv:
722: switch (pdo_odbc_ucs22utf8(stmt, C->is_unicode, *ptr, *len, &ulen)) {
723: case PDO_ODBC_CONV_FAIL:
724: /* oh well. They can have the binary version of it */
725: case PDO_ODBC_CONV_NOT_REQUIRED:
726: /* shouldn't happen... */
727: return 1;
728:
729: case PDO_ODBC_CONV_OK:
730: if (*caller_frees) {
731: efree(*ptr);
732: }
733: *ptr = emalloc(ulen + 1);
734: *len = ulen;
735: memcpy(*ptr, S->convbuf, ulen+1);
736: *caller_frees = 1;
737: return 1;
738: }
739: return 1;
740: }
741:
742: static int odbc_stmt_set_param(pdo_stmt_t *stmt, long attr, zval *val TSRMLS_DC)
743: {
744: SQLRETURN rc;
745: pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
746:
747: switch (attr) {
748: case PDO_ATTR_CURSOR_NAME:
749: convert_to_string(val);
750: rc = SQLSetCursorName(S->stmt, Z_STRVAL_P(val), Z_STRLEN_P(val));
751:
752: if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) {
753: return 1;
754: }
755: pdo_odbc_stmt_error("SQLSetCursorName");
756: return 0;
757:
758: case PDO_ODBC_ATTR_ASSUME_UTF8:
759: S->assume_utf8 = zval_is_true(val);
760: return 0;
761: default:
762: strcpy(S->einfo.last_err_msg, "Unknown Attribute");
763: S->einfo.what = "setAttribute";
764: strcpy(S->einfo.last_state, "IM001");
765: return -1;
766: }
767: }
768:
769: static int odbc_stmt_get_attr(pdo_stmt_t *stmt, long attr, zval *val TSRMLS_DC)
770: {
771: SQLRETURN rc;
772: pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
773:
774: switch (attr) {
775: case PDO_ATTR_CURSOR_NAME:
776: {
777: char buf[256];
778: SQLSMALLINT len = 0;
779: rc = SQLGetCursorName(S->stmt, buf, sizeof(buf), &len);
780:
781: if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) {
782: ZVAL_STRINGL(val, buf, len, 1);
783: return 1;
784: }
785: pdo_odbc_stmt_error("SQLGetCursorName");
786: return 0;
787: }
788:
789: case PDO_ODBC_ATTR_ASSUME_UTF8:
790: ZVAL_BOOL(val, S->assume_utf8 ? 1 : 0);
791: return 0;
792:
793: default:
794: strcpy(S->einfo.last_err_msg, "Unknown Attribute");
795: S->einfo.what = "getAttribute";
796: strcpy(S->einfo.last_state, "IM001");
797: return -1;
798: }
799: }
800:
801: static int odbc_stmt_next_rowset(pdo_stmt_t *stmt TSRMLS_DC)
802: {
803: SQLRETURN rc;
804: SQLSMALLINT colcount;
805: pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
806:
807: /* NOTE: can't guarantee that output or input/output parameters
808: * are set until this fella returns SQL_NO_DATA, according to
809: * MSDN ODBC docs */
810: rc = SQLMoreResults(S->stmt);
811:
812: if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
813: return 0;
814: }
815:
816: free_cols(stmt, S TSRMLS_CC);
817: /* how many columns do we have ? */
818: SQLNumResultCols(S->stmt, &colcount);
819: stmt->column_count = (int)colcount;
820: S->cols = ecalloc(colcount, sizeof(pdo_odbc_column));
821: S->going_long = 0;
822:
823: return 1;
824: }
825:
826: struct pdo_stmt_methods odbc_stmt_methods = {
827: odbc_stmt_dtor,
828: odbc_stmt_execute,
829: odbc_stmt_fetch,
830: odbc_stmt_describe,
831: odbc_stmt_get_col,
832: odbc_stmt_param_hook,
833: odbc_stmt_set_param,
834: odbc_stmt_get_attr, /* get attr */
835: NULL, /* get column meta */
836: odbc_stmt_next_rowset
837: };
838:
839: /*
840: * Local variables:
841: * tab-width: 4
842: * c-basic-offset: 4
843: * End:
844: * vim600: noet sw=4 ts=4 fdm=marker
845: * vim<600: noet sw=4 ts=4
846: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>