Annotation of embedaddon/php/ext/pdo_odbc/odbc_stmt.c, revision 1.1.1.1
1.1 misho 1: /*
2: +----------------------------------------------------------------------+
3: | PHP Version 5 |
4: +----------------------------------------------------------------------+
5: | Copyright (c) 1997-2012 The PHP Group |
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:
19: /* $Id: odbc_stmt.c 321634 2012-01-01 13:15:04Z felipe $ */
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) {
636: /* promote up to a bigger buffer */
637:
638: if (C->fetched_len != SQL_NO_TOTAL) {
639: /* use size suggested by the driver, if it knows it */
640: alloced = C->fetched_len + 1;
641: }
642:
643: buf = emalloc(alloced);
644: memcpy(buf, C->data, 256);
645: used = 255; /* not 256; the driver NUL terminated the buffer */
646:
647: do {
648: C->fetched_len = 0;
649: rc = SQLGetData(S->stmt, colno+1, SQL_C_CHAR,
650: buf + used, alloced - used,
651: &C->fetched_len);
652:
653: if (rc == SQL_NO_DATA) {
654: /* we got the lot */
655: break;
656: } else if (rc != SQL_SUCCESS) {
657: pdo_odbc_stmt_error("SQLGetData");
658: if (rc != SQL_SUCCESS_WITH_INFO) {
659: break;
660: }
661: }
662:
663: if (C->fetched_len == SQL_NO_TOTAL) {
664: used += alloced - used;
665: } else {
666: used += C->fetched_len;
667: }
668:
669: if (rc == SQL_SUCCESS) {
670: /* this was the final fetch */
671: break;
672: }
673:
674: /* we need to fetch another chunk; resize the
675: * buffer */
676: alloced *= 2;
677: buf = erealloc(buf, alloced);
678: } while (1);
679:
680: /* size down */
681: if (used < alloced - 1024) {
682: alloced = used+1;
683: buf = erealloc(buf, used+1);
684: }
685: buf[used] = '\0';
686: *ptr = buf;
687: *caller_frees = 1;
688: *len = used;
689: if (C->is_unicode) {
690: goto unicode_conv;
691: }
692: return 1;
693: }
694:
695: /* something went caca */
696: *ptr = NULL;
697: *len = 0;
698: return 1;
699: }
700:
701: in_data:
702: /* check the indicator to ensure that the data is intact */
703: if (C->fetched_len == SQL_NULL_DATA) {
704: /* A NULL value */
705: *ptr = NULL;
706: *len = 0;
707: return 1;
708: } else if (C->fetched_len >= 0) {
709: /* it was stored perfectly */
710: *ptr = C->data;
711: *len = C->fetched_len;
712: if (C->is_unicode) {
713: goto unicode_conv;
714: }
715: return 1;
716: } else {
717: /* no data? */
718: *ptr = NULL;
719: *len = 0;
720: return 1;
721: }
722:
723: unicode_conv:
724: switch (pdo_odbc_ucs22utf8(stmt, C->is_unicode, *ptr, *len, &ulen)) {
725: case PDO_ODBC_CONV_FAIL:
726: /* oh well. They can have the binary version of it */
727: case PDO_ODBC_CONV_NOT_REQUIRED:
728: /* shouldn't happen... */
729: return 1;
730:
731: case PDO_ODBC_CONV_OK:
732: if (*caller_frees) {
733: efree(*ptr);
734: }
735: *ptr = emalloc(ulen + 1);
736: *len = ulen;
737: memcpy(*ptr, S->convbuf, ulen+1);
738: *caller_frees = 1;
739: return 1;
740: }
741: return 1;
742: }
743:
744: static int odbc_stmt_set_param(pdo_stmt_t *stmt, long attr, zval *val TSRMLS_DC)
745: {
746: SQLRETURN rc;
747: pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
748:
749: switch (attr) {
750: case PDO_ATTR_CURSOR_NAME:
751: convert_to_string(val);
752: rc = SQLSetCursorName(S->stmt, Z_STRVAL_P(val), Z_STRLEN_P(val));
753:
754: if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) {
755: return 1;
756: }
757: pdo_odbc_stmt_error("SQLSetCursorName");
758: return 0;
759:
760: case PDO_ODBC_ATTR_ASSUME_UTF8:
761: S->assume_utf8 = zval_is_true(val);
762: return 0;
763: default:
764: strcpy(S->einfo.last_err_msg, "Unknown Attribute");
765: S->einfo.what = "setAttribute";
766: strcpy(S->einfo.last_state, "IM001");
767: return -1;
768: }
769: }
770:
771: static int odbc_stmt_get_attr(pdo_stmt_t *stmt, long attr, zval *val TSRMLS_DC)
772: {
773: SQLRETURN rc;
774: pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
775:
776: switch (attr) {
777: case PDO_ATTR_CURSOR_NAME:
778: {
779: char buf[256];
780: SQLSMALLINT len = 0;
781: rc = SQLGetCursorName(S->stmt, buf, sizeof(buf), &len);
782:
783: if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) {
784: ZVAL_STRINGL(val, buf, len, 1);
785: return 1;
786: }
787: pdo_odbc_stmt_error("SQLGetCursorName");
788: return 0;
789: }
790:
791: case PDO_ODBC_ATTR_ASSUME_UTF8:
792: ZVAL_BOOL(val, S->assume_utf8 ? 1 : 0);
793: return 0;
794:
795: default:
796: strcpy(S->einfo.last_err_msg, "Unknown Attribute");
797: S->einfo.what = "getAttribute";
798: strcpy(S->einfo.last_state, "IM001");
799: return -1;
800: }
801: }
802:
803: static int odbc_stmt_next_rowset(pdo_stmt_t *stmt TSRMLS_DC)
804: {
805: SQLRETURN rc;
806: SQLSMALLINT colcount;
807: pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
808:
809: /* NOTE: can't guarantee that output or input/output parameters
810: * are set until this fella returns SQL_NO_DATA, according to
811: * MSDN ODBC docs */
812: rc = SQLMoreResults(S->stmt);
813:
814: if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
815: return 0;
816: }
817:
818: free_cols(stmt, S TSRMLS_CC);
819: /* how many columns do we have ? */
820: SQLNumResultCols(S->stmt, &colcount);
821: stmt->column_count = (int)colcount;
822: S->cols = ecalloc(colcount, sizeof(pdo_odbc_column));
823: S->going_long = 0;
824:
825: return 1;
826: }
827:
828: struct pdo_stmt_methods odbc_stmt_methods = {
829: odbc_stmt_dtor,
830: odbc_stmt_execute,
831: odbc_stmt_fetch,
832: odbc_stmt_describe,
833: odbc_stmt_get_col,
834: odbc_stmt_param_hook,
835: odbc_stmt_set_param,
836: odbc_stmt_get_attr, /* get attr */
837: NULL, /* get column meta */
838: odbc_stmt_next_rowset
839: };
840:
841: /*
842: * Local variables:
843: * tab-width: 4
844: * c-basic-offset: 4
845: * End:
846: * vim600: noet sw=4 ts=4 fdm=marker
847: * vim<600: noet sw=4 ts=4
848: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>