root/ext/pdo_odbc/odbc_stmt.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pdo_odbc_sqltype_is_unicode
  2. pdo_odbc_utf82ucs2
  3. pdo_odbc_ucs22utf8
  4. free_cols
  5. odbc_stmt_dtor
  6. odbc_stmt_execute
  7. odbc_stmt_param_hook
  8. odbc_stmt_fetch
  9. odbc_stmt_describe
  10. odbc_stmt_get_col
  11. odbc_stmt_set_param
  12. odbc_stmt_get_attr
  13. odbc_stmt_next_rowset

   1 /*
   2   +----------------------------------------------------------------------+
   3   | PHP Version 7                                                        |
   4   +----------------------------------------------------------------------+
   5   | Copyright (c) 1997-2016 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 
  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         zend_ulong buflen, zend_ulong *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         zend_ulong buflen, zend_ulong *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)
 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)
 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);
 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)
 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*)&param);
 179                 if (rc == SQL_NEED_DATA) {
 180                         php_stream *stm;
 181                         int len;
 182                         pdo_odbc_param *P;
 183                         zval *parameter;
 184 
 185                         P = (pdo_odbc_param*)param->driver_data;
 186                         if (Z_ISREF(param->parameter)) {
 187                                 parameter = Z_REFVAL(param->parameter);
 188                         } else {
 189                                 parameter = &param->parameter;
 190                         }
 191                         if (Z_TYPE_P(parameter) != IS_RESOURCE) {
 192                                 /* they passed in a string */
 193                                 zend_ulong ulen;
 194                                 convert_to_string(parameter);
 195 
 196                                 switch (pdo_odbc_utf82ucs2(stmt, P->is_unicode,
 197                                                         Z_STRVAL_P(parameter),
 198                                                         Z_STRLEN_P(parameter),
 199                                                         &ulen)) {
 200                                         case PDO_ODBC_CONV_NOT_REQUIRED:
 201                                                 SQLPutData(S->stmt, Z_STRVAL_P(parameter),
 202                                                         Z_STRLEN_P(parameter));
 203                                                 break;
 204                                         case PDO_ODBC_CONV_OK:
 205                                                 SQLPutData(S->stmt, S->convbuf, ulen);
 206                                                 break;
 207                                         case PDO_ODBC_CONV_FAIL:
 208                                                 pdo_odbc_stmt_error("error converting input string");
 209                                                 SQLCloseCursor(S->stmt);
 210                                                 if (buf) {
 211                                                         efree(buf);
 212                                                 }
 213                                                 return 0;
 214                                 }
 215                                 continue;
 216                         }
 217 
 218                         /* we assume that LOBs are binary and don't need charset
 219                          * conversion */
 220 
 221                         php_stream_from_zval_no_verify(stm, parameter);
 222                         if (!stm) {
 223                                 /* shouldn't happen either */
 224                                 pdo_odbc_stmt_error("input LOB is no longer a stream");
 225                                 SQLCloseCursor(S->stmt);
 226                                 if (buf) {
 227                                         efree(buf);
 228                                 }
 229                                 return 0;
 230                         }
 231 
 232                         /* now suck data from the stream and stick it into the database */
 233                         if (buf == NULL) {
 234                                 buf = emalloc(8192);
 235                         }
 236 
 237                         do {
 238                                 len = php_stream_read(stm, buf, 8192);
 239                                 if (len == 0) {
 240                                         break;
 241                                 }
 242                                 SQLPutData(S->stmt, buf, len);
 243                         } while (1);
 244                 }
 245         }
 246 
 247         if (buf) {
 248                 efree(buf);
 249         }
 250 
 251         switch (rc) {
 252                 case SQL_SUCCESS:
 253                         break;
 254                 case SQL_NO_DATA_FOUND:
 255                 case SQL_SUCCESS_WITH_INFO:
 256                         pdo_odbc_stmt_error("SQLExecute");
 257                         break;
 258 
 259                 default:
 260                         pdo_odbc_stmt_error("SQLExecute");
 261                         return 0;
 262         }
 263 
 264         SQLRowCount(S->stmt, &row_count);
 265         stmt->row_count = row_count;
 266 
 267         if (!stmt->executed) {
 268                 /* do first-time-only definition of bind/mapping stuff */
 269                 SQLSMALLINT colcount;
 270 
 271                 /* how many columns do we have ? */
 272                 SQLNumResultCols(S->stmt, &colcount);
 273 
 274                 stmt->column_count = (int)colcount;
 275                 S->cols = ecalloc(colcount, sizeof(pdo_odbc_column));
 276                 S->going_long = 0;
 277         }
 278 
 279         return 1;
 280 }
 281 
 282 static int odbc_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data *param,
 283                 enum pdo_param_event event_type)
 284 {
 285         pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
 286         RETCODE rc;
 287         SWORD sqltype = 0, ctype = 0, scale = 0, nullable = 0;
 288         SQLULEN precision = 0;
 289         pdo_odbc_param *P;
 290         zval *parameter;
 291 
 292         /* we're only interested in parameters for prepared SQL right now */
 293         if (param->is_param) {
 294 
 295                 switch (event_type) {
 296                         case PDO_PARAM_EVT_FETCH_PRE:
 297                         case PDO_PARAM_EVT_FETCH_POST:
 298                         case PDO_PARAM_EVT_NORMALIZE:
 299                                 /* Do nothing */
 300                                 break;
 301 
 302                         case PDO_PARAM_EVT_FREE:
 303                                 P = param->driver_data;
 304                                 if (P) {
 305                                         efree(P);
 306                                 }
 307                                 break;
 308 
 309                         case PDO_PARAM_EVT_ALLOC:
 310                         {
 311                                 /* figure out what we're doing */
 312                                 switch (PDO_PARAM_TYPE(param->param_type)) {
 313                                         case PDO_PARAM_LOB:
 314                                                 break;
 315 
 316                                         case PDO_PARAM_STMT:
 317                                                 return 0;
 318 
 319                                         default:
 320                                                 break;
 321                                 }
 322 
 323                                 rc = SQLDescribeParam(S->stmt, (SQLUSMALLINT) param->paramno+1, &sqltype, &precision, &scale, &nullable);
 324                                 if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
 325                                         /* MS Access, for instance, doesn't support SQLDescribeParam,
 326                                          * so we need to guess */
 327                                         sqltype = PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB ?
 328                                                                         SQL_LONGVARBINARY :
 329                                                                         SQL_LONGVARCHAR;
 330                                         precision = 4000;
 331                                         scale = 5;
 332                                         nullable = 1;
 333 
 334                                         if (param->max_value_len > 0) {
 335                                                 precision = param->max_value_len;
 336                                         }
 337                                 }
 338                                 if (sqltype == SQL_BINARY || sqltype == SQL_VARBINARY || sqltype == SQL_LONGVARBINARY) {
 339                                         ctype = SQL_C_BINARY;
 340                                 } else {
 341                                         ctype = SQL_C_CHAR;
 342                                 }
 343 
 344                                 P = emalloc(sizeof(*P));
 345                                 param->driver_data = P;
 346 
 347                                 P->len = 0; /* is re-populated each EXEC_PRE */
 348                                 P->outbuf = NULL;
 349 
 350                                 P->is_unicode = pdo_odbc_sqltype_is_unicode(S, sqltype);
 351                                 if (P->is_unicode) {
 352                                         /* avoid driver auto-translation: we'll do it ourselves */
 353                                         ctype = SQL_C_BINARY;
 354                                 }
 355 
 356                                 if ((param->param_type & PDO_PARAM_INPUT_OUTPUT) == PDO_PARAM_INPUT_OUTPUT) {
 357                                         P->paramtype = SQL_PARAM_INPUT_OUTPUT;
 358                                 } else if (param->max_value_len <= 0) {
 359                                         P->paramtype = SQL_PARAM_INPUT;
 360                                 } else {
 361                                         P->paramtype = SQL_PARAM_OUTPUT;
 362                                 }
 363 
 364                                 if (P->paramtype != SQL_PARAM_INPUT) {
 365                                         if (PDO_PARAM_TYPE(param->param_type) != PDO_PARAM_NULL) {
 366                                                 /* need an explicit buffer to hold result */
 367                                                 P->len = param->max_value_len > 0 ? param->max_value_len : precision;
 368                                                 if (P->is_unicode) {
 369                                                         P->len *= 2;
 370                                                 }
 371                                                 P->outbuf = emalloc(P->len + (P->is_unicode ? 2:1));
 372                                         }
 373                                 }
 374 
 375                                 if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB && P->paramtype != SQL_PARAM_INPUT) {
 376                                         pdo_odbc_stmt_error("Can't bind a lob for output");
 377                                         return 0;
 378                                 }
 379 
 380                                 rc = SQLBindParameter(S->stmt, (SQLUSMALLINT) param->paramno+1,
 381                                                 P->paramtype, ctype, sqltype, precision, scale,
 382                                                 P->paramtype == SQL_PARAM_INPUT ?
 383                                                         (SQLPOINTER)param :
 384                                                         P->outbuf,
 385                                                 P->len,
 386                                                 &P->len
 387                                                 );
 388 
 389                                 if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) {
 390                                         return 1;
 391                                 }
 392                                 pdo_odbc_stmt_error("SQLBindParameter");
 393                                 return 0;
 394                         }
 395 
 396                         case PDO_PARAM_EVT_EXEC_PRE:
 397                                 P = param->driver_data;
 398                                 if (!Z_ISREF(param->parameter)) {
 399                                         parameter = &param->parameter;
 400                                 } else {
 401                                         parameter = Z_REFVAL(param->parameter);
 402                                 }
 403 
 404                                 if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB) {
 405                                         if (Z_TYPE_P(parameter) == IS_RESOURCE) {
 406                                                 php_stream *stm;
 407                                                 php_stream_statbuf sb;
 408 
 409                                                 php_stream_from_zval_no_verify(stm, parameter);
 410 
 411                                                 if (!stm) {
 412                                                         return 0;
 413                                                 }
 414 
 415                                                 if (0 == php_stream_stat(stm, &sb)) {
 416                                                         if (P->outbuf) {
 417                                                                 int len, amount;
 418                                                                 char *ptr = P->outbuf;
 419                                                                 char *end = P->outbuf + P->len;
 420 
 421                                                                 P->len = 0;
 422                                                                 do {
 423                                                                         amount = end - ptr;
 424                                                                         if (amount == 0) {
 425                                                                                 break;
 426                                                                         }
 427                                                                         if (amount > 8192)
 428                                                                                 amount = 8192;
 429                                                                         len = php_stream_read(stm, ptr, amount);
 430                                                                         if (len == 0) {
 431                                                                                 break;
 432                                                                         }
 433                                                                         ptr += len;
 434                                                                         P->len += len;
 435                                                                 } while (1);
 436 
 437                                                         } else {
 438                                                                 P->len = SQL_LEN_DATA_AT_EXEC(sb.sb.st_size);
 439                                                         }
 440                                                 } else {
 441                                                         if (P->outbuf) {
 442                                                                 P->len = 0;
 443                                                         } else {
 444                                                                 P->len = SQL_LEN_DATA_AT_EXEC(0);
 445                                                         }
 446                                                 }
 447                                         } else {
 448                                                 convert_to_string(parameter);
 449                                                 if (P->outbuf) {
 450                                                         P->len = Z_STRLEN_P(parameter);
 451                                                         memcpy(P->outbuf, Z_STRVAL_P(parameter), P->len);
 452                                                 } else {
 453                                                         P->len = SQL_LEN_DATA_AT_EXEC(Z_STRLEN_P(parameter));
 454                                                 }
 455                                         }
 456                                 } else if (Z_TYPE_P(parameter) == IS_NULL || PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_NULL) {
 457                                         P->len = SQL_NULL_DATA;
 458                                 } else {
 459                                         convert_to_string(parameter);
 460                                         if (P->outbuf) {
 461                                                 zend_ulong ulen;
 462                                                 switch (pdo_odbc_utf82ucs2(stmt, P->is_unicode,
 463                                                                 Z_STRVAL_P(parameter),
 464                                                                 Z_STRLEN_P(parameter),
 465                                                                 &ulen)) {
 466                                                         case PDO_ODBC_CONV_FAIL:
 467                                                         case PDO_ODBC_CONV_NOT_REQUIRED:
 468                                                                 P->len = Z_STRLEN_P(parameter);
 469                                                                 memcpy(P->outbuf, Z_STRVAL_P(parameter), P->len);
 470                                                                 break;
 471                                                         case PDO_ODBC_CONV_OK:
 472                                                                 P->len = ulen;
 473                                                                 memcpy(P->outbuf, S->convbuf, P->len);
 474                                                                 break;
 475                                                 }
 476                                         } else {
 477                                                 P->len = SQL_LEN_DATA_AT_EXEC(Z_STRLEN_P(parameter));
 478                                         }
 479                                 }
 480                                 return 1;
 481 
 482                         case PDO_PARAM_EVT_EXEC_POST:
 483                                 P = param->driver_data;
 484 
 485                                 if (P->outbuf) {
 486                                         zend_ulong ulen;
 487                                         char *srcbuf;
 488                                         zend_ulong srclen = 0;
 489 
 490                                         if (Z_ISREF(param->parameter)) {
 491                                                 parameter = Z_REFVAL(param->parameter);
 492                                         } else {
 493                                                 parameter = &param->parameter;
 494                                         }
 495                                         zval_ptr_dtor(parameter);
 496                                         ZVAL_NULL(parameter);
 497 
 498                                         switch (P->len) {
 499                                                 case SQL_NULL_DATA:
 500                                                         break;
 501                                                 default:
 502                                                         switch (pdo_odbc_ucs22utf8(stmt, P->is_unicode, P->outbuf, P->len, &ulen)) {
 503                                                                 case PDO_ODBC_CONV_FAIL:
 504                                                                         /* something fishy, but allow it to come back as binary */
 505                                                                 case PDO_ODBC_CONV_NOT_REQUIRED:
 506                                                                         srcbuf = P->outbuf;
 507                                                                         srclen = P->len;
 508                                                                         break;
 509                                                                 case PDO_ODBC_CONV_OK:
 510                                                                         srcbuf = S->convbuf;
 511                                                                         srclen = ulen;
 512                                                                         break;
 513                                                         }
 514 
 515                                                         ZVAL_NEW_STR(parameter, zend_string_alloc(srclen, 0));
 516                                                         memcpy(Z_STRVAL_P(parameter), srcbuf, srclen);
 517                                                         Z_STRVAL_P(parameter)[Z_STRLEN_P(parameter)] = '\0';
 518                                         }
 519                                 }
 520                                 return 1;
 521                 }
 522         }
 523         return 1;
 524 }
 525 
 526 static int odbc_stmt_fetch(pdo_stmt_t *stmt,
 527         enum pdo_fetch_orientation ori, zend_long offset)
 528 {
 529         RETCODE rc;
 530         SQLSMALLINT odbcori;
 531         pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
 532 
 533         switch (ori) {
 534                 case PDO_FETCH_ORI_NEXT:        odbcori = SQL_FETCH_NEXT; break;
 535                 case PDO_FETCH_ORI_PRIOR:       odbcori = SQL_FETCH_PRIOR; break;
 536                 case PDO_FETCH_ORI_FIRST:       odbcori = SQL_FETCH_FIRST; break;
 537                 case PDO_FETCH_ORI_LAST:        odbcori = SQL_FETCH_LAST; break;
 538                 case PDO_FETCH_ORI_ABS:         odbcori = SQL_FETCH_ABSOLUTE; break;
 539                 case PDO_FETCH_ORI_REL:         odbcori = SQL_FETCH_RELATIVE; break;
 540                 default:
 541                         strcpy(stmt->error_code, "HY106");
 542                         return 0;
 543         }
 544         rc = SQLFetchScroll(S->stmt, odbcori, offset);
 545 
 546         if (rc == SQL_SUCCESS) {
 547                 return 1;
 548         }
 549         if (rc == SQL_SUCCESS_WITH_INFO) {
 550                 pdo_odbc_stmt_error("SQLFetchScroll");
 551                 return 1;
 552         }
 553 
 554         if (rc == SQL_NO_DATA) {
 555                 /* pdo_odbc_stmt_error("SQLFetchScroll"); */
 556                 return 0;
 557         }
 558 
 559         pdo_odbc_stmt_error("SQLFetchScroll");
 560 
 561         return 0;
 562 }
 563 
 564 static int odbc_stmt_describe(pdo_stmt_t *stmt, int colno)
 565 {
 566         pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
 567         struct pdo_column_data *col = &stmt->columns[colno];
 568         RETCODE rc;
 569         SWORD   colnamelen;
 570         SQLULEN colsize;
 571         SQLLEN displaysize;
 572 
 573         rc = SQLDescribeCol(S->stmt, colno+1, S->cols[colno].colname,
 574                         sizeof(S->cols[colno].colname)-1, &colnamelen,
 575                         &S->cols[colno].coltype, &colsize, NULL, NULL);
 576 
 577         if (rc != SQL_SUCCESS) {
 578                 pdo_odbc_stmt_error("SQLDescribeCol");
 579                 if (rc != SQL_SUCCESS_WITH_INFO) {
 580                         return 0;
 581                 }
 582         }
 583 
 584         rc = SQLColAttribute(S->stmt, colno+1,
 585                         SQL_DESC_DISPLAY_SIZE,
 586                         NULL, 0, NULL, &displaysize);
 587 
 588         if (rc != SQL_SUCCESS) {
 589                 pdo_odbc_stmt_error("SQLColAttribute");
 590                 if (rc != SQL_SUCCESS_WITH_INFO) {
 591                         return 0;
 592                 }
 593         }
 594         colsize = displaysize;
 595 
 596         col->maxlen = S->cols[colno].datalen = colsize;
 597         col->name = zend_string_init(S->cols[colno].colname, colnamelen, 0);
 598         S->cols[colno].is_unicode = pdo_odbc_sqltype_is_unicode(S, S->cols[colno].coltype);
 599 
 600         /* returning data as a string */
 601         col->param_type = PDO_PARAM_STR;
 602 
 603         /* tell ODBC to put it straight into our buffer, but only if it
 604          * isn't "long" data, and only if we haven't already bound a long
 605          * column. */
 606         if (colsize < 256 && !S->going_long) {
 607                 S->cols[colno].data = emalloc(colsize+1);
 608                 S->cols[colno].is_long = 0;
 609 
 610                 rc = SQLBindCol(S->stmt, colno+1,
 611                         S->cols[colno].is_unicode ? SQL_C_BINARY : SQL_C_CHAR,
 612                         S->cols[colno].data,
 613                         S->cols[colno].datalen+1, &S->cols[colno].fetched_len);
 614 
 615                 if (rc != SQL_SUCCESS) {
 616                         pdo_odbc_stmt_error("SQLBindCol");
 617                         return 0;
 618                 }
 619         } else {
 620                 /* allocate a smaller buffer to keep around for smaller
 621                  * "long" columns */
 622                 S->cols[colno].data = emalloc(256);
 623                 S->going_long = 1;
 624                 S->cols[colno].is_long = 1;
 625         }
 626 
 627         return 1;
 628 }
 629 
 630 static int odbc_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, zend_ulong *len, int *caller_frees)
 631 {
 632         pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
 633         pdo_odbc_column *C = &S->cols[colno];
 634         zend_ulong ulen;
 635 
 636         /* if it is a column containing "long" data, perform late binding now */
 637         if (C->is_long) {
 638                 zend_ulong used = 0;
 639                 char *buf;
 640                 RETCODE rc;
 641 
 642                 /* fetch it into C->data, which is allocated with a length
 643                  * of 256 bytes; if there is more to be had, we then allocate
 644                  * bigger buffer for the caller to free */
 645 
 646                 rc = SQLGetData(S->stmt, colno+1, C->is_unicode ? SQL_C_BINARY : SQL_C_CHAR, C->data,
 647                         256, &C->fetched_len);
 648 
 649                 if (rc == SQL_SUCCESS) {
 650                         /* all the data fit into our little buffer;
 651                          * jump down to the generic bound data case */
 652                         goto in_data;
 653                 }
 654 
 655                 if (rc == SQL_SUCCESS_WITH_INFO) {
 656                         /* this is a 'long column'
 657 
 658                          read the column in 255 byte blocks until the end of the column is reached, reassembling those blocks
 659                          in order into the output buffer
 660 
 661                          this loop has to work whether or not SQLGetData() provides the total column length.
 662                          calling SQLDescribeCol() or other, specifically to get the column length, then doing a single read
 663                          for that size would be slower except maybe for extremely long columns.*/
 664                         char *buf2;
 665 
 666                         buf2 = emalloc(256);
 667                         buf = estrndup(C->data, 256);
 668                         used = 255; /* not 256; the driver NUL terminated the buffer */
 669 
 670                         do {
 671                                 C->fetched_len = 0;
 672                                 /* read block. 256 bytes => 255 bytes are actually read, the last 1 is NULL */
 673                                 rc = SQLGetData(S->stmt, colno+1, SQL_C_CHAR, buf2, 256, &C->fetched_len);
 674 
 675                                 /* resize output buffer and reassemble block */
 676                                 if (rc==SQL_SUCCESS_WITH_INFO) {
 677                                         /* point 5, in section "Retrieving Data with SQLGetData" in http://msdn.microsoft.com/en-us/library/windows/desktop/ms715441(v=vs.85).aspx
 678                                          states that if SQL_SUCCESS_WITH_INFO, fetched_len will be > 255 (greater than buf2's size)
 679                                          (if a driver fails to follow that and wrote less than 255 bytes to buf2, this will AV or read garbage into buf) */
 680                                         buf = erealloc(buf, used + 255+1);
 681                                         memcpy(buf + used, buf2, 255);
 682                                         used = used + 255;
 683                                 } else if (rc==SQL_SUCCESS) {
 684                                         buf = erealloc(buf, used + C->fetched_len+1);
 685                                         memcpy(buf + used, buf2, C->fetched_len);
 686                                         used = used + C->fetched_len;
 687                                 } else {
 688                                         /* includes SQL_NO_DATA */
 689                                         break;
 690                                 }
 691 
 692                         } while (1);
 693 
 694                         efree(buf2);
 695 
 696                         /* NULL terminate the buffer once, when finished, for use with the rest of PHP */
 697                         buf[used] = '\0';
 698 
 699                         *ptr = buf;
 700                         *caller_frees = 1;
 701                         *len = used;
 702                         if (C->is_unicode) {
 703                                 goto unicode_conv;
 704                         }
 705                         return 1;
 706                 }
 707 
 708                 /* something went caca */
 709                 *ptr = NULL;
 710                 *len = 0;
 711                 return 1;
 712         }
 713 
 714 in_data:
 715         /* check the indicator to ensure that the data is intact */
 716         if (C->fetched_len == SQL_NULL_DATA) {
 717                 /* A NULL value */
 718                 *ptr = NULL;
 719                 *len = 0;
 720                 return 1;
 721         } else if (C->fetched_len >= 0) {
 722                 /* it was stored perfectly */
 723                 *ptr = C->data;
 724                 *len = C->fetched_len;
 725                 if (C->is_unicode) {
 726                         goto unicode_conv;
 727                 }
 728                 return 1;
 729         } else {
 730                 /* no data? */
 731                 *ptr = NULL;
 732                 *len = 0;
 733                 return 1;
 734         }
 735 
 736         unicode_conv:
 737         switch (pdo_odbc_ucs22utf8(stmt, C->is_unicode, *ptr, *len, &ulen)) {
 738                 case PDO_ODBC_CONV_FAIL:
 739                         /* oh well.  They can have the binary version of it */
 740                 case PDO_ODBC_CONV_NOT_REQUIRED:
 741                         /* shouldn't happen... */
 742                         return 1;
 743 
 744                 case PDO_ODBC_CONV_OK:
 745                         if (*caller_frees) {
 746                                 efree(*ptr);
 747                         }
 748                         *ptr = emalloc(ulen + 1);
 749                         *len = ulen;
 750                         memcpy(*ptr, S->convbuf, ulen+1);
 751                         *caller_frees = 1;
 752                         return 1;
 753         }
 754         return 1;
 755 }
 756 
 757 static int odbc_stmt_set_param(pdo_stmt_t *stmt, zend_long attr, zval *val)
 758 {
 759         SQLRETURN rc;
 760         pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
 761 
 762         switch (attr) {
 763                 case PDO_ATTR_CURSOR_NAME:
 764                         convert_to_string(val);
 765                         rc = SQLSetCursorName(S->stmt, Z_STRVAL_P(val), Z_STRLEN_P(val));
 766 
 767                         if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) {
 768                                 return 1;
 769                         }
 770                         pdo_odbc_stmt_error("SQLSetCursorName");
 771                         return 0;
 772 
 773                 case PDO_ODBC_ATTR_ASSUME_UTF8:
 774                         S->assume_utf8 = zval_is_true(val);
 775                         return 0;
 776                 default:
 777                         strcpy(S->einfo.last_err_msg, "Unknown Attribute");
 778                         S->einfo.what = "setAttribute";
 779                         strcpy(S->einfo.last_state, "IM001");
 780                         return -1;
 781         }
 782 }
 783 
 784 static int odbc_stmt_get_attr(pdo_stmt_t *stmt, zend_long attr, zval *val)
 785 {
 786         SQLRETURN rc;
 787         pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
 788 
 789         switch (attr) {
 790                 case PDO_ATTR_CURSOR_NAME:
 791                 {
 792                         char buf[256];
 793                         SQLSMALLINT len = 0;
 794                         rc = SQLGetCursorName(S->stmt, buf, sizeof(buf), &len);
 795 
 796                         if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) {
 797                                 ZVAL_STRINGL(val, buf, len);
 798                                 return 1;
 799                         }
 800                         pdo_odbc_stmt_error("SQLGetCursorName");
 801                         return 0;
 802                 }
 803 
 804                 case PDO_ODBC_ATTR_ASSUME_UTF8:
 805                         ZVAL_BOOL(val, S->assume_utf8 ? 1 : 0);
 806                         return 0;
 807 
 808                 default:
 809                         strcpy(S->einfo.last_err_msg, "Unknown Attribute");
 810                         S->einfo.what = "getAttribute";
 811                         strcpy(S->einfo.last_state, "IM001");
 812                         return -1;
 813         }
 814 }
 815 
 816 static int odbc_stmt_next_rowset(pdo_stmt_t *stmt)
 817 {
 818         SQLRETURN rc;
 819         SQLSMALLINT colcount;
 820         pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
 821 
 822         /* NOTE: can't guarantee that output or input/output parameters
 823          * are set until this fella returns SQL_NO_DATA, according to
 824          * MSDN ODBC docs */
 825         rc = SQLMoreResults(S->stmt);
 826 
 827         if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
 828                 return 0;
 829         }
 830 
 831         free_cols(stmt, S);
 832         /* how many columns do we have ? */
 833         SQLNumResultCols(S->stmt, &colcount);
 834         stmt->column_count = (int)colcount;
 835         S->cols = ecalloc(colcount, sizeof(pdo_odbc_column));
 836         S->going_long = 0;
 837 
 838         return 1;
 839 }
 840 
 841 struct pdo_stmt_methods odbc_stmt_methods = {
 842         odbc_stmt_dtor,
 843         odbc_stmt_execute,
 844         odbc_stmt_fetch,
 845         odbc_stmt_describe,
 846         odbc_stmt_get_col,
 847         odbc_stmt_param_hook,
 848         odbc_stmt_set_param,
 849         odbc_stmt_get_attr, /* get attr */
 850         NULL, /* get column meta */
 851         odbc_stmt_next_rowset
 852 };
 853 
 854 /*
 855  * Local variables:
 856  * tab-width: 4
 857  * c-basic-offset: 4
 858  * End:
 859  * vim600: noet sw=4 ts=4 fdm=marker
 860  * vim<600: noet sw=4 ts=4
 861  */

/* [<][>][^][v][top][bottom][index][help] */