1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 5 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2014 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$ */
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
pdo_odbc_sqltype_is_unicode(pdo_odbc_stmt * S,SWORD sqltype)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
pdo_odbc_utf82ucs2(pdo_stmt_t * stmt,int is_unicode,const char * buf,unsigned long buflen,unsigned long * outlen)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
pdo_odbc_ucs22utf8(pdo_stmt_t * stmt,int is_unicode,const char * buf,unsigned long buflen,unsigned long * outlen)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
free_cols(pdo_stmt_t * stmt,pdo_odbc_stmt * S TSRMLS_DC)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
odbc_stmt_dtor(pdo_stmt_t * stmt TSRMLS_DC)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
odbc_stmt_execute(pdo_stmt_t * stmt TSRMLS_DC)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
odbc_stmt_param_hook(pdo_stmt_t * stmt,struct pdo_bound_param_data * param,enum pdo_param_event event_type TSRMLS_DC)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_FETCH_PRE:
290 case PDO_PARAM_EVT_FETCH_POST:
291 case PDO_PARAM_EVT_NORMALIZE:
292 /* Do nothing */
293 break;
294
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 = 0;
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
odbc_stmt_fetch(pdo_stmt_t * stmt,enum pdo_fetch_orientation ori,long offset TSRMLS_DC)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
odbc_stmt_describe(pdo_stmt_t * stmt,int colno TSRMLS_DC)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;
555 SQLLEN displaysize;
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
odbc_stmt_get_col(pdo_stmt_t * stmt,int colno,char ** ptr,unsigned long * len,int * caller_frees TSRMLS_DC)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) {
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
655 do {
656 C->fetched_len = 0;
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;
672 } else {
673 /* includes SQL_NO_DATA */
674 break;
675 }
676
677 } while (1);
678
679 efree(buf2);
680
681 /* NULL terminate the buffer once, when finished, for use with the rest of PHP */
682 buf[used] = '\0';
683
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
odbc_stmt_set_param(pdo_stmt_t * stmt,long attr,zval * val TSRMLS_DC)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
odbc_stmt_get_attr(pdo_stmt_t * stmt,long attr,zval * val TSRMLS_DC)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
odbc_stmt_next_rowset(pdo_stmt_t * stmt TSRMLS_DC)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 */
847