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 5                                                        |
   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         unsigned long buflen, unsigned long *outlen)
  62 {
  63 #ifdef PHP_WIN32
  64         if (is_unicode && buflen) {
  65                 pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
  66                 DWORD ret;
  67 
  68                 ret = MultiByteToWideChar(CP_UTF8, 0, buf, buflen, NULL, 0);
  69                 if (ret == 0) {
  70                         /*printf("%s:%d %d [%d] %.*s\n", __FILE__, __LINE__, GetLastError(), buflen, buflen, buf);*/
  71                         return PDO_ODBC_CONV_FAIL;
  72                 }
  73 
  74                 ret *= sizeof(WCHAR);
  75 
  76                 if (S->convbufsize <= ret) {
  77                         S->convbufsize = ret + sizeof(WCHAR);
  78                         S->convbuf = erealloc(S->convbuf, S->convbufsize);
  79                 }
  80                 
  81                 ret = MultiByteToWideChar(CP_UTF8, 0, buf, buflen, (LPWSTR)S->convbuf, S->convbufsize / sizeof(WCHAR));
  82                 if (ret == 0) {
  83                         /*printf("%s:%d %d [%d] %.*s\n", __FILE__, __LINE__, GetLastError(), buflen, buflen, buf);*/
  84                         return PDO_ODBC_CONV_FAIL;
  85                 }
  86 
  87                 ret *= sizeof(WCHAR);
  88                 *outlen = ret;
  89                 return PDO_ODBC_CONV_OK;
  90         }
  91 #endif
  92         return PDO_ODBC_CONV_NOT_REQUIRED;
  93 }
  94 
  95 static int pdo_odbc_ucs22utf8(pdo_stmt_t *stmt, int is_unicode, const char *buf, 
  96         unsigned long buflen, unsigned long *outlen)
  97 {
  98 #ifdef PHP_WIN32
  99         if (is_unicode && buflen) {
 100                 pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
 101                 DWORD ret;
 102 
 103                 ret = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)buf, buflen/sizeof(WCHAR), NULL, 0, NULL, NULL);
 104                 if (ret == 0) {
 105                         return PDO_ODBC_CONV_FAIL;
 106                 }
 107 
 108                 if (S->convbufsize <= ret) {
 109                         S->convbufsize = ret + 1;
 110                         S->convbuf = erealloc(S->convbuf, S->convbufsize);
 111                 }
 112                 
 113                 ret = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)buf, buflen/sizeof(WCHAR), S->convbuf, S->convbufsize, NULL, NULL);
 114                 if (ret == 0) {
 115                         return PDO_ODBC_CONV_FAIL;
 116                 }
 117 
 118                 *outlen = ret;
 119                 S->convbuf[*outlen] = '\0';
 120                 return PDO_ODBC_CONV_OK;
 121         }
 122 #endif
 123         return PDO_ODBC_CONV_NOT_REQUIRED;
 124 }
 125 
 126 static void free_cols(pdo_stmt_t *stmt, pdo_odbc_stmt *S TSRMLS_DC)
 127 {
 128         if (S->cols) {
 129                 int i;
 130 
 131                 for (i = 0; i < stmt->column_count; i++) {
 132                         if (S->cols[i].data) {
 133                                 efree(S->cols[i].data);
 134                         }
 135                 }
 136                 efree(S->cols);
 137                 S->cols = NULL;
 138         }
 139 }
 140 
 141 static int odbc_stmt_dtor(pdo_stmt_t *stmt TSRMLS_DC)
 142 {
 143         pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
 144 
 145         if (S->stmt != SQL_NULL_HANDLE) {
 146                 if (stmt->executed) {
 147                         SQLCloseCursor(S->stmt);
 148                 }
 149                 SQLFreeHandle(SQL_HANDLE_STMT, S->stmt);
 150                 S->stmt = SQL_NULL_HANDLE;
 151         }
 152 
 153         free_cols(stmt, S TSRMLS_CC);
 154         if (S->convbuf) {
 155                 efree(S->convbuf);
 156         }
 157         efree(S);
 158 
 159         return 1;
 160 }
 161 
 162 static int odbc_stmt_execute(pdo_stmt_t *stmt TSRMLS_DC)
 163 {
 164         RETCODE rc;
 165         pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
 166         char *buf = NULL;
 167         SQLLEN row_count = -1;
 168 
 169         if (stmt->executed) {
 170                 SQLCloseCursor(S->stmt);
 171         }
 172         
 173         rc = SQLExecute(S->stmt);       
 174 
 175         while (rc == SQL_NEED_DATA) {
 176                 struct pdo_bound_param_data *param;
 177 
 178                 rc = SQLParamData(S->stmt, (SQLPOINTER*)&param);
 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, &param->parameter);
 216                         if (!stm) {
 217                                 /* shouldn't happen either */
 218                                 pdo_odbc_stmt_error("input LOB is no longer a stream");
 219                                 SQLCloseCursor(S->stmt);
 220                                 if (buf) {
 221                                         efree(buf);
 222                                 }
 223                                 return 0;
 224                         }
 225 
 226                         /* now suck data from the stream and stick it into the database */
 227                         if (buf == NULL) {
 228                                 buf = emalloc(8192);
 229                         }
 230 
 231                         do {
 232                                 len = php_stream_read(stm, buf, 8192);
 233                                 if (len == 0) {
 234                                         break;
 235                                 }
 236                                 SQLPutData(S->stmt, buf, len);
 237                         } while (1);
 238                 }
 239         }
 240 
 241         if (buf) {
 242                 efree(buf);
 243         }
 244 
 245         switch (rc) {
 246                 case SQL_SUCCESS:
 247                         break;
 248                 case SQL_NO_DATA_FOUND:
 249                 case SQL_SUCCESS_WITH_INFO:
 250                         pdo_odbc_stmt_error("SQLExecute");
 251                         break;
 252 
 253                 default:
 254                         pdo_odbc_stmt_error("SQLExecute");
 255                         return 0;
 256         }
 257 
 258         SQLRowCount(S->stmt, &row_count);
 259         stmt->row_count = row_count;
 260 
 261         if (!stmt->executed) {
 262                 /* do first-time-only definition of bind/mapping stuff */
 263                 SQLSMALLINT colcount;
 264 
 265                 /* how many columns do we have ? */
 266                 SQLNumResultCols(S->stmt, &colcount);
 267 
 268                 stmt->column_count = (int)colcount;
 269                 S->cols = ecalloc(colcount, sizeof(pdo_odbc_column));
 270                 S->going_long = 0;
 271         }
 272 
 273         return 1;
 274 }
 275 
 276 static int odbc_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data *param,
 277                 enum pdo_param_event event_type TSRMLS_DC)
 278 {
 279         pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
 280         RETCODE rc;
 281         SWORD sqltype = 0, ctype = 0, scale = 0, nullable = 0;
 282         SQLULEN 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, &param->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 
 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 
 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         SQLULEN 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 
 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 
 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 
 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 
 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  */

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