⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mysqlnd_ps.c

📁 linux下安装不上mysql5与php5的可用此关联
💻 C
📖 第 1 页 / 共 3 页
字号:
mysqlnd_fetch_stmt_row_buffered(MYSQLND_RES *result, void *param, unsigned int flags,								zend_bool *fetched_anything TSRMLS_DC){	unsigned int i;	MYSQLND_STMT *stmt = (MYSQLND_STMT *) param;	/* If we haven't read everything */	if (result->data->data_cursor &&		(result->data->data_cursor - result->data->data) < result->data->row_count)	{		/* The user could have skipped binding - don't crash*/		if (stmt->result_bind) {			zval **current_row = *result->data->data_cursor;			for (i = 0; i < result->field_count; i++) {				/* copy the type */				if (stmt->result_bind[i].bound == TRUE) {					if (Z_TYPE_P(current_row[i]) != IS_NULL) {						/*						  Copy the value.						  Pre-condition is that the zvals in the result_bind buffer						  have been  ZVAL_NULL()-ed or to another simple type						  (int, double, bool but not string). Because of the reference						  counting the user can't delete the strings the variables point to.						*/						Z_TYPE_P(stmt->result_bind[i].zv) = Z_TYPE_P(current_row[i]);						stmt->result_bind[i].zv->value = current_row[i]->value;					} else {						ZVAL_NULL(stmt->result_bind[i].zv);					}				}			}		}		result->data->data_cursor++;		*fetched_anything = TRUE;	} else {		result->data->data_cursor = NULL;		*fetched_anything = FALSE;#ifndef MYSQLND_SILENT		php_printf("NO MORE DATA\n ");#endif	}	return PASS;}/* }}} *//* {{{ mysqlnd_stmt_fetch_row_unbuffered */enum_func_statusmysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES *result, void *param, unsigned int flags,								zend_bool *fetched_anything TSRMLS_DC){	enum_func_status ret;	MYSQLND_STMT *stmt = (MYSQLND_STMT *) param;	unsigned int i, field_count = result->field_count;	php_mysql_packet_row *row_packet = result->row_packet;	if (result->unbuf->eof_reached) {		/* No more rows obviously */		*fetched_anything = FALSE;		return PASS;	}	if (result->conn->state != CONN_FETCHING_DATA) {		SET_CLIENT_ERROR(result->conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE,						 mysqlnd_out_of_sync); 		return FAIL;	}	/* Let the row packet fill our buffer and skip additional malloc + memcpy */	row_packet->skip_extraction = stmt && stmt->result_bind? FALSE:TRUE;	/*	  If we skip rows (stmt == NULL || stmt->result_bind == NULL) we have to	  mysqlnd_unbuffered_free_last_data() before it. The function returns always true.	*/	if (PASS == (ret = PACKET_READ(row_packet, result->conn)) && !row_packet->eof) {		result->unbuf->row_count++;		*fetched_anything = TRUE;		if (!row_packet->skip_extraction) {			mysqlnd_unbuffered_free_last_data(result TSRMLS_CC);			result->unbuf->last_row_data = row_packet->fields;			result->unbuf->last_row_buffer = row_packet->row_buffer;			row_packet->fields = NULL;			row_packet->row_buffer = NULL;			for (i = 0; i < field_count; i++) {				if (stmt->result_bind[i].bound == TRUE) {					zval *data = result->unbuf->last_row_data[i];					/*					  stmt->result_bind[i].zv has been already destructed					  in mysqlnd_unbuffered_free_last_data()					*/					if (IS_NULL != (Z_TYPE_P(stmt->result_bind[i].zv) = Z_TYPE_P(data)) ) {						stmt->result_bind[i].zv->value = data->value;						if (							(Z_TYPE_P(data) == IS_STRING#if PHP_MAJOR_VERSION >= 6							|| Z_TYPE_P(data) == IS_UNICODE#endif							)							 && (result->meta->fields[i].max_length < Z_STRLEN_P(data)))						{							result->meta->fields[i].max_length = Z_STRLEN_P(data);						}					}				}			}		} else {			/*			  Data has been allocated and usually mysqlnd_unbuffered_free_last_data()			  frees it but we can't call this function as it will cause problems with			  the bound variables. Thus we need to do part of what it does or Zend will			  report leaks.			*/			efree(row_packet->row_buffer);			row_packet->row_buffer = NULL;		}	}	/* Mark the connection as usable again */	if (row_packet->eof) {		result->unbuf->eof_reached = TRUE;		result->conn->upsert_status.warning_count = row_packet->warning_count;		result->conn->upsert_status.server_status = row_packet->server_status;		/*		  result->row_packet will be cleaned when		  destroying the result object		*/		if (result->conn->upsert_status.server_status & SERVER_MORE_RESULTS_EXISTS) {			result->conn->state = CONN_NEXT_RESULT_PENDING;		} else {			result->conn->state = CONN_READY;		}		*fetched_anything = FALSE;	}	return ret;}/* }}} *//* {{{ mysqlnd_stmt_use_result */MYSQLND_RES * _mysqlnd_stmt_use_result(MYSQLND_STMT *stmt TSRMLS_DC){	MYSQLND_RES *result;	MYSQLND *conn = stmt->conn;	if (!stmt->field_count ||		(!stmt->cursor_exists && conn->state != CONN_FETCHING_DATA) ||		(stmt->cursor_exists && conn->state != CONN_READY) ||		(stmt->state != MYSQLND_STMT_WAITING_USE_OR_STORE))	{		SET_CLIENT_ERROR(conn->error_info, CR_COMMANDS_OUT_OF_SYNC,						 UNKNOWN_SQLSTATE, mysqlnd_out_of_sync); 		return NULL;	}	MYSQLND_INC_CONN_STATISTIC(&stmt->conn->stats, STAT_PS_UNBUFFERED_SETS);	result					= stmt->result;	result->type 			= MYSQLND_RES_PS;	result->m.fetch_row		= stmt->cursor_exists? mysqlnd_fetch_stmt_row_cursor:													mysqlnd_stmt_fetch_row_unbuffered;	result->m.fetch_lengths	= NULL; /* makes no sense */	result->zval_cache		= NULL;	result->unbuf	= ecalloc(1, sizeof(MYSQLND_RES_UNBUFFERED));	/*	  Will be freed in the mysqlnd_internal_free_result_contents() called	  by the resource destructor. mysqlnd_fetch_row_unbuffered() expects	  this to be not NULL.	*/	PACKET_INIT(result->row_packet, PROT_ROW_PACKET, php_mysql_packet_row *);	result->row_packet->field_count = result->field_count;	result->row_packet->binary_protocol = TRUE;	result->row_packet->fields_metadata = stmt->result->meta->fields;	result->lengths = NULL;	stmt->state = MYSQLND_STMT_USE_OR_STORE_CALLED;	/* No multithreading issues as we don't share the connection :) */	return result;}/* }}} */#define STMT_ID_LENGTH 4/* {{{ mysqlnd_fetch_row_cursor */enum_func_statusmysqlnd_fetch_stmt_row_cursor(MYSQLND_RES *result, void *param, unsigned int flags,							  zend_bool *fetched_anything TSRMLS_DC){	enum_func_status ret;	MYSQLND_STMT *stmt = (MYSQLND_STMT *) param;	zend_uchar buf[STMT_ID_LENGTH /* statement id */ + 4 /* number of rows to fetch */];	php_mysql_packet_row *row_packet = result->row_packet;	if (!stmt) {		return FAIL;	}	if (stmt->state < MYSQLND_STMT_USER_FETCHING) {		/* Only initted - error */		SET_CLIENT_ERROR(stmt->conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE,						mysqlnd_out_of_sync);		return FAIL;	}	int4store(buf, stmt->stmt_id);	int4store(buf + STMT_ID_LENGTH, 1); /* for now fetch only one row */	if (FAIL == mysqlnd_simple_command(stmt->conn, COM_STMT_FETCH, (char *)buf, sizeof(buf),									   PROT_LAST /* we will handle the response packet*/,									   FALSE TSRMLS_CC)) {		stmt->error_info = stmt->conn->error_info;		return FAIL;	}	row_packet->skip_extraction = stmt->result_bind? FALSE:TRUE;	if (PASS == (ret = PACKET_READ(row_packet, result->conn)) && !row_packet->eof) {		unsigned int i, field_count = result->field_count;		mysqlnd_unbuffered_free_last_data(result TSRMLS_CC);		result->unbuf->last_row_data = row_packet->fields;		result->unbuf->last_row_buffer = row_packet->row_buffer;		row_packet->fields = NULL;		row_packet->row_buffer = NULL;		if (!row_packet->skip_extraction) {			/* If no result bind, do nothing. We consumed the data */			for (i = 0; i < field_count; i++) {				if (stmt->result_bind[i].bound == TRUE) {					zval *data = result->unbuf->last_row_data[i];					/*					  stmt->result_bind[i].zv has been already destructed					  in mysqlnd_unbuffered_free_last_data()					*/					if (IS_NULL != (Z_TYPE_P(stmt->result_bind[i].zv) = Z_TYPE_P(data)) ) {						stmt->result_bind[i].zv->value = data->value;						if ((Z_TYPE_P(data) == IS_STRING#if PHP_MAJOR_VERSION >= 6							|| Z_TYPE_P(data) == IS_UNICODE#endif							)							 && (result->meta->fields[i].max_length < Z_STRLEN_P(data)))						{							result->meta->fields[i].max_length = Z_STRLEN_P(data);						}					}				}			}		}		result->unbuf->row_count++;		*fetched_anything = TRUE;		/* We asked for one row, the next one should be EOF, eat it */		ret = PACKET_READ(row_packet, result->conn);		if (row_packet->row_buffer) {			efree(row_packet->row_buffer);			row_packet->row_buffer = NULL;		}	} else {		*fetched_anything = FALSE;		stmt->upsert_status.warning_count =			stmt->conn->upsert_status.warning_count =				row_packet->warning_count;		stmt->upsert_status.server_status = 			stmt->conn->upsert_status.server_status =				row_packet->server_status;		result->unbuf->eof_reached = row_packet->eof;	}	stmt->upsert_status.warning_count =		stmt->conn->upsert_status.warning_count =			row_packet->warning_count;	stmt->upsert_status.server_status = 		stmt->conn->upsert_status.server_status =			row_packet->server_status;	return ret;}/* }}} *//* {{{ mysqlnd_stmt_fetch */PHPAPI enum_func_statusmysqlnd_stmt_fetch(MYSQLND_STMT * const stmt, zend_bool * const fetched_anything TSRMLS_DC){	if (!stmt->result ||		stmt->state < MYSQLND_STMT_WAITING_USE_OR_STORE) {		return FAIL;	} else if (stmt->state == MYSQLND_STMT_WAITING_USE_OR_STORE) {		/* Execute only once. We have to free the previous contents of user's bound vars */		stmt->default_rset_handler(stmt TSRMLS_CC);		stmt->state = MYSQLND_STMT_USER_FETCHING;	}	/* no else please */	/*	  The user might have not bound any variables for result.	  Do the binding once she does it.	*/	if (stmt->result_bind && !stmt->result_zvals_separated_once) {		unsigned int i;		/*		  mysqlnd_stmt_store_result() has been called free the bind		  variables to prevent leaking of their previous content.		*/		for (i = 0; i < stmt->result->field_count; i++) {			if (stmt->result_bind[i].bound == TRUE) {				zval_dtor(stmt->result_bind[i].zv);				ZVAL_NULL(stmt->result_bind[i].zv);			}		}		stmt->result_zvals_separated_once = TRUE;	}	MYSQLND_INC_CONN_STATISTIC(&stmt->conn->stats, STAT_ROWS_FETCHED_FROM_CLIENT);	return stmt->result->m.fetch_row(stmt->result, (void*)stmt, 0, fetched_anything TSRMLS_CC);}/* }}} *//* {{{ _mysqlnd_stmt_reset */static enum_func_status_mysqlnd_stmt_reset(MYSQLND_STMT * const stmt TSRMLS_DC){	enum_func_status ret = PASS;	MYSQLND * conn = stmt->conn;	zend_uchar cmd_buf[STMT_ID_LENGTH /* statement id */];	if (stmt->stmt_id) {		if (stmt->param_bind) {			unsigned int i;			/* Reset Long Data */			for (i = 0; i < stmt->param_count; i++) {				if (stmt->param_bind[i].flags & MYSQLND_PARAM_BIND_BLOB_USED) {					stmt->param_bind[i].flags &= ~MYSQLND_PARAM_BIND_BLOB_USED;				}			}		}		/*		  If the user decided to close the statement right after execute()		  We have to call the appropriate use_result() or store_result() and		  clean.		*/		if (stmt->state == MYSQLND_STMT_WAITING_USE_OR_STORE) {			stmt->default_rset_handler(stmt TSRMLS_CC);			stmt->state = MYSQLND_STMT_USER_FETCHING;		}		if (stmt->result) {			stmt->result->m.skip_result(stmt->result TSRMLS_CC);		}		/* Now the line should be free, if it wasn't */		int4store(cmd_buf, stmt->stmt_id);		if (conn->state == CONN_READY &&			FAIL == (ret = mysqlnd_simple_command(conn, COM_STMT_RESET, (char *)cmd_buf,												  sizeof(cmd_buf), PROT_OK_PACKET,												  FALSE TSRMLS_CC))) {			stmt->error_info = conn->error_info;		}		stmt->upsert_status = conn->upsert_status;		stmt->state = MYSQLND_STMT_PREPARED;	}	return ret;}/* }}} *//* {{{ _mysqlnd_stmt_send_long_data */static enum_func_status_mysqlnd_stmt_send_long_data(MYSQLND_STMT * const stmt, unsigned int param_no,							 const char * const data, unsigned long length TSRMLS_DC){	enum_func_status ret = FAIL;	MYSQLND * conn = stmt->conn;	zend_uchar *cmd_buf;	size_t packet_len;	enum php_mysqlnd_server_command cmd = COM_STMT_SEND_LONG_DATA;		if (stmt->state < MYSQLND_STMT_PREPARED || !stmt->param_bind) {		return FAIL;	}	if (param_no >= stmt->param_count) {		SET_STMT_ERROR(stmt, CR_INVALID_PARAMETER_NO, UNKNOWN_SQLSTATE, "Invalid parameter number");		return FAIL;	}	if (stmt->param_bind[param_no].type != MYSQL_TYPE_LONG_BLOB) {		SET_STMT_ERROR(stmt, CR_INVALID_BUFFER_USE, UNKNOWN_SQLSTATE, mysqlnd_not_bound_as_blob);		return FAIL;	}	/*	  XXX:	Unfortunately we have to allocate additional buffer to be able the			additional data, which is like a header inside the payload.			This should be optimised, but it will be a pervasive change, so			mysqlnd_simple_command() will accept not a buffer, but actually MYSQLND_STRING*			terminated by NULL, to send. If the strings are not big, we can collapse them			on the buffer every connection has, but otherwise we will just send them			one by one to the wire.	*/	if (conn->state == CONN_READY) {		stmt->param_bind[param_no].flags |= MYSQLND_PARAM_BIND_BLOB_USED;		cmd_buf = emalloc(packet_len = STMT_ID_LENGTH + 2 + length);		int4store(cmd_buf, stmt->stmt_id);		int2store(cmd_buf + STMT_ID_LENGTH, param_no);		memcpy(cmd_buf + STMT_ID_LENGTH + 2, data, length);		/* COM_STMT_SEND_LONG_DATA doesn't send an OK packet*/		ret = mysqlnd_simple_command(conn, cmd, (char *)cmd_buf, packet_len,									 PROT_LAST , FALSE TSRMLS_CC);		efree(cmd_buf);		if (FAIL == ret) {			stmt->error_info = conn->error_info;		}		/*		  Cover protocol error: COM_STMT_SEND_LONG_DATA was designed to be quick and not		  sent response packets. According to documentation the only way to get an error		  is to have out-of-memory on the server-side. However, that's not true, as if		  max_allowed_packet_size is smaller than the chunk being sent to the server, the		  latter will complain with an error message. However, normally we don't expect		  an error message, thus we continue. When sending the next command, which expects		  response we will read the unexpected data and error message will look weird.		  Therefore we do non-blocking read to clean the line, if there is a need.		  Nevertheless, there is a built-in protection when sending a command packet, that		  checks if the line is clear - useful for debug purposes and to be switched off		  in release builds.		  Maybe we can make it automatic by checking what's the value of		  max_allowed_packet_size on the server and resending the data.		*/#if HAVE_USLEEP		usleep(120000);#endif		if ((packet_len = php_mysqlnd_consume_uneaten_data(conn, cmd TSRMLS_CC))) {			php_error_docref(NULL TSRMLS_CC, E_WARNING, "There was an error "							 "while sending long data. Probably max_allowed_packet_size "							 "is smaller than the data. You have to increase it or send "							 "smaller chunks of data. Answer was %u bytes long.", packet_len);			SET_STMT_ERROR(stmt, CR_CONNECTION_ERROR, UNKNOWN_SQLSTATE,							"Server responded to COM_STMT_SEND_LONG_DATA.");			ret = FAIL;		}	}	return ret;}/* }}} *//* {{{ _mysqlnd_stmt_bind_param */static enum_func_status_mysqlnd_stmt_bind_param(MYSQLND_STMT * const stmt, MYSQLND_PARAM_BIND * const param_bind){	unsigned int i = 0;	if (stmt->state < MYSQLND_STMT_PREPARED) {		SET_STMT_ERROR(stmt, CR_NO_PREPARE_STMT, UNKNOWN_SQLSTATE, mysqlnd_stmt_not_prepared);		return FAIL;	}	if (stmt->param_count) {		if (!param_bind) {			SET_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE,							 "Re-binding (still) not supported");			return FAIL;		} else if (stmt->param_bind) {			/*			  There is already result bound.			  Forbid for now re-binding!!			*/			for (i = 0; i < stmt->param_count; i++) {				/* For BLOBS zv is NULL */				if (stmt->param_bind[i].zv) {					/*					  We may have the last reference, then call zval_ptr_dtor()					  or we may leak memory.					*/					zval_ptr_dtor(&stmt->param_bind[i].zv);					stmt->param_bind[i].zv = NULL;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -