1/* 2 +----------------------------------------------------------------------+ 3 | PHP Version 5 | 4 +----------------------------------------------------------------------+ 5 | Copyright (c) 1997-2013 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 33enum pdo_odbc_conv_result { 34 PDO_ODBC_CONV_NOT_REQUIRED, 35 PDO_ODBC_CONV_OK, 36 PDO_ODBC_CONV_FAIL 37}; 38 39static 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 60static 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 95static 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 126static 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 141static 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 162static 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 276static 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 504static 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 542static 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 609static 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 /* this is a 'long column' 637 638 read the column in 255 byte blocks until the end of the column is reached, reassembling those blocks 639 in order into the output buffer 640 641 this loop has to work whether or not SQLGetData() provides the total column length. 642 calling SQLDescribeCol() or other, specifically to get the column length, then doing a single read 643 for that size would be slower except maybe for extremely long columns.*/ 644 char *buf2; 645 646 buf2 = emalloc(256); 647 buf = estrndup(C->data, 256); 648 used = 255; /* not 256; the driver NUL terminated the buffer */ 649 650 do { 651 C->fetched_len = 0; 652 /* read block. 256 bytes => 255 bytes are actually read, the last 1 is NULL */ 653 rc = SQLGetData(S->stmt, colno+1, SQL_C_CHAR, buf2, 256, &C->fetched_len); 654 655 /* resize output buffer and reassemble block */ 656 if (rc==SQL_SUCCESS_WITH_INFO) { 657 /* point 5, in section "Retrieving Data with SQLGetData" in http://msdn.microsoft.com/en-us/library/windows/desktop/ms715441(v=vs.85).aspx 658 states that if SQL_SUCCESS_WITH_INFO, fetched_len will be > 255 (greater than buf2's size) 659 (if a driver fails to follow that and wrote less than 255 bytes to buf2, this will AV or read garbage into buf) */ 660 buf = erealloc(buf, used + 255+1); 661 memcpy(buf + used, buf2, 255); 662 used = used + 255; 663 } else if (rc==SQL_SUCCESS) { 664 buf = erealloc(buf, used + C->fetched_len+1); 665 memcpy(buf + used, buf2, C->fetched_len); 666 used = used + C->fetched_len; 667 } else { 668 /* includes SQL_NO_DATA */ 669 break; 670 } 671 672 } while (1); 673 674 efree(buf2); 675 676 /* NULL terminate the buffer once, when finished, for use with the rest of PHP */ 677 buf[used] = '\0'; 678 679 *ptr = buf; 680 *caller_frees = 1; 681 *len = used; 682 if (C->is_unicode) { 683 goto unicode_conv; 684 } 685 return 1; 686 } 687 688 /* something went caca */ 689 *ptr = NULL; 690 *len = 0; 691 return 1; 692 } 693 694in_data: 695 /* check the indicator to ensure that the data is intact */ 696 if (C->fetched_len == SQL_NULL_DATA) { 697 /* A NULL value */ 698 *ptr = NULL; 699 *len = 0; 700 return 1; 701 } else if (C->fetched_len >= 0) { 702 /* it was stored perfectly */ 703 *ptr = C->data; 704 *len = C->fetched_len; 705 if (C->is_unicode) { 706 goto unicode_conv; 707 } 708 return 1; 709 } else { 710 /* no data? */ 711 *ptr = NULL; 712 *len = 0; 713 return 1; 714 } 715 716 unicode_conv: 717 switch (pdo_odbc_ucs22utf8(stmt, C->is_unicode, *ptr, *len, &ulen)) { 718 case PDO_ODBC_CONV_FAIL: 719 /* oh well. They can have the binary version of it */ 720 case PDO_ODBC_CONV_NOT_REQUIRED: 721 /* shouldn't happen... */ 722 return 1; 723 724 case PDO_ODBC_CONV_OK: 725 if (*caller_frees) { 726 efree(*ptr); 727 } 728 *ptr = emalloc(ulen + 1); 729 *len = ulen; 730 memcpy(*ptr, S->convbuf, ulen+1); 731 *caller_frees = 1; 732 return 1; 733 } 734 return 1; 735} 736 737static int odbc_stmt_set_param(pdo_stmt_t *stmt, long attr, zval *val TSRMLS_DC) 738{ 739 SQLRETURN rc; 740 pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data; 741 742 switch (attr) { 743 case PDO_ATTR_CURSOR_NAME: 744 convert_to_string(val); 745 rc = SQLSetCursorName(S->stmt, Z_STRVAL_P(val), Z_STRLEN_P(val)); 746 747 if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) { 748 return 1; 749 } 750 pdo_odbc_stmt_error("SQLSetCursorName"); 751 return 0; 752 753 case PDO_ODBC_ATTR_ASSUME_UTF8: 754 S->assume_utf8 = zval_is_true(val); 755 return 0; 756 default: 757 strcpy(S->einfo.last_err_msg, "Unknown Attribute"); 758 S->einfo.what = "setAttribute"; 759 strcpy(S->einfo.last_state, "IM001"); 760 return -1; 761 } 762} 763 764static int odbc_stmt_get_attr(pdo_stmt_t *stmt, long attr, zval *val TSRMLS_DC) 765{ 766 SQLRETURN rc; 767 pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data; 768 769 switch (attr) { 770 case PDO_ATTR_CURSOR_NAME: 771 { 772 char buf[256]; 773 SQLSMALLINT len = 0; 774 rc = SQLGetCursorName(S->stmt, buf, sizeof(buf), &len); 775 776 if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) { 777 ZVAL_STRINGL(val, buf, len, 1); 778 return 1; 779 } 780 pdo_odbc_stmt_error("SQLGetCursorName"); 781 return 0; 782 } 783 784 case PDO_ODBC_ATTR_ASSUME_UTF8: 785 ZVAL_BOOL(val, S->assume_utf8 ? 1 : 0); 786 return 0; 787 788 default: 789 strcpy(S->einfo.last_err_msg, "Unknown Attribute"); 790 S->einfo.what = "getAttribute"; 791 strcpy(S->einfo.last_state, "IM001"); 792 return -1; 793 } 794} 795 796static int odbc_stmt_next_rowset(pdo_stmt_t *stmt TSRMLS_DC) 797{ 798 SQLRETURN rc; 799 SQLSMALLINT colcount; 800 pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data; 801 802 /* NOTE: can't guarantee that output or input/output parameters 803 * are set until this fella returns SQL_NO_DATA, according to 804 * MSDN ODBC docs */ 805 rc = SQLMoreResults(S->stmt); 806 807 if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { 808 return 0; 809 } 810 811 free_cols(stmt, S TSRMLS_CC); 812 /* how many columns do we have ? */ 813 SQLNumResultCols(S->stmt, &colcount); 814 stmt->column_count = (int)colcount; 815 S->cols = ecalloc(colcount, sizeof(pdo_odbc_column)); 816 S->going_long = 0; 817 818 return 1; 819} 820 821struct pdo_stmt_methods odbc_stmt_methods = { 822 odbc_stmt_dtor, 823 odbc_stmt_execute, 824 odbc_stmt_fetch, 825 odbc_stmt_describe, 826 odbc_stmt_get_col, 827 odbc_stmt_param_hook, 828 odbc_stmt_set_param, 829 odbc_stmt_get_attr, /* get attr */ 830 NULL, /* get column meta */ 831 odbc_stmt_next_rowset 832}; 833 834/* 835 * Local variables: 836 * tab-width: 4 837 * c-basic-offset: 4 838 * End: 839 * vim600: noet sw=4 ts=4 fdm=marker 840 * vim<600: noet sw=4 ts=4 841 */ 842