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