Back to index

php5  5.3.10
mysql_statement.c
Go to the documentation of this file.
00001 /*
00002   +----------------------------------------------------------------------+
00003   | PHP Version 5                                                        |
00004   +----------------------------------------------------------------------+
00005   | Copyright (c) 1997-2012 The PHP Group                                |
00006   +----------------------------------------------------------------------+
00007   | This source file is subject to version 3.01 of the PHP license,      |
00008   | that is bundled with this package in the file LICENSE, and is        |
00009   | available through the world-wide-web at the following url:           |
00010   | http://www.php.net/license/3_01.txt                                  |
00011   | If you did not receive a copy of the PHP license and are unable to   |
00012   | obtain it through the world-wide-web, please send a note to          |
00013   | license@php.net so we can mail you a copy immediately.               |
00014   +----------------------------------------------------------------------+
00015   | Author: George Schlossnagle <george@omniti.com>                      |
00016   |         Wez Furlong <wez@php.net>                                    |
00017   |         Johannes Schlueter <johannes@mysql.com>                      |
00018   +----------------------------------------------------------------------+
00019 */
00020 
00021 /* $Id: mysql_statement.c 321634 2012-01-01 13:15:04Z felipe $ */
00022 
00023 #ifdef HAVE_CONFIG_H
00024 #include "config.h"
00025 #endif
00026 
00027 #include "php.h"
00028 #include "php_ini.h"
00029 #include "ext/standard/info.h"
00030 #include "pdo/php_pdo.h"
00031 #include "pdo/php_pdo_driver.h"
00032 #include "php_pdo_mysql.h"
00033 #include "php_pdo_mysql_int.h"
00034 
00035 #ifdef PDO_USE_MYSQLND
00036 #      define pdo_mysql_stmt_execute_prepared(stmt) pdo_mysql_stmt_execute_prepared_mysqlnd(stmt TSRMLS_CC)
00037 #      define pdo_free_bound_result(res) zval_dtor(res.zv)
00038 #      define pdo_mysql_stmt_close(stmt) mysqlnd_stmt_close(stmt, 0)
00039 #else
00040 #      define pdo_mysql_stmt_execute_prepared(stmt) pdo_mysql_stmt_execute_prepared_libmysql(stmt TSRMLS_CC)
00041 #      define pdo_free_bound_result(res) efree(res.buffer)
00042 #      define pdo_mysql_stmt_close(stmt) mysql_stmt_close(stmt)
00043 #endif
00044 
00045 
00046 
00047 static int pdo_mysql_stmt_dtor(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
00048 {
00049        pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt->driver_data;
00050 
00051        PDO_DBG_ENTER("pdo_mysql_stmt_dtor");
00052        PDO_DBG_INF_FMT("stmt=%p", S->stmt);
00053        if (S->result) {
00054               /* free the resource */
00055               mysql_free_result(S->result);
00056               S->result = NULL;
00057        }
00058        if (S->einfo.errmsg) {
00059               pefree(S->einfo.errmsg, stmt->dbh->is_persistent);
00060               S->einfo.errmsg = NULL;
00061        }
00062 #if HAVE_MYSQL_STMT_PREPARE || PDO_USE_MYSQLND
00063        if (S->stmt) {
00064               pdo_mysql_stmt_close(S->stmt);
00065               S->stmt = NULL;
00066        }
00067 #endif /* HAVE_MYSQL_STMT_PREPARE || PDO_USE_MYSQLND */
00068 
00069 #ifndef PDO_USE_MYSQLND
00070        if (S->params) {
00071               efree(S->params);
00072        }
00073        if (S->in_null) {
00074               efree(S->in_null);
00075        }
00076        if (S->in_length) {
00077               efree(S->in_length);
00078        }
00079 
00080 #endif /* PDO_USE_MYSQLND */
00081 
00082 #ifdef HAVE_MYSQL_STMT_PREPARE
00083        if (S->bound_result) 
00084        {
00085               int i;
00086               for (i = 0; i < stmt->column_count; i++) {
00087                      pdo_free_bound_result(S->bound_result[i]);
00088               }
00089        
00090               efree(S->bound_result);
00091               efree(S->out_null);
00092               efree(S->out_length);
00093        }
00094 #endif /* HAVE_MYSQL_STMT_PREPARE */
00095 
00096 
00097 #if HAVE_MYSQL_NEXT_RESULT || PDO_USE_MYSQLND
00098        if (S->H->server) {
00099               while (mysql_more_results(S->H->server)) {
00100                      MYSQL_RES *res;
00101                      if (mysql_next_result(S->H->server) != 0) {
00102                             break;
00103                      }
00104                      
00105                      res = mysql_store_result(S->H->server);
00106                      if (res) {
00107                             mysql_free_result(res);
00108                      }
00109               }
00110        }      
00111 #endif /* HAVE_MYSQL_NEXT_RESULT || PDO_USE_MYSQLND */
00112 #if PDO_USE_MYSQLND
00113        if (!S->stmt && S->current_data) {
00114               mnd_free(S->current_data);
00115        }
00116 #endif /* PDO_USE_MYSQLND */
00117 
00118        efree(S);
00119        PDO_DBG_RETURN(1);
00120 }
00121 /* }}} */
00122 
00123 static void pdo_mysql_stmt_set_row_count(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
00124 {
00125        long row_count;
00126        pdo_mysql_stmt *S = stmt->driver_data;
00127        row_count = (long) mysql_stmt_affected_rows(S->stmt);
00128        if (row_count != (long)-1) {
00129               stmt->row_count = row_count;
00130        }
00131 }
00132 /* }}} */
00133 
00134 #ifdef HAVE_MYSQL_STMT_PREPARE
00135 static int pdo_mysql_stmt_execute_prepared_libmysql(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
00136 {
00137        pdo_mysql_stmt *S = stmt->driver_data;
00138        pdo_mysql_db_handle *H = S->H;
00139 
00140        PDO_DBG_ENTER("pdo_mysql_stmt_execute_prepared_libmysql");
00141 
00142        /* (re)bind the parameters */
00143        if (mysql_stmt_bind_param(S->stmt, S->params) || mysql_stmt_execute(S->stmt)) {
00144               if (S->params) {
00145                      memset(S->params, 0, S->num_params * sizeof(MYSQL_BIND));
00146               }
00147               pdo_mysql_error_stmt(stmt);
00148               if (mysql_stmt_errno(S->stmt) == 2057) {
00149                      /* CR_NEW_STMT_METADATA makes the statement unusable */
00150                      S->stmt = NULL;
00151               }
00152               PDO_DBG_RETURN(0);
00153        }
00154 
00155        if (!S->result) {
00156               int i; 
00157 
00158               /* figure out the result set format, if any */ 
00159               S->result = mysql_stmt_result_metadata(S->stmt); 
00160               if (S->result) { 
00161                      int calc_max_length = H->buffered && S->max_length == 1; 
00162                      S->fields = mysql_fetch_fields(S->result); 
00163                      if (S->bound_result) { 
00164                             int i; 
00165                             for (i = 0; i < stmt->column_count; i++) { 
00166                                    efree(S->bound_result[i].buffer);  
00167                             } 
00168                             efree(S->bound_result); 
00169                             efree(S->out_null); 
00170                             efree(S->out_length); 
00171                      }
00172                      
00173                      stmt->column_count = (int)mysql_num_fields(S->result);
00174                      S->bound_result = ecalloc(stmt->column_count, sizeof(MYSQL_BIND));
00175                      S->out_null = ecalloc(stmt->column_count, sizeof(my_bool));
00176                      S->out_length = ecalloc(stmt->column_count, sizeof(unsigned long));
00177 
00178                      /* summon memory to hold the row */
00179                      for (i = 0; i < stmt->column_count; i++) {
00180                             if (calc_max_length && S->fields[i].type == FIELD_TYPE_BLOB) {
00181                                    my_bool on = 1;
00182                                    mysql_stmt_attr_set(S->stmt, STMT_ATTR_UPDATE_MAX_LENGTH, &on);
00183                                    calc_max_length = 0;
00184                             }
00185                             switch (S->fields[i].type) {
00186                                    case FIELD_TYPE_INT24:
00187                                           S->bound_result[i].buffer_length = MAX_MEDIUMINT_WIDTH + 1;
00188                                           break;
00189                                    case FIELD_TYPE_LONG:
00190                                           S->bound_result[i].buffer_length = MAX_INT_WIDTH + 1;
00191                                           break;
00192                                    case FIELD_TYPE_LONGLONG:
00193                                           S->bound_result[i].buffer_length = MAX_BIGINT_WIDTH + 1;
00194                                           break;
00195                                    case FIELD_TYPE_TINY:
00196                                           S->bound_result[i].buffer_length = MAX_TINYINT_WIDTH + 1;
00197                                           break;
00198                                    case FIELD_TYPE_SHORT:
00199                                           S->bound_result[i].buffer_length = MAX_SMALLINT_WIDTH + 1;
00200                                           break;
00201                                    default:
00202                                           S->bound_result[i].buffer_length =
00203                                                  S->fields[i].max_length? S->fields[i].max_length:
00204                                                  S->fields[i].length;
00205                                           /* work-around for longtext and alike */
00206                                           if (S->bound_result[i].buffer_length > H->max_buffer_size) {
00207                                                  S->bound_result[i].buffer_length = H->max_buffer_size;
00208                                           }
00209                             }
00210 
00211                             /* there are cases where the length reported by mysql is too short.
00212                              * eg: when describing a table that contains an enum column. Since
00213                              * we have no way of knowing the true length either, we'll bump up
00214                              * our buffer size to a reasonable size, just in case */
00215                             if (S->fields[i].max_length == 0 && S->bound_result[i].buffer_length < 128 && MYSQL_TYPE_VAR_STRING) {
00216                                    S->bound_result[i].buffer_length = 128;
00217                             }
00218 
00219                             S->out_length[i] = 0;
00220 
00221                             S->bound_result[i].buffer = emalloc(S->bound_result[i].buffer_length);
00222                             S->bound_result[i].is_null = &S->out_null[i];
00223                             S->bound_result[i].length = &S->out_length[i];
00224                             S->bound_result[i].buffer_type = MYSQL_TYPE_STRING;
00225                      }
00226 
00227                      if (mysql_stmt_bind_result(S->stmt, S->bound_result)) {
00228                             pdo_mysql_error_stmt(stmt);
00229                             PDO_DBG_RETURN(0);
00230                      }
00231 
00232                      /* if buffered, pre-fetch all the data */
00233                      if (H->buffered) {
00234                             mysql_stmt_store_result(S->stmt);
00235                      }
00236               }
00237        }
00238        
00239        pdo_mysql_stmt_set_row_count(stmt TSRMLS_CC);
00240        PDO_DBG_RETURN(1);
00241 }
00242 /* }}} */
00243 #endif
00244 
00245 #ifdef PDO_USE_MYSQLND
00246 static int pdo_mysql_stmt_execute_prepared_mysqlnd(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
00247 {
00248        pdo_mysql_stmt *S = stmt->driver_data;
00249        pdo_mysql_db_handle *H = S->H;
00250        int i;
00251        
00252        PDO_DBG_ENTER("pdo_mysql_stmt_execute_prepared_mysqlnd");
00253        
00254        if (mysql_stmt_execute(S->stmt)) {
00255               pdo_mysql_error_stmt(stmt);
00256               PDO_DBG_RETURN(0);
00257        }
00258 
00259        if (S->result) {
00260               /* TODO: add a test to check if we really have zvals here... */
00261               mysql_free_result(S->result);
00262               S->result = NULL;
00263        }
00264 
00265        /* for SHOW/DESCRIBE and others the column/field count is not available before execute */
00266        stmt->column_count = mysql_stmt_field_count(S->stmt);
00267        for (i = 0; i < stmt->column_count; i++) {
00268               mysqlnd_stmt_bind_one_result(S->stmt, i);
00269        }
00270 
00271        S->result = mysqlnd_stmt_result_metadata(S->stmt);
00272        if (S->result) {
00273               S->fields = mysql_fetch_fields(S->result);
00274               /* if buffered, pre-fetch all the data */
00275               if (H->buffered) {
00276                      if (mysql_stmt_store_result(S->stmt)) {
00277                             PDO_DBG_RETURN(0);
00278                      }
00279               }
00280        }
00281        
00282        pdo_mysql_stmt_set_row_count(stmt TSRMLS_CC);
00283        PDO_DBG_RETURN(1);
00284 }
00285 /* }}} */
00286 #endif
00287 
00288 static int pdo_mysql_stmt_execute(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
00289 {
00290        pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt->driver_data;
00291        pdo_mysql_db_handle *H = S->H;
00292        my_ulonglong row_count;
00293        PDO_DBG_ENTER("pdo_mysql_stmt_execute");
00294        PDO_DBG_INF_FMT("stmt=%p", S->stmt);
00295 
00296 #if HAVE_MYSQL_STMT_PREPARE || PDO_USE_MYSQLND
00297        if (S->stmt) {
00298               PDO_DBG_RETURN(pdo_mysql_stmt_execute_prepared(stmt));
00299        }
00300 #endif
00301        
00302        /* ensure that we free any previous unfetched results */
00303        if (S->result) {
00304               mysql_free_result(S->result);
00305               S->result = NULL;
00306        }
00307 
00308        if (mysql_real_query(H->server, stmt->active_query_string, stmt->active_query_stringlen) != 0) {
00309               pdo_mysql_error_stmt(stmt);
00310               PDO_DBG_RETURN(0);
00311        }
00312 
00313        row_count = mysql_affected_rows(H->server);
00314        if (row_count == (my_ulonglong)-1) {
00315               /* we either have a query that returned a result set or an error occured
00316                  lets see if we have access to a result set */
00317               if (!H->buffered) {
00318                      S->result = mysql_use_result(H->server);
00319               } else {
00320                      S->result = mysql_store_result(H->server);
00321               }
00322               if (NULL == S->result) {
00323                      pdo_mysql_error_stmt(stmt);
00324                      PDO_DBG_RETURN(0);
00325               }
00326 
00327               stmt->row_count = (long) mysql_num_rows(S->result);
00328               stmt->column_count = (int) mysql_num_fields(S->result);
00329               S->fields = mysql_fetch_fields(S->result);
00330 
00331        } else {
00332               /* this was a DML or DDL query (INSERT, UPDATE, DELETE, ... */
00333               stmt->row_count = (long) row_count;
00334        }
00335 
00336        PDO_DBG_RETURN(1);
00337 }
00338 /* }}} */
00339 
00340 static int pdo_mysql_stmt_next_rowset(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
00341 {
00342 #if HAVE_MYSQL_NEXT_RESULT || PDO_USE_MYSQLND
00343        pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt->driver_data;
00344        pdo_mysql_db_handle *H = S->H;
00345        long row_count;
00346        int ret;
00347        PDO_DBG_ENTER("pdo_mysql_stmt_next_rowset");
00348        PDO_DBG_INF_FMT("stmt=%p", S->stmt);
00349 
00350 #if PDO_USE_MYSQLND
00351        if (!H->emulate_prepare) {
00352               if (!mysqlnd_stmt_more_results(S->stmt)) {
00353                      PDO_DBG_RETURN(0);
00354               }
00355               if (mysqlnd_stmt_next_result(S->stmt)) {
00356                      PDO_DBG_RETURN(0);
00357               }
00358 
00359               if (!mysqlnd_stmt_more_results(S->stmt)) {
00360                      /* 
00361                      MySQL gives us n + 1 result sets for 
00362                      CALL proc() and n result sets returned by the proc itself.
00363                      Result set n + 1 is about the procedure call itself.
00364                      As the PDO emulation does not return it, we skip it as well
00365                      */
00366                      PDO_DBG_RETURN(0);
00367               }
00368 
00369               /* TODO - this code is stolen from execute() - see above */
00370               if (S->result) {
00371                      mysql_free_result(S->result);
00372                      S->result = NULL;
00373               }
00374               {
00375                      /* for SHOW/DESCRIBE and others the column/field count is not available before execute */
00376                      int i;
00377 
00378                      stmt->column_count = mysql_stmt_field_count(S->stmt);
00379                      for (i = 0; i < stmt->column_count; i++) {
00380                             mysqlnd_stmt_bind_one_result(S->stmt, i);
00381                      }
00382               }
00383 
00384               S->result = mysqlnd_stmt_result_metadata(S->stmt);
00385               if (S->result) {
00386                      S->fields = mysql_fetch_fields(S->result);
00387 
00388                      /* if buffered, pre-fetch all the data */
00389                      if (H->buffered) {
00390                             if (mysql_stmt_store_result(S->stmt)) {
00391                                    PDO_DBG_RETURN(1);
00392                             }
00393                      }
00394               }
00395               row_count = (long) mysql_stmt_affected_rows(S->stmt);
00396               if (row_count != (long)-1) {
00397                      stmt->row_count = row_count;
00398               }
00399               PDO_DBG_RETURN(1);
00400        }
00401 #endif
00402 
00403 /* ensure that we free any previous unfetched results */
00404 #if HAVE_MYSQL_STMT_PREPARE
00405        if (S->stmt) {
00406               stmt->column_count = (int)mysql_num_fields(S->result);
00407               mysql_stmt_free_result(S->stmt);
00408        }
00409 #endif
00410        if (S->result) {
00411               mysql_free_result(S->result);
00412               S->result = NULL;
00413        }
00414 
00415        ret = mysql_next_result(H->server);
00416 
00417        if (ret > 0) {
00418               pdo_mysql_error_stmt(stmt);
00419               PDO_DBG_RETURN(0);
00420        } else if (ret < 0) {
00421               /* No more results */
00422               PDO_DBG_RETURN(0);
00423        } else {
00424               if (!H->buffered) {
00425                      S->result = mysql_use_result(H->server);
00426                      row_count = 0;
00427               } else {
00428                      S->result = mysql_store_result(H->server);
00429                      if ((long)-1 == (row_count = (long) mysql_affected_rows(H->server))) {
00430                             pdo_mysql_error_stmt(stmt);
00431                             PDO_DBG_RETURN(0);
00432                      }
00433               }
00434 
00435               if (NULL == S->result) {
00436                      PDO_DBG_RETURN(0);
00437               }
00438 
00439               stmt->row_count = row_count;
00440               stmt->column_count = (int) mysql_num_fields(S->result);
00441               S->fields = mysql_fetch_fields(S->result);
00442               PDO_DBG_RETURN(1);
00443        }
00444 #else
00445        strcpy(stmt->error_code, "HYC00");
00446        PDO_DBG_RETURN(0);
00447 #endif /* HAVE_MYSQL_STMT_PREPARE */
00448 }
00449 /* }}} */
00450 
00451 
00452 static const char * const pdo_param_event_names[] =
00453 {
00454        "PDO_PARAM_EVT_ALLOC",
00455        "PDO_PARAM_EVT_FREE",
00456        "PDO_PARAM_EVT_EXEC_PRE",
00457        "PDO_PARAM_EVT_EXEC_POST",
00458        "PDO_PARAM_EVT_FETCH_PRE",
00459        "PDO_PARAM_EVT_FETCH_POST",
00460        "PDO_PARAM_EVT_NORMALIZE",
00461 };
00462 
00463 
00464 static int pdo_mysql_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data *param, enum pdo_param_event event_type TSRMLS_DC) /* {{{ */
00465 {
00466 #ifndef PDO_USE_MYSQLND
00467        PDO_MYSQL_PARAM_BIND *b;
00468 #endif
00469 #if HAVE_MYSQL_STMT_PREPARE || PDO_USE_MYSQLND
00470        pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt->driver_data; 
00471 
00472        PDO_DBG_ENTER("pdo_mysql_stmt_param_hook");
00473        PDO_DBG_INF_FMT("stmt=%p", S->stmt);
00474        PDO_DBG_INF_FMT("event = %s", pdo_param_event_names[event_type]);
00475        if (S->stmt && param->is_param) {
00476               switch (event_type) {
00477                      case PDO_PARAM_EVT_ALLOC:
00478                             /* sanity check parameter number range */
00479                             if (param->paramno < 0 || param->paramno >= S->num_params) {
00480                                    strcpy(stmt->error_code, "HY093");
00481                                    PDO_DBG_RETURN(0);
00482                             }
00483                             S->params_given++;
00484 
00485 #ifndef PDO_USE_MYSQLND
00486                             b = &S->params[param->paramno];
00487                             param->driver_data = b;
00488                             b->is_null = &S->in_null[param->paramno];
00489                             b->length = &S->in_length[param->paramno];
00490                             /* recall how many parameters have been provided */
00491 #endif
00492                             PDO_DBG_RETURN(1);
00493 
00494                      case PDO_PARAM_EVT_EXEC_PRE:
00495                             if (S->params_given < (unsigned int) S->num_params) {
00496                                    /* too few parameter bound */
00497                                    PDO_DBG_ERR("too few parameters bound");
00498                                    strcpy(stmt->error_code, "HY093");
00499                                    PDO_DBG_RETURN(0);
00500                             }
00501 
00502 #if PDO_USE_MYSQLND
00503                             if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_NULL ||
00504                                           Z_TYPE_P(param->parameter) == IS_NULL) {
00505                                    mysqlnd_stmt_bind_one_param(S->stmt, param->paramno, param->parameter, MYSQL_TYPE_NULL);
00506                                    PDO_DBG_RETURN(1);
00507                             }
00508 #else
00509                             b = (PDO_MYSQL_PARAM_BIND*)param->driver_data;
00510                             *b->is_null = 0; 
00511                             if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_NULL ||  
00512                                           Z_TYPE_P(param->parameter) == IS_NULL) { 
00513                                    *b->is_null = 1; 
00514                                    b->buffer_type = MYSQL_TYPE_STRING; 
00515                                    b->buffer = NULL; 
00516                                    b->buffer_length = 0; 
00517                                    *b->length = 0; 
00518                                    PDO_DBG_RETURN(1);
00519                             } 
00520 #endif /* PDO_USE_MYSQLND */
00521        
00522                             switch (PDO_PARAM_TYPE(param->param_type)) {
00523                                    case PDO_PARAM_STMT:
00524                                           PDO_DBG_RETURN(0);
00525                                    case PDO_PARAM_LOB:
00526                                           PDO_DBG_INF("PDO_PARAM_LOB");
00527                                           if (Z_TYPE_P(param->parameter) == IS_RESOURCE) {
00528                                                  php_stream *stm;
00529                                                  php_stream_from_zval_no_verify(stm, &param->parameter);
00530                                                  if (stm) {
00531                                                         SEPARATE_ZVAL_IF_NOT_REF(&param->parameter);
00532                                                         Z_TYPE_P(param->parameter) = IS_STRING;
00533                                                         Z_STRLEN_P(param->parameter) = php_stream_copy_to_mem(stm,
00534                                                                &Z_STRVAL_P(param->parameter), PHP_STREAM_COPY_ALL, 0);
00535                                                  } else {
00536                                                         pdo_raise_impl_error(stmt->dbh, stmt, "HY105", "Expected a stream resource" TSRMLS_CC);
00537                                                         return 0;
00538                                                  }
00539                                           }
00540                                           /* fall through */
00541 
00542                                    default:
00543                                           ;
00544                             }
00545               
00546 #if PDO_USE_MYSQLND
00547                             /* Is it really correct to check the zval's type? - But well, that's what the old code below does, too */
00548                             PDO_DBG_INF_FMT("param->parameter->type=%d", Z_TYPE_P(param->parameter));
00549                             switch (Z_TYPE_P(param->parameter)) {
00550                                    case IS_STRING:
00551                                           mysqlnd_stmt_bind_one_param(S->stmt, param->paramno, param->parameter, MYSQL_TYPE_VAR_STRING);
00552                                           break;
00553                                    case IS_LONG:
00554 #if SIZEOF_LONG==8
00555                                           mysqlnd_stmt_bind_one_param(S->stmt, param->paramno, param->parameter, MYSQL_TYPE_LONGLONG);
00556 #elif SIZEOF_LONG==4
00557                                           mysqlnd_stmt_bind_one_param(S->stmt, param->paramno, param->parameter, MYSQL_TYPE_LONG);
00558 #endif /* SIZEOF_LONG */
00559                                           break;
00560                                    case IS_DOUBLE:
00561                                           mysqlnd_stmt_bind_one_param(S->stmt, param->paramno, param->parameter, MYSQL_TYPE_DOUBLE);
00562                                           break;
00563                                    default:
00564                                           PDO_DBG_RETURN(0);
00565                             }
00566                             
00567                             PDO_DBG_RETURN(1);
00568 #else  
00569                             PDO_DBG_INF_FMT("param->parameter->type=%d", Z_TYPE_P(param->parameter));
00570                             switch (Z_TYPE_P(param->parameter)) {
00571                                    case IS_STRING:
00572                                           b->buffer_type = MYSQL_TYPE_STRING;
00573                                           b->buffer = Z_STRVAL_P(param->parameter);
00574                                           b->buffer_length = Z_STRLEN_P(param->parameter);
00575                                           *b->length = Z_STRLEN_P(param->parameter);
00576                                           PDO_DBG_RETURN(1);
00577 
00578                                    case IS_LONG:
00579                                           b->buffer_type = MYSQL_TYPE_LONG;
00580                                           b->buffer = &Z_LVAL_P(param->parameter);
00581                                           PDO_DBG_RETURN(1);
00582 
00583                                    case IS_DOUBLE:
00584                                           b->buffer_type = MYSQL_TYPE_DOUBLE;
00585                                           b->buffer = &Z_DVAL_P(param->parameter);
00586                                           PDO_DBG_RETURN(1);
00587 
00588                                    default:
00589                                           PDO_DBG_RETURN(0);
00590                             }
00591 #endif /* PDO_USE_MYSQLND */
00592               case PDO_PARAM_EVT_FREE:
00593               case PDO_PARAM_EVT_EXEC_POST:
00594               case PDO_PARAM_EVT_FETCH_PRE:
00595               case PDO_PARAM_EVT_FETCH_POST:
00596               case PDO_PARAM_EVT_NORMALIZE:
00597                      /* do nothing */
00598                      break;
00599               }
00600        }
00601 #endif /* HAVE_MYSQL_STMT_PREPARE || PDO_USE_MYSQLND */
00602        PDO_DBG_RETURN(1);
00603 }
00604 /* }}} */
00605 
00606 static int pdo_mysql_stmt_fetch(pdo_stmt_t *stmt, enum pdo_fetch_orientation ori, long offset TSRMLS_DC) /* {{{ */
00607 {
00608        pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt->driver_data;
00609 #if PDO_USE_MYSQLND
00610        zend_bool fetched_anything;
00611 
00612        PDO_DBG_ENTER("pdo_mysql_stmt_fetch");
00613        PDO_DBG_INF_FMT("stmt=%p", S->stmt);
00614        if (S->stmt) {
00615               if (FAIL == mysqlnd_stmt_fetch(S->stmt, &fetched_anything) || fetched_anything == FALSE) {
00616                      PDO_DBG_RETURN(0);
00617               }
00618 
00619               PDO_DBG_RETURN(1);
00620        }
00621 #else
00622 #      if HAVE_MYSQL_STMT_PREPARE
00623        int ret;
00624        
00625        if (S->stmt) {
00626               ret = mysql_stmt_fetch(S->stmt);
00627 
00628 #             ifdef MYSQL_DATA_TRUNCATED
00629               if (ret == MYSQL_DATA_TRUNCATED) {
00630                      ret = 0;
00631               }
00632 #             endif
00633 
00634               if (ret) {
00635                      if (ret != MYSQL_NO_DATA) {
00636                             pdo_mysql_error_stmt(stmt);
00637                      }
00638                      PDO_DBG_RETURN(0);
00639               }
00640 
00641               PDO_DBG_RETURN(1);
00642        }
00643 #      endif /* HAVE_MYSQL_STMT_PREPARE */
00644 #endif /* PDO_USE_MYSQLND */
00645        
00646        if (!S->result) {
00647               strcpy(stmt->error_code, "HY000");
00648               PDO_DBG_RETURN(0);
00649        }
00650 #if PDO_USE_MYSQLND
00651        if (!S->stmt && S->current_data) {
00652               mnd_free(S->current_data);
00653        }
00654 #endif /* PDO_USE_MYSQLND */
00655 
00656        if ((S->current_data = mysql_fetch_row(S->result)) == NULL) {
00657 #if PDO_USE_MYSQLND
00658               if (S->result->unbuf && !S->result->unbuf->eof_reached && mysql_errno(S->H->server)) {
00659 #else
00660               if (!S->result->eof && mysql_errno(S->H->server)) {
00661 #endif
00662                      pdo_mysql_error_stmt(stmt);
00663               }
00664               PDO_DBG_RETURN(0);
00665        } 
00666 
00667        S->current_lengths = mysql_fetch_lengths(S->result);
00668        PDO_DBG_RETURN(1);
00669 }
00670 /* }}} */
00671 
00672 static int pdo_mysql_stmt_describe(pdo_stmt_t *stmt, int colno TSRMLS_DC) /* {{{ */
00673 {
00674        pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt->driver_data;
00675        struct pdo_column_data *cols = stmt->columns;
00676        int i;
00677 
00678        PDO_DBG_ENTER("pdo_mysql_stmt_describe");
00679        PDO_DBG_INF_FMT("stmt=%p", S->stmt);
00680        if (!S->result) {
00681               PDO_DBG_RETURN(0);
00682        }
00683 
00684        if (colno >= stmt->column_count) {
00685               /* error invalid column */
00686               PDO_DBG_RETURN(0);
00687        }
00688 
00689        /* fetch all on demand, this seems easiest 
00690        ** if we've been here before bail out 
00691        */
00692        if (cols[0].name) {
00693               PDO_DBG_RETURN(1);
00694        }
00695        for (i = 0; i < stmt->column_count; i++) {
00696               int namelen;
00697 
00698               if (S->H->fetch_table_names) {
00699                      namelen = spprintf(&cols[i].name, 0, "%s.%s", S->fields[i].table, S->fields[i].name);
00700                      cols[i].namelen = namelen;
00701               } else {
00702                      namelen = strlen(S->fields[i].name);
00703                      cols[i].namelen = namelen;
00704                      cols[i].name = estrndup(S->fields[i].name, namelen);
00705               }
00706               
00707               cols[i].precision = S->fields[i].decimals;
00708               cols[i].maxlen = S->fields[i].length;
00709               
00710 #ifdef PDO_USE_MYSQLND
00711               if (S->stmt) {
00712                      cols[i].param_type = PDO_PARAM_ZVAL;
00713               } else
00714 #endif
00715               {
00716                      cols[i].param_type = PDO_PARAM_STR;
00717               }
00718        }
00719        PDO_DBG_RETURN(1);
00720 }
00721 /* }}} */
00722 
00723 static int pdo_mysql_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, unsigned long *len, int *caller_frees TSRMLS_DC) /* {{{ */
00724 {
00725        pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt->driver_data;
00726 
00727        PDO_DBG_ENTER("pdo_mysql_stmt_get_col");
00728        PDO_DBG_INF_FMT("stmt=%p", S->stmt);
00729        if (!S->result) {
00730               PDO_DBG_RETURN(0);
00731        }
00732 
00733        /* With mysqlnd data is stored inside mysqlnd, not S->current_data */
00734 #if HAVE_MYSQL_STMT_PREPARE || PDO_USE_MYSQLND
00735        if (!S->stmt) {
00736 #endif
00737               if (S->current_data == NULL || !S->result) {
00738                      PDO_DBG_RETURN(0);
00739               }
00740 #if HAVE_MYSQL_STMT_PREPARE || PDO_USE_MYSQLND
00741        }
00742 #endif
00743        if (colno >= stmt->column_count) {
00744               /* error invalid column */
00745               PDO_DBG_RETURN(0);
00746        }
00747 #if PDO_USE_MYSQLND
00748        if (S->stmt) {
00749               Z_ADDREF_P(S->stmt->data->result_bind[colno].zv);
00750               *ptr = (char*)&S->stmt->data->result_bind[colno].zv;
00751               *len = sizeof(zval);
00752               PDO_DBG_RETURN(1);
00753        }
00754 #elif HAVE_MYSQL_STMT_PREPARE
00755        if (S->stmt) {
00756               if (S->out_null[colno]) {
00757                      *ptr = NULL;
00758                      *len = 0;
00759                      PDO_DBG_RETURN(1);
00760               }
00761               *ptr = S->bound_result[colno].buffer;
00762               if (S->out_length[colno] > S->bound_result[colno].buffer_length) {
00763                      /* mysql lied about the column width */
00764                      strcpy(stmt->error_code, "01004"); /* truncated */
00765                      S->out_length[colno] = S->bound_result[colno].buffer_length;
00766                      *len = S->out_length[colno];
00767                      PDO_DBG_RETURN(0);
00768               }
00769               *len = S->out_length[colno];
00770               PDO_DBG_RETURN(1);
00771        }
00772 #endif /* PDO_USE_MYSQLND else HAVE_MYSQL_STMT_PREPARE */
00773        *ptr = S->current_data[colno];
00774        *len = S->current_lengths[colno];
00775        PDO_DBG_RETURN(1);
00776 } /* }}} */
00777 
00778 static char *type_to_name_native(int type) /* {{{ */
00779 {
00780 #define PDO_MYSQL_NATIVE_TYPE_NAME(x)     case FIELD_TYPE_##x: return #x;
00781 
00782     switch (type) {
00783         PDO_MYSQL_NATIVE_TYPE_NAME(STRING)
00784         PDO_MYSQL_NATIVE_TYPE_NAME(VAR_STRING)
00785 #ifdef MYSQL_HAS_TINY
00786         PDO_MYSQL_NATIVE_TYPE_NAME(TINY)
00787 #endif
00788         PDO_MYSQL_NATIVE_TYPE_NAME(SHORT)
00789         PDO_MYSQL_NATIVE_TYPE_NAME(LONG)
00790         PDO_MYSQL_NATIVE_TYPE_NAME(LONGLONG)
00791         PDO_MYSQL_NATIVE_TYPE_NAME(INT24)
00792         PDO_MYSQL_NATIVE_TYPE_NAME(FLOAT)
00793         PDO_MYSQL_NATIVE_TYPE_NAME(DOUBLE)
00794         PDO_MYSQL_NATIVE_TYPE_NAME(DECIMAL)
00795 #ifdef FIELD_TYPE_NEWDECIMAL
00796         PDO_MYSQL_NATIVE_TYPE_NAME(NEWDECIMAL)
00797 #endif
00798 #ifdef FIELD_TYPE_GEOMETRY
00799         PDO_MYSQL_NATIVE_TYPE_NAME(GEOMETRY)
00800 #endif
00801         PDO_MYSQL_NATIVE_TYPE_NAME(TIMESTAMP)
00802 #ifdef MYSQL_HAS_YEAR
00803         PDO_MYSQL_NATIVE_TYPE_NAME(YEAR)
00804 #endif
00805         PDO_MYSQL_NATIVE_TYPE_NAME(SET)
00806         PDO_MYSQL_NATIVE_TYPE_NAME(ENUM)
00807         PDO_MYSQL_NATIVE_TYPE_NAME(DATE)
00808 #ifdef FIELD_TYPE_NEWDATE
00809         PDO_MYSQL_NATIVE_TYPE_NAME(NEWDATE)
00810 #endif
00811         PDO_MYSQL_NATIVE_TYPE_NAME(TIME)
00812         PDO_MYSQL_NATIVE_TYPE_NAME(DATETIME)
00813         PDO_MYSQL_NATIVE_TYPE_NAME(TINY_BLOB)
00814         PDO_MYSQL_NATIVE_TYPE_NAME(MEDIUM_BLOB)
00815         PDO_MYSQL_NATIVE_TYPE_NAME(LONG_BLOB)
00816         PDO_MYSQL_NATIVE_TYPE_NAME(BLOB)
00817         PDO_MYSQL_NATIVE_TYPE_NAME(NULL)
00818         default:
00819             return NULL;
00820     }
00821 #undef PDO_MYSQL_NATIVE_TYPE_NAME
00822 } /* }}} */
00823 
00824 static int pdo_mysql_stmt_col_meta(pdo_stmt_t *stmt, long colno, zval *return_value TSRMLS_DC) /* {{{ */
00825 {
00826        pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt->driver_data;
00827        const MYSQL_FIELD *F;
00828        zval *flags;
00829        char *str;
00830        
00831        PDO_DBG_ENTER("pdo_mysql_stmt_col_meta");
00832        PDO_DBG_INF_FMT("stmt=%p", S->stmt);
00833        if (!S->result) {
00834               PDO_DBG_RETURN(FAILURE);
00835        }
00836        if (colno >= stmt->column_count) {
00837               /* error invalid column */
00838               PDO_DBG_RETURN(FAILURE);
00839        }
00840 
00841        array_init(return_value);
00842        MAKE_STD_ZVAL(flags);
00843        array_init(flags);
00844 
00845        F = S->fields + colno;
00846 
00847        if (F->def) {
00848               add_assoc_string(return_value, "mysql:def", F->def, 1);
00849        }
00850        if (IS_NOT_NULL(F->flags)) {
00851               add_next_index_string(flags, "not_null", 1);
00852        }
00853        if (IS_PRI_KEY(F->flags)) {
00854               add_next_index_string(flags, "primary_key", 1);
00855        }
00856        if (F->flags & MULTIPLE_KEY_FLAG) {
00857               add_next_index_string(flags, "multiple_key", 1);
00858        }
00859        if (F->flags & UNIQUE_KEY_FLAG) {
00860               add_next_index_string(flags, "unique_key", 1);
00861        }
00862        if (IS_BLOB(F->flags)) {
00863               add_next_index_string(flags, "blob", 1);
00864        }
00865        str = type_to_name_native(F->type);
00866        if (str) {
00867               add_assoc_string(return_value, "native_type", str, 1);
00868        }
00869 
00870 #ifdef PDO_USE_MYSQLND
00871        switch (F->type) {
00872               case MYSQL_TYPE_BIT:
00873               case MYSQL_TYPE_YEAR:
00874               case MYSQL_TYPE_TINY:
00875               case MYSQL_TYPE_SHORT:
00876               case MYSQL_TYPE_INT24:
00877               case MYSQL_TYPE_LONG:
00878 #if SIZEOF_LONG==8
00879               case MYSQL_TYPE_LONGLONG:
00880 #endif
00881                      add_assoc_long(return_value, "pdo_type", PDO_PARAM_INT);
00882                      break;
00883               default:
00884                      add_assoc_long(return_value, "pdo_type", PDO_PARAM_STR);
00885                      break;
00886        }
00887 #endif
00888        
00889        add_assoc_zval(return_value, "flags", flags);
00890        add_assoc_string(return_value, "table",(char *) (F->table?F->table:""), 1);
00891        PDO_DBG_RETURN(SUCCESS);
00892 } /* }}} */
00893 
00894 static int pdo_mysql_stmt_cursor_closer(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
00895 {
00896        pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt->driver_data;
00897 
00898        PDO_DBG_ENTER("pdo_mysql_stmt_cursor_closer");
00899        PDO_DBG_INF_FMT("stmt=%p", S->stmt);
00900        if (S->result) {
00901               mysql_free_result(S->result);
00902               S->result = NULL;
00903        }
00904 #if HAVE_MYSQL_STMT_PREPARE || PDO_USE_MYSQLND
00905        if (S->stmt) {
00906               int retval;
00907               retval = mysql_stmt_free_result(S->stmt);
00908               PDO_DBG_RETURN(retval ? 0 : 1);
00909        }
00910 #endif
00911 
00912 #if HAVE_MYSQL_NEXT_RESULT || PDO_USE_MYSQLND
00913        while (mysql_more_results(S->H->server)) {
00914               MYSQL_RES *res;
00915               if (mysql_next_result(S->H->server) != 0) {
00916                      break;
00917               }
00918               res = mysql_store_result(S->H->server);
00919               if (res) {
00920                      mysql_free_result(res);
00921               }
00922        }
00923 #endif
00924        PDO_DBG_RETURN(1);
00925 }
00926 /* }}} */
00927 
00928 struct pdo_stmt_methods mysql_stmt_methods = {
00929        pdo_mysql_stmt_dtor,
00930        pdo_mysql_stmt_execute,
00931        pdo_mysql_stmt_fetch,
00932        pdo_mysql_stmt_describe,
00933        pdo_mysql_stmt_get_col,
00934        pdo_mysql_stmt_param_hook,
00935        NULL, /* set_attr */
00936        NULL, /* get_attr */
00937        pdo_mysql_stmt_col_meta,
00938        pdo_mysql_stmt_next_rowset,
00939        pdo_mysql_stmt_cursor_closer
00940 };
00941 
00942 /*
00943  * Local variables:
00944  * tab-width: 4
00945  * c-basic-offset: 4
00946  * End:
00947  * vim600: noet sw=4 ts=4 fdm=marker
00948  * vim<600: noet sw=4 ts=4
00949  */