File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / ext / pdo_mysql / mysql_statement.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jul 22 01:31:58 2013 UTC (10 years, 11 months ago) by misho
Branches: php, MAIN
CVS tags: v5_4_29p0, v5_4_20p0, v5_4_20, v5_4_17, HEAD
5.4.17

    1: /*
    2:   +----------------------------------------------------------------------+
    3:   | PHP Version 5                                                        |
    4:   +----------------------------------------------------------------------+
    5:   | Copyright (c) 1997-2013 The PHP Group                                |
    6:   +----------------------------------------------------------------------+
    7:   | This source file is subject to version 3.01 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_01.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: George Schlossnagle <george@omniti.com>                      |
   16:   |         Wez Furlong <wez@php.net>                                    |
   17:   |         Johannes Schlueter <johannes@mysql.com>                      |
   18:   +----------------------------------------------------------------------+
   19: */
   20: 
   21: /* $Id: mysql_statement.c,v 1.1.1.3 2013/07/22 01:31:58 misho Exp $ */
   22: 
   23: #ifdef HAVE_CONFIG_H
   24: #include "config.h"
   25: #endif
   26: 
   27: #include "php.h"
   28: #include "php_ini.h"
   29: #include "ext/standard/info.h"
   30: #include "pdo/php_pdo.h"
   31: #include "pdo/php_pdo_driver.h"
   32: #include "php_pdo_mysql.h"
   33: #include "php_pdo_mysql_int.h"
   34: 
   35: #ifdef PDO_USE_MYSQLND
   36: #	define pdo_mysql_stmt_execute_prepared(stmt) pdo_mysql_stmt_execute_prepared_mysqlnd(stmt TSRMLS_CC)
   37: #	define pdo_free_bound_result(res) zval_dtor(res.zv)
   38: #	define pdo_mysql_stmt_close(stmt) mysqlnd_stmt_close(stmt, 0)
   39: #else
   40: #	define pdo_mysql_stmt_execute_prepared(stmt) pdo_mysql_stmt_execute_prepared_libmysql(stmt TSRMLS_CC)
   41: #	define pdo_free_bound_result(res) efree(res.buffer)
   42: #	define pdo_mysql_stmt_close(stmt) mysql_stmt_close(stmt)
   43: #endif
   44: 
   45: 
   46: 
   47: static int pdo_mysql_stmt_dtor(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
   48: {
   49: 	pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt->driver_data;
   50: 
   51: 	PDO_DBG_ENTER("pdo_mysql_stmt_dtor");
   52: 	PDO_DBG_INF_FMT("stmt=%p", S->stmt);
   53: 	if (S->result) {
   54: 		/* free the resource */
   55: 		mysql_free_result(S->result);
   56: 		S->result = NULL;
   57: 	}
   58: 	if (S->einfo.errmsg) {
   59: 		pefree(S->einfo.errmsg, stmt->dbh->is_persistent);
   60: 		S->einfo.errmsg = NULL;
   61: 	}
   62: 	if (S->stmt) {
   63: 		pdo_mysql_stmt_close(S->stmt);
   64: 		S->stmt = NULL;
   65: 	}
   66: 
   67: #ifndef PDO_USE_MYSQLND
   68: 	if (S->params) {
   69: 		efree(S->params);
   70: 	}
   71: 	if (S->in_null) {
   72: 		efree(S->in_null);
   73: 	}
   74: 	if (S->in_length) {
   75: 		efree(S->in_length);
   76: 	}
   77: 
   78: 	if (S->bound_result)
   79: 	{
   80: 		int i;
   81: 		for (i = 0; i < stmt->column_count; i++) {
   82: 			pdo_free_bound_result(S->bound_result[i]);
   83: 		}
   84: 
   85: 		efree(S->bound_result);
   86: 		efree(S->out_null);
   87: 		efree(S->out_length);
   88: 	}
   89: #endif
   90: 
   91: 
   92: 	if (S->H->server) {
   93: 		while (mysql_more_results(S->H->server)) {
   94: 			MYSQL_RES *res;
   95: 			if (mysql_next_result(S->H->server) != 0) {
   96: 				break;
   97: 			}
   98: 
   99: 			res = mysql_store_result(S->H->server);
  100: 			if (res) {
  101: 				mysql_free_result(res);
  102: 			}
  103: 		}
  104: 	}
  105: 
  106: #if PDO_USE_MYSQLND
  107: 	if (!S->stmt && S->current_data) {
  108: 		mnd_free(S->current_data);
  109: 	}
  110: #endif /* PDO_USE_MYSQLND */
  111: 
  112: 	efree(S);
  113: 	PDO_DBG_RETURN(1);
  114: }
  115: /* }}} */
  116: 
  117: static void pdo_mysql_stmt_set_row_count(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
  118: {
  119: 	long row_count;
  120: 	pdo_mysql_stmt *S = stmt->driver_data;
  121: 	row_count = (long) mysql_stmt_affected_rows(S->stmt);
  122: 	if (row_count != (long)-1) {
  123: 		stmt->row_count = row_count;
  124: 	}
  125: }
  126: /* }}} */
  127: 
  128: static int pdo_mysql_fill_stmt_from_result(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
  129: {
  130: 	pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt->driver_data;
  131: 	pdo_mysql_db_handle *H = S->H;
  132: 	my_ulonglong row_count;
  133: 	PDO_DBG_ENTER("pdo_mysql_fill_stmt_from_result");
  134: 
  135: 	row_count = mysql_affected_rows(H->server);
  136: 	if (row_count == (my_ulonglong)-1) {
  137: 		/* we either have a query that returned a result set or an error occurred
  138: 		   lets see if we have access to a result set */
  139: 		if (!H->buffered) {
  140: 			S->result = mysql_use_result(H->server);
  141: 		} else {
  142: 			S->result = mysql_store_result(H->server);
  143: 		}
  144: 		if (NULL == S->result) {
  145: 			pdo_mysql_error_stmt(stmt);
  146: 			PDO_DBG_RETURN(0);
  147: 		}
  148: 
  149: 		stmt->row_count = (long) mysql_num_rows(S->result);
  150: 		stmt->column_count = (int) mysql_num_fields(S->result);
  151: 		S->fields = mysql_fetch_fields(S->result);
  152: 	} else {
  153: 		/* this was a DML or DDL query (INSERT, UPDATE, DELETE, ... */
  154: 		stmt->row_count = (long) row_count;
  155: 	}
  156: 
  157: 	PDO_DBG_RETURN(1);
  158: }
  159: /* }}} */
  160: 
  161: #ifndef PDO_USE_MYSQLND
  162: static int pdo_mysql_stmt_execute_prepared_libmysql(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
  163: {
  164: 	pdo_mysql_stmt *S = stmt->driver_data;
  165: 	pdo_mysql_db_handle *H = S->H;
  166: 
  167: 	PDO_DBG_ENTER("pdo_mysql_stmt_execute_prepared_libmysql");
  168: 
  169: 	/* (re)bind the parameters */
  170: 	if (mysql_stmt_bind_param(S->stmt, S->params) || mysql_stmt_execute(S->stmt)) {
  171: 		if (S->params) {
  172: 			memset(S->params, 0, S->num_params * sizeof(MYSQL_BIND));
  173: 		}
  174: 		pdo_mysql_error_stmt(stmt);
  175: 		if (mysql_stmt_errno(S->stmt) == 2057) {
  176: 			/* CR_NEW_STMT_METADATA makes the statement unusable */
  177: 			S->stmt = NULL;
  178: 		}
  179: 		PDO_DBG_RETURN(0);
  180: 	}
  181: 
  182: 	if (!S->result) {
  183: 		int i;
  184: 
  185: 		/* figure out the result set format, if any */
  186: 		S->result = mysql_stmt_result_metadata(S->stmt);
  187: 		if (S->result) {
  188: 			int calc_max_length = H->buffered && S->max_length == 1;
  189: 			S->fields = mysql_fetch_fields(S->result);
  190: 			if (S->bound_result) {
  191: 				int i;
  192: 				for (i = 0; i < stmt->column_count; i++) {
  193: 					efree(S->bound_result[i].buffer);
  194: 				}
  195: 				efree(S->bound_result);
  196: 				efree(S->out_null);
  197: 				efree(S->out_length);
  198: 			}
  199: 
  200: 			stmt->column_count = (int)mysql_num_fields(S->result);
  201: 			S->bound_result = ecalloc(stmt->column_count, sizeof(MYSQL_BIND));
  202: 			S->out_null = ecalloc(stmt->column_count, sizeof(my_bool));
  203: 			S->out_length = ecalloc(stmt->column_count, sizeof(unsigned long));
  204: 
  205: 			/* summon memory to hold the row */
  206: 			for (i = 0; i < stmt->column_count; i++) {
  207: 				if (calc_max_length && S->fields[i].type == FIELD_TYPE_BLOB) {
  208: 					my_bool on = 1;
  209: 					mysql_stmt_attr_set(S->stmt, STMT_ATTR_UPDATE_MAX_LENGTH, &on);
  210: 					calc_max_length = 0;
  211: 				}
  212: 				switch (S->fields[i].type) {
  213: 					case FIELD_TYPE_INT24:
  214: 						S->bound_result[i].buffer_length = MAX_MEDIUMINT_WIDTH + 1;
  215: 						break;
  216: 					case FIELD_TYPE_LONG:
  217: 						S->bound_result[i].buffer_length = MAX_INT_WIDTH + 1;
  218: 						break;
  219: 					case FIELD_TYPE_LONGLONG:
  220: 						S->bound_result[i].buffer_length = MAX_BIGINT_WIDTH + 1;
  221: 						break;
  222: 					case FIELD_TYPE_TINY:
  223: 						S->bound_result[i].buffer_length = MAX_TINYINT_WIDTH + 1;
  224: 						break;
  225: 					case FIELD_TYPE_SHORT:
  226: 						S->bound_result[i].buffer_length = MAX_SMALLINT_WIDTH + 1;
  227: 						break;
  228: 					default:
  229: 						S->bound_result[i].buffer_length =
  230: 							S->fields[i].max_length? S->fields[i].max_length:
  231: 							S->fields[i].length;
  232: 						/* work-around for longtext and alike */
  233: 						if (S->bound_result[i].buffer_length > H->max_buffer_size) {
  234: 							S->bound_result[i].buffer_length = H->max_buffer_size;
  235: 						}
  236: 				}
  237: 
  238: 				/* there are cases where the length reported by mysql is too short.
  239: 				 * eg: when describing a table that contains an enum column. Since
  240: 				 * we have no way of knowing the true length either, we'll bump up
  241: 				 * our buffer size to a reasonable size, just in case */
  242: 				if (S->fields[i].max_length == 0 && S->bound_result[i].buffer_length < 128 && MYSQL_TYPE_VAR_STRING) {
  243: 					S->bound_result[i].buffer_length = 128;
  244: 				}
  245: 
  246: 				S->out_length[i] = 0;
  247: 
  248: 				S->bound_result[i].buffer = emalloc(S->bound_result[i].buffer_length);
  249: 				S->bound_result[i].is_null = &S->out_null[i];
  250: 				S->bound_result[i].length = &S->out_length[i];
  251: 				S->bound_result[i].buffer_type = MYSQL_TYPE_STRING;
  252: 			}
  253: 
  254: 			if (mysql_stmt_bind_result(S->stmt, S->bound_result)) {
  255: 				pdo_mysql_error_stmt(stmt);
  256: 				PDO_DBG_RETURN(0);
  257: 			}
  258: 
  259: 			/* if buffered, pre-fetch all the data */
  260: 			if (H->buffered) {
  261: 				mysql_stmt_store_result(S->stmt);
  262: 			}
  263: 		}
  264: 	}
  265: 
  266: 	pdo_mysql_stmt_set_row_count(stmt TSRMLS_CC);
  267: 	PDO_DBG_RETURN(1);
  268: }
  269: /* }}} */
  270: #endif
  271: 
  272: #ifdef PDO_USE_MYSQLND
  273: static int pdo_mysql_stmt_execute_prepared_mysqlnd(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
  274: {
  275: 	pdo_mysql_stmt *S = stmt->driver_data;
  276: 	pdo_mysql_db_handle *H = S->H;
  277: 	int i;
  278: 
  279: 	PDO_DBG_ENTER("pdo_mysql_stmt_execute_prepared_mysqlnd");
  280: 
  281: 	if (mysql_stmt_execute(S->stmt)) {
  282: 		pdo_mysql_error_stmt(stmt);
  283: 		PDO_DBG_RETURN(0);
  284: 	}
  285: 
  286: 	if (S->result) {
  287: 		/* TODO: add a test to check if we really have zvals here... */
  288: 		mysql_free_result(S->result);
  289: 		S->result = NULL;
  290: 	}
  291: 
  292: 	/* for SHOW/DESCRIBE and others the column/field count is not available before execute */
  293: 	stmt->column_count = mysql_stmt_field_count(S->stmt);
  294: 	for (i = 0; i < stmt->column_count; i++) {
  295: 		mysqlnd_stmt_bind_one_result(S->stmt, i);
  296: 	}
  297: 
  298: 	S->result = mysqlnd_stmt_result_metadata(S->stmt);
  299: 	if (S->result) {
  300: 		S->fields = mysql_fetch_fields(S->result);
  301: 		/* if buffered, pre-fetch all the data */
  302: 		if (H->buffered) {
  303: 			if (mysql_stmt_store_result(S->stmt)) {
  304: 				PDO_DBG_RETURN(0);
  305: 			}
  306: 		}
  307: 	}
  308: 
  309: 	pdo_mysql_stmt_set_row_count(stmt TSRMLS_CC);
  310: 	PDO_DBG_RETURN(1);
  311: }
  312: /* }}} */
  313: #endif
  314: 
  315: static int pdo_mysql_stmt_execute(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
  316: {
  317: 	pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt->driver_data;
  318: 	pdo_mysql_db_handle *H = S->H;
  319: 	PDO_DBG_ENTER("pdo_mysql_stmt_execute");
  320: 	PDO_DBG_INF_FMT("stmt=%p", S->stmt);
  321: 
  322: 	if (S->stmt) {
  323: 		PDO_DBG_RETURN(pdo_mysql_stmt_execute_prepared(stmt));
  324: 	}
  325: 
  326: 	/* ensure that we free any previous unfetched results */
  327: 	if (S->result) {
  328: 		mysql_free_result(S->result);
  329: 		S->result = NULL;
  330: 	}
  331: 
  332: 	if (mysql_real_query(H->server, stmt->active_query_string, stmt->active_query_stringlen) != 0) {
  333: 		pdo_mysql_error_stmt(stmt);
  334: 		PDO_DBG_RETURN(0);
  335: 	}
  336: 
  337: 	PDO_DBG_RETURN(pdo_mysql_fill_stmt_from_result(stmt TSRMLS_CC));
  338: }
  339: /* }}} */
  340: 
  341: static int pdo_mysql_stmt_next_rowset(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
  342: {
  343: 	pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt->driver_data;
  344: 	pdo_mysql_db_handle *H = S->H;
  345: 	long row_count;
  346: 	PDO_DBG_ENTER("pdo_mysql_stmt_next_rowset");
  347: 	PDO_DBG_INF_FMT("stmt=%p", S->stmt);
  348: 
  349: #if PDO_USE_MYSQLND
  350: 	if (!H->emulate_prepare) {
  351: 		if (!mysqlnd_stmt_more_results(S->stmt)) {
  352: 			PDO_DBG_RETURN(0);
  353: 		}
  354: 		if (mysqlnd_stmt_next_result(S->stmt)) {
  355: 			PDO_DBG_RETURN(0);
  356: 		}
  357: 
  358: 		if (!mysqlnd_stmt_more_results(S->stmt)) {
  359: 			/*
  360: 			MySQL gives us n + 1 result sets for
  361: 			CALL proc() and n result sets returned by the proc itself.
  362: 			Result set n + 1 is about the procedure call itself.
  363: 			As the PDO emulation does not return it, we skip it as well
  364: 			*/
  365: 			PDO_DBG_RETURN(0);
  366: 		}
  367: 
  368: 		/* TODO - this code is stolen from execute() - see above */
  369: 		if (S->result) {
  370: 			mysql_free_result(S->result);
  371: 			S->result = NULL;
  372: 		}
  373: 		{
  374: 			/* for SHOW/DESCRIBE and others the column/field count is not available before execute */
  375: 			int i;
  376: 
  377: 			stmt->column_count = mysql_stmt_field_count(S->stmt);
  378: 			for (i = 0; i < stmt->column_count; i++) {
  379: 				mysqlnd_stmt_bind_one_result(S->stmt, i);
  380: 			}
  381: 		}
  382: 
  383: 		S->result = mysqlnd_stmt_result_metadata(S->stmt);
  384: 		if (S->result) {
  385: 			S->fields = mysql_fetch_fields(S->result);
  386: 
  387: 			/* if buffered, pre-fetch all the data */
  388: 			if (H->buffered) {
  389: 				if (mysql_stmt_store_result(S->stmt)) {
  390: 					PDO_DBG_RETURN(1);
  391: 				}
  392: 			}
  393: 		}
  394: 		row_count = (long) mysql_stmt_affected_rows(S->stmt);
  395: 		if (row_count != (long)-1) {
  396: 			stmt->row_count = row_count;
  397: 		}
  398: 		PDO_DBG_RETURN(1);
  399: 	}
  400: #endif
  401: 
  402: /* ensure that we free any previous unfetched results */
  403: #ifndef PDO_USE_MYSQLND
  404: 	if (S->stmt) {
  405: 		stmt->column_count = (int)mysql_num_fields(S->result);
  406: 		mysql_stmt_free_result(S->stmt);
  407: 	}
  408: #endif
  409: 	if (S->result) {
  410: 		mysql_free_result(S->result);
  411: 		S->result = NULL;
  412: 	}
  413: 
  414: 	if (!mysql_more_results(H->server)) {
  415: 		/* No more results */
  416: 		PDO_DBG_RETURN(0);	
  417: 	}
  418: #if PDO_USE_MYSQLND
  419: 	if (mysql_next_result(H->server) == FAIL) {
  420: 		pdo_mysql_error_stmt(stmt);
  421: 		PDO_DBG_RETURN(0);
  422: 	} else {
  423: 		PDO_DBG_RETURN(pdo_mysql_fill_stmt_from_result(stmt TSRMLS_CC));
  424: 	}
  425: #else
  426: 	if (mysql_next_result(H->server) > 0) {
  427: 		pdo_mysql_error_stmt(stmt);
  428: 		PDO_DBG_RETURN(0);
  429: 	} else {
  430: 		PDO_DBG_RETURN(pdo_mysql_fill_stmt_from_result(stmt TSRMLS_CC));
  431: 	}
  432: #endif
  433: }
  434: /* }}} */
  435: 
  436: 
  437: static const char * const pdo_param_event_names[] =
  438: {
  439: 	"PDO_PARAM_EVT_ALLOC",
  440: 	"PDO_PARAM_EVT_FREE",
  441: 	"PDO_PARAM_EVT_EXEC_PRE",
  442: 	"PDO_PARAM_EVT_EXEC_POST",
  443: 	"PDO_PARAM_EVT_FETCH_PRE",
  444: 	"PDO_PARAM_EVT_FETCH_POST",
  445: 	"PDO_PARAM_EVT_NORMALIZE",
  446: };
  447: 
  448: 
  449: 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) /* {{{ */
  450: {
  451: #ifndef PDO_USE_MYSQLND
  452: 	PDO_MYSQL_PARAM_BIND *b;
  453: #endif
  454: 	pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt->driver_data;
  455: 
  456: 	PDO_DBG_ENTER("pdo_mysql_stmt_param_hook");
  457: 	PDO_DBG_INF_FMT("stmt=%p", S->stmt);
  458: 	PDO_DBG_INF_FMT("event = %s", pdo_param_event_names[event_type]);
  459: 	if (S->stmt && param->is_param) {
  460: 		switch (event_type) {
  461: 			case PDO_PARAM_EVT_ALLOC:
  462: 				/* sanity check parameter number range */
  463: 				if (param->paramno < 0 || param->paramno >= S->num_params) {
  464: 					strcpy(stmt->error_code, "HY093");
  465: 					PDO_DBG_RETURN(0);
  466: 				}
  467: 				S->params_given++;
  468: 
  469: #ifndef PDO_USE_MYSQLND
  470: 				b = &S->params[param->paramno];
  471: 				param->driver_data = b;
  472: 				b->is_null = &S->in_null[param->paramno];
  473: 				b->length = &S->in_length[param->paramno];
  474: 				/* recall how many parameters have been provided */
  475: #endif
  476: 				PDO_DBG_RETURN(1);
  477: 
  478: 			case PDO_PARAM_EVT_EXEC_PRE:
  479: 				if (S->params_given < (unsigned int) S->num_params) {
  480: 					/* too few parameter bound */
  481: 					PDO_DBG_ERR("too few parameters bound");
  482: 					strcpy(stmt->error_code, "HY093");
  483: 					PDO_DBG_RETURN(0);
  484: 				}
  485: 
  486: #if PDO_USE_MYSQLND
  487: 				if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_NULL ||
  488: 						Z_TYPE_P(param->parameter) == IS_NULL) {
  489: 					mysqlnd_stmt_bind_one_param(S->stmt, param->paramno, param->parameter, MYSQL_TYPE_NULL);
  490: 					PDO_DBG_RETURN(1);
  491: 				}
  492: #else
  493: 				b = (PDO_MYSQL_PARAM_BIND*)param->driver_data;
  494: 				*b->is_null = 0;
  495: 				if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_NULL ||
  496: 						Z_TYPE_P(param->parameter) == IS_NULL) {
  497: 					*b->is_null = 1;
  498: 					b->buffer_type = MYSQL_TYPE_STRING;
  499: 					b->buffer = NULL;
  500: 					b->buffer_length = 0;
  501: 					*b->length = 0;
  502: 					PDO_DBG_RETURN(1);
  503: 				}
  504: #endif /* PDO_USE_MYSQLND */
  505: 
  506: 				switch (PDO_PARAM_TYPE(param->param_type)) {
  507: 					case PDO_PARAM_STMT:
  508: 						PDO_DBG_RETURN(0);
  509: 					case PDO_PARAM_LOB:
  510: 						PDO_DBG_INF("PDO_PARAM_LOB");
  511: 						if (Z_TYPE_P(param->parameter) == IS_RESOURCE) {
  512: 							php_stream *stm;
  513: 							php_stream_from_zval_no_verify(stm, &param->parameter);
  514: 							if (stm) {
  515: 								SEPARATE_ZVAL_IF_NOT_REF(&param->parameter);
  516: 								Z_TYPE_P(param->parameter) = IS_STRING;
  517: 								Z_STRLEN_P(param->parameter) = php_stream_copy_to_mem(stm,
  518: 									&Z_STRVAL_P(param->parameter), PHP_STREAM_COPY_ALL, 0);
  519: 							} else {
  520: 								pdo_raise_impl_error(stmt->dbh, stmt, "HY105", "Expected a stream resource" TSRMLS_CC);
  521: 								return 0;
  522: 							}
  523: 						}
  524: 						/* fall through */
  525: 
  526: 					default:
  527: 						;
  528: 				}
  529: 
  530: #if PDO_USE_MYSQLND
  531: 				/* Is it really correct to check the zval's type? - But well, that's what the old code below does, too */
  532: 				PDO_DBG_INF_FMT("param->parameter->type=%d", Z_TYPE_P(param->parameter));
  533: 				switch (Z_TYPE_P(param->parameter)) {
  534: 					case IS_STRING:
  535: 						mysqlnd_stmt_bind_one_param(S->stmt, param->paramno, param->parameter, MYSQL_TYPE_VAR_STRING);
  536: 						break;
  537: 					case IS_LONG:
  538: #if SIZEOF_LONG==8
  539: 						mysqlnd_stmt_bind_one_param(S->stmt, param->paramno, param->parameter, MYSQL_TYPE_LONGLONG);
  540: #elif SIZEOF_LONG==4
  541: 						mysqlnd_stmt_bind_one_param(S->stmt, param->paramno, param->parameter, MYSQL_TYPE_LONG);
  542: #endif /* SIZEOF_LONG */
  543: 						break;
  544: 					case IS_DOUBLE:
  545: 						mysqlnd_stmt_bind_one_param(S->stmt, param->paramno, param->parameter, MYSQL_TYPE_DOUBLE);
  546: 						break;
  547: 					default:
  548: 						PDO_DBG_RETURN(0);
  549: 				}
  550: 
  551: 				PDO_DBG_RETURN(1);
  552: #else
  553: 				PDO_DBG_INF_FMT("param->parameter->type=%d", Z_TYPE_P(param->parameter));
  554: 				switch (Z_TYPE_P(param->parameter)) {
  555: 					case IS_STRING:
  556: 						b->buffer_type = MYSQL_TYPE_STRING;
  557: 						b->buffer = Z_STRVAL_P(param->parameter);
  558: 						b->buffer_length = Z_STRLEN_P(param->parameter);
  559: 						*b->length = Z_STRLEN_P(param->parameter);
  560: 						PDO_DBG_RETURN(1);
  561: 
  562: 					case IS_LONG:
  563: 						b->buffer_type = MYSQL_TYPE_LONG;
  564: 						b->buffer = &Z_LVAL_P(param->parameter);
  565: 						PDO_DBG_RETURN(1);
  566: 
  567: 					case IS_DOUBLE:
  568: 						b->buffer_type = MYSQL_TYPE_DOUBLE;
  569: 						b->buffer = &Z_DVAL_P(param->parameter);
  570: 						PDO_DBG_RETURN(1);
  571: 
  572: 					default:
  573: 						PDO_DBG_RETURN(0);
  574: 				}
  575: #endif /* PDO_USE_MYSQLND */
  576: 		case PDO_PARAM_EVT_FREE:
  577: 		case PDO_PARAM_EVT_EXEC_POST:
  578: 		case PDO_PARAM_EVT_FETCH_PRE:
  579: 		case PDO_PARAM_EVT_FETCH_POST:
  580: 		case PDO_PARAM_EVT_NORMALIZE:
  581: 			/* do nothing */
  582: 			break;
  583: 		}
  584: 	}
  585: 
  586: 	PDO_DBG_RETURN(1);
  587: }
  588: /* }}} */
  589: 
  590: static int pdo_mysql_stmt_fetch(pdo_stmt_t *stmt, enum pdo_fetch_orientation ori, long offset TSRMLS_DC) /* {{{ */
  591: {
  592: 	pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt->driver_data;
  593: #if PDO_USE_MYSQLND
  594: 	zend_bool fetched_anything;
  595: 
  596: 	PDO_DBG_ENTER("pdo_mysql_stmt_fetch");
  597: 	PDO_DBG_INF_FMT("stmt=%p", S->stmt);
  598: 	if (S->stmt) {
  599: 		if (FAIL == mysqlnd_stmt_fetch(S->stmt, &fetched_anything) || fetched_anything == FALSE) {
  600: 			PDO_DBG_RETURN(0);
  601: 		}
  602: 
  603: 		PDO_DBG_RETURN(1);
  604: 	}
  605: #else
  606: 	int ret;
  607: 
  608: 	if (S->stmt) {
  609: 		ret = mysql_stmt_fetch(S->stmt);
  610: 
  611: #		ifdef MYSQL_DATA_TRUNCATED
  612: 		if (ret == MYSQL_DATA_TRUNCATED) {
  613: 			ret = 0;
  614: 		}
  615: #		endif
  616: 
  617: 		if (ret) {
  618: 			if (ret != MYSQL_NO_DATA) {
  619: 				pdo_mysql_error_stmt(stmt);
  620: 			}
  621: 			PDO_DBG_RETURN(0);
  622: 		}
  623: 
  624: 		PDO_DBG_RETURN(1);
  625: 	}
  626: #endif /* PDO_USE_MYSQLND */
  627: 
  628: 	if (!S->result) {
  629: 		strcpy(stmt->error_code, "HY000");
  630: 		PDO_DBG_RETURN(0);
  631: 	}
  632: #if PDO_USE_MYSQLND
  633: 	if (!S->stmt && S->current_data) {
  634: 		mnd_free(S->current_data);
  635: 	}
  636: #endif /* PDO_USE_MYSQLND */
  637: 
  638: 	if ((S->current_data = mysql_fetch_row(S->result)) == NULL) {
  639: #if PDO_USE_MYSQLND
  640: 		if (S->result->unbuf && !S->result->unbuf->eof_reached && mysql_errno(S->H->server)) {
  641: #else
  642: 		if (!S->result->eof && mysql_errno(S->H->server)) {
  643: #endif
  644: 			pdo_mysql_error_stmt(stmt);
  645: 		}
  646: 		PDO_DBG_RETURN(0);
  647: 	}
  648: 
  649: 	S->current_lengths = mysql_fetch_lengths(S->result);
  650: 	PDO_DBG_RETURN(1);
  651: }
  652: /* }}} */
  653: 
  654: static int pdo_mysql_stmt_describe(pdo_stmt_t *stmt, int colno TSRMLS_DC) /* {{{ */
  655: {
  656: 	pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt->driver_data;
  657: 	struct pdo_column_data *cols = stmt->columns;
  658: 	int i;
  659: 
  660: 	PDO_DBG_ENTER("pdo_mysql_stmt_describe");
  661: 	PDO_DBG_INF_FMT("stmt=%p", S->stmt);
  662: 	if (!S->result) {
  663: 		PDO_DBG_RETURN(0);
  664: 	}
  665: 
  666: 	if (colno >= stmt->column_count) {
  667: 		/* error invalid column */
  668: 		PDO_DBG_RETURN(0);
  669: 	}
  670: 
  671: 	/* fetch all on demand, this seems easiest
  672: 	** if we've been here before bail out
  673: 	*/
  674: 	if (cols[0].name) {
  675: 		PDO_DBG_RETURN(1);
  676: 	}
  677: 	for (i = 0; i < stmt->column_count; i++) {
  678: 		int namelen;
  679: 
  680: 		if (S->H->fetch_table_names) {
  681: 			namelen = spprintf(&cols[i].name, 0, "%s.%s", S->fields[i].table, S->fields[i].name);
  682: 			cols[i].namelen = namelen;
  683: 		} else {
  684: 			namelen = strlen(S->fields[i].name);
  685: 			cols[i].namelen = namelen;
  686: 			cols[i].name = estrndup(S->fields[i].name, namelen);
  687: 		}
  688: 
  689: 		cols[i].precision = S->fields[i].decimals;
  690: 		cols[i].maxlen = S->fields[i].length;
  691: 
  692: #ifdef PDO_USE_MYSQLND
  693: 		if (S->stmt) {
  694: 			cols[i].param_type = PDO_PARAM_ZVAL;
  695: 		} else
  696: #endif
  697: 		{
  698: 			cols[i].param_type = PDO_PARAM_STR;
  699: 		}
  700: 	}
  701: 	PDO_DBG_RETURN(1);
  702: }
  703: /* }}} */
  704: 
  705: static int pdo_mysql_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, unsigned long *len, int *caller_frees TSRMLS_DC) /* {{{ */
  706: {
  707: 	pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt->driver_data;
  708: 
  709: 	PDO_DBG_ENTER("pdo_mysql_stmt_get_col");
  710: 	PDO_DBG_INF_FMT("stmt=%p", S->stmt);
  711: 	if (!S->result) {
  712: 		PDO_DBG_RETURN(0);
  713: 	}
  714: 
  715: 	/* With mysqlnd data is stored inside mysqlnd, not S->current_data */
  716: 	if (!S->stmt) {
  717: 		if (S->current_data == NULL || !S->result) {
  718: 			PDO_DBG_RETURN(0);
  719: 		}
  720: 	}
  721: 
  722: 	if (colno >= stmt->column_count) {
  723: 		/* error invalid column */
  724: 		PDO_DBG_RETURN(0);
  725: 	}
  726: #if PDO_USE_MYSQLND
  727: 	if (S->stmt) {
  728: 		Z_ADDREF_P(S->stmt->data->result_bind[colno].zv);
  729: 		*ptr = (char*)&S->stmt->data->result_bind[colno].zv;
  730: 		*len = sizeof(zval);
  731: 		PDO_DBG_RETURN(1);
  732: 	}
  733: #else
  734: 	if (S->stmt) {
  735: 		if (S->out_null[colno]) {
  736: 			*ptr = NULL;
  737: 			*len = 0;
  738: 			PDO_DBG_RETURN(1);
  739: 		}
  740: 		*ptr = S->bound_result[colno].buffer;
  741: 		if (S->out_length[colno] > S->bound_result[colno].buffer_length) {
  742: 			/* mysql lied about the column width */
  743: 			strcpy(stmt->error_code, "01004"); /* truncated */
  744: 			S->out_length[colno] = S->bound_result[colno].buffer_length;
  745: 			*len = S->out_length[colno];
  746: 			PDO_DBG_RETURN(0);
  747: 		}
  748: 		*len = S->out_length[colno];
  749: 		PDO_DBG_RETURN(1);
  750: 	}
  751: #endif
  752: 	*ptr = S->current_data[colno];
  753: 	*len = S->current_lengths[colno];
  754: 	PDO_DBG_RETURN(1);
  755: } /* }}} */
  756: 
  757: static char *type_to_name_native(int type) /* {{{ */
  758: {
  759: #define PDO_MYSQL_NATIVE_TYPE_NAME(x)	case FIELD_TYPE_##x: return #x;
  760: 
  761:     switch (type) {
  762:         PDO_MYSQL_NATIVE_TYPE_NAME(STRING)
  763:         PDO_MYSQL_NATIVE_TYPE_NAME(VAR_STRING)
  764: #ifdef FIELD_TYPE_TINY
  765:         PDO_MYSQL_NATIVE_TYPE_NAME(TINY)
  766: #endif
  767: #ifdef FIELD_TYPE_BIT
  768:         PDO_MYSQL_NATIVE_TYPE_NAME(BIT)
  769: #endif
  770:         PDO_MYSQL_NATIVE_TYPE_NAME(SHORT)
  771:         PDO_MYSQL_NATIVE_TYPE_NAME(LONG)
  772:         PDO_MYSQL_NATIVE_TYPE_NAME(LONGLONG)
  773:         PDO_MYSQL_NATIVE_TYPE_NAME(INT24)
  774:         PDO_MYSQL_NATIVE_TYPE_NAME(FLOAT)
  775:         PDO_MYSQL_NATIVE_TYPE_NAME(DOUBLE)
  776:         PDO_MYSQL_NATIVE_TYPE_NAME(DECIMAL)
  777: #ifdef FIELD_TYPE_NEWDECIMAL
  778:         PDO_MYSQL_NATIVE_TYPE_NAME(NEWDECIMAL)
  779: #endif
  780: #ifdef FIELD_TYPE_GEOMETRY
  781:         PDO_MYSQL_NATIVE_TYPE_NAME(GEOMETRY)
  782: #endif
  783:         PDO_MYSQL_NATIVE_TYPE_NAME(TIMESTAMP)
  784: #ifdef FIELD_TYPE_YEAR
  785:         PDO_MYSQL_NATIVE_TYPE_NAME(YEAR)
  786: #endif
  787:         PDO_MYSQL_NATIVE_TYPE_NAME(SET)
  788:         PDO_MYSQL_NATIVE_TYPE_NAME(ENUM)
  789:         PDO_MYSQL_NATIVE_TYPE_NAME(DATE)
  790: #ifdef FIELD_TYPE_NEWDATE
  791:         PDO_MYSQL_NATIVE_TYPE_NAME(NEWDATE)
  792: #endif
  793:         PDO_MYSQL_NATIVE_TYPE_NAME(TIME)
  794:         PDO_MYSQL_NATIVE_TYPE_NAME(DATETIME)
  795:         PDO_MYSQL_NATIVE_TYPE_NAME(TINY_BLOB)
  796:         PDO_MYSQL_NATIVE_TYPE_NAME(MEDIUM_BLOB)
  797:         PDO_MYSQL_NATIVE_TYPE_NAME(LONG_BLOB)
  798:         PDO_MYSQL_NATIVE_TYPE_NAME(BLOB)
  799:         PDO_MYSQL_NATIVE_TYPE_NAME(NULL)
  800:         default:
  801:             return NULL;
  802:     }
  803: #undef PDO_MYSQL_NATIVE_TYPE_NAME
  804: } /* }}} */
  805: 
  806: static int pdo_mysql_stmt_col_meta(pdo_stmt_t *stmt, long colno, zval *return_value TSRMLS_DC) /* {{{ */
  807: {
  808: 	pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt->driver_data;
  809: 	const MYSQL_FIELD *F;
  810: 	zval *flags;
  811: 	char *str;
  812: 
  813: 	PDO_DBG_ENTER("pdo_mysql_stmt_col_meta");
  814: 	PDO_DBG_INF_FMT("stmt=%p", S->stmt);
  815: 	if (!S->result) {
  816: 		PDO_DBG_RETURN(FAILURE);
  817: 	}
  818: 	if (colno >= stmt->column_count) {
  819: 		/* error invalid column */
  820: 		PDO_DBG_RETURN(FAILURE);
  821: 	}
  822: 
  823: 	array_init(return_value);
  824: 	MAKE_STD_ZVAL(flags);
  825: 	array_init(flags);
  826: 
  827: 	F = S->fields + colno;
  828: 
  829: 	if (F->def) {
  830: 		add_assoc_string(return_value, "mysql:def", F->def, 1);
  831: 	}
  832: 	if (IS_NOT_NULL(F->flags)) {
  833: 		add_next_index_string(flags, "not_null", 1);
  834: 	}
  835: 	if (IS_PRI_KEY(F->flags)) {
  836: 		add_next_index_string(flags, "primary_key", 1);
  837: 	}
  838: 	if (F->flags & MULTIPLE_KEY_FLAG) {
  839: 		add_next_index_string(flags, "multiple_key", 1);
  840: 	}
  841: 	if (F->flags & UNIQUE_KEY_FLAG) {
  842: 		add_next_index_string(flags, "unique_key", 1);
  843: 	}
  844: 	if (IS_BLOB(F->flags)) {
  845: 		add_next_index_string(flags, "blob", 1);
  846: 	}
  847: 	str = type_to_name_native(F->type);
  848: 	if (str) {
  849: 		add_assoc_string(return_value, "native_type", str, 1);
  850: 	}
  851: 
  852: #ifdef PDO_USE_MYSQLND
  853: 	switch (F->type) {
  854: 		case MYSQL_TYPE_BIT:
  855: 		case MYSQL_TYPE_YEAR:
  856: 		case MYSQL_TYPE_TINY:
  857: 		case MYSQL_TYPE_SHORT:
  858: 		case MYSQL_TYPE_INT24:
  859: 		case MYSQL_TYPE_LONG:
  860: #if SIZEOF_LONG==8
  861: 		case MYSQL_TYPE_LONGLONG:
  862: #endif
  863: 			add_assoc_long(return_value, "pdo_type", PDO_PARAM_INT);
  864: 			break;
  865: 		default:
  866: 			add_assoc_long(return_value, "pdo_type", PDO_PARAM_STR);
  867: 			break;
  868: 	}
  869: #endif
  870: 
  871: 	add_assoc_zval(return_value, "flags", flags);
  872: 	add_assoc_string(return_value, "table", (char *) (F->table?F->table:""), 1);
  873: 	PDO_DBG_RETURN(SUCCESS);
  874: } /* }}} */
  875: 
  876: static int pdo_mysql_stmt_cursor_closer(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
  877: {
  878: 	pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt->driver_data;
  879: 
  880: 	PDO_DBG_ENTER("pdo_mysql_stmt_cursor_closer");
  881: 	PDO_DBG_INF_FMT("stmt=%p", S->stmt);
  882: 	if (S->result) {
  883: 		mysql_free_result(S->result);
  884: 		S->result = NULL;
  885: 	}
  886: 	if (S->stmt) {
  887: 		int retval;
  888: 		retval = mysql_stmt_free_result(S->stmt);
  889: 		PDO_DBG_RETURN(retval ? 0 : 1);
  890: 	}
  891: 
  892: 	while (mysql_more_results(S->H->server)) {
  893: 		MYSQL_RES *res;
  894: 		if (mysql_next_result(S->H->server) != 0) {
  895: 			break;
  896: 		}
  897: 		res = mysql_store_result(S->H->server);
  898: 		if (res) {
  899: 			mysql_free_result(res);
  900: 		}
  901: 	}
  902: 	PDO_DBG_RETURN(1);
  903: }
  904: /* }}} */
  905: 
  906: struct pdo_stmt_methods mysql_stmt_methods = {
  907: 	pdo_mysql_stmt_dtor,
  908: 	pdo_mysql_stmt_execute,
  909: 	pdo_mysql_stmt_fetch,
  910: 	pdo_mysql_stmt_describe,
  911: 	pdo_mysql_stmt_get_col,
  912: 	pdo_mysql_stmt_param_hook,
  913: 	NULL, /* set_attr */
  914: 	NULL, /* get_attr */
  915: 	pdo_mysql_stmt_col_meta,
  916: 	pdo_mysql_stmt_next_rowset,
  917: 	pdo_mysql_stmt_cursor_closer
  918: };
  919: 
  920: /*
  921:  * Local variables:
  922:  * tab-width: 4
  923:  * c-basic-offset: 4
  924:  * End:
  925:  * vim600: noet sw=4 ts=4 fdm=marker
  926:  * vim<600: noet sw=4 ts=4
  927:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>