@@ -476,6 +476,146 @@ PHP_FUNCTION(mysqli_stmt_execute)
476476}
477477/* }}} */
478478
479+ void close_stmt_and_copy_errors (MY_STMT * stmt , MY_MYSQL * mysql )
480+ {
481+ /* mysql_stmt_close() clears errors, so we have to store them temporarily */
482+ MYSQLND_ERROR_INFO error_info = * stmt -> stmt -> data -> error_info ;
483+ stmt -> stmt -> data -> error_info -> error_list .head = NULL ;
484+ stmt -> stmt -> data -> error_info -> error_list .tail = NULL ;
485+ stmt -> stmt -> data -> error_info -> error_list .count = 0 ;
486+
487+ /* we also remember affected_rows which gets cleared too */
488+ uint64_t affected_rows = mysql -> mysql -> data -> upsert_status -> affected_rows ;
489+
490+ mysqli_stmt_close (stmt -> stmt , false);
491+ stmt -> stmt = NULL ;
492+ php_clear_stmt_bind (stmt );
493+
494+ /* restore error messages, but into the mysql object */
495+ zend_llist_clean (& mysql -> mysql -> data -> error_info -> error_list );
496+ * mysql -> mysql -> data -> error_info = error_info ;
497+ mysql -> mysql -> data -> upsert_status -> affected_rows = affected_rows ;
498+ }
499+
500+ PHP_FUNCTION (mysqli_execute_query )
501+ {
502+ MY_MYSQL * mysql ;
503+ MY_STMT * stmt ;
504+ char * query = NULL ;
505+ size_t query_len ;
506+ zval * mysql_link ;
507+ HashTable * input_params = NULL ;
508+ MYSQL_RES * result ;
509+ MYSQLI_RESOURCE * mysqli_resource ;
510+
511+ if (zend_parse_method_parameters (ZEND_NUM_ARGS (), getThis (), "Os|h!" , & mysql_link , mysqli_link_class_entry , & query , & query_len , & input_params ) == FAILURE ) {
512+ RETURN_THROWS ();
513+ }
514+ MYSQLI_FETCH_RESOURCE_CONN (mysql , mysql_link , MYSQLI_STATUS_VALID );
515+
516+ stmt = (MY_STMT * )ecalloc (1 ,sizeof (MY_STMT ));
517+
518+ if (!(stmt -> stmt = mysql_stmt_init (mysql -> mysql ))) {
519+ MYSQLI_REPORT_MYSQL_ERROR (mysql -> mysql );
520+ efree (stmt );
521+ RETURN_FALSE ;
522+ }
523+
524+ if (FAIL == mysql_stmt_prepare (stmt -> stmt , query , query_len )) {
525+ MYSQLI_REPORT_STMT_ERROR (stmt -> stmt );
526+
527+ close_stmt_and_copy_errors (stmt , mysql );
528+ RETURN_FALSE ;
529+ }
530+
531+ /* The bit below, which is copied from mysqli_prepare, is needed for bad index exceptions */
532+ /* don't initialize stmt->query with NULL, we ecalloc()-ed the memory */
533+ /* Get performance boost if reporting is switched off */
534+ if (query_len && (MyG (report_mode ) & MYSQLI_REPORT_INDEX )) {
535+ stmt -> query = estrdup (query );
536+ }
537+
538+ // bind-in-execute
539+ // It's very similar to the mysqli_stmt::execute, but it uses different error handling
540+ if (input_params ) {
541+ zval * tmp ;
542+ unsigned int index ;
543+ unsigned int hash_num_elements ;
544+ unsigned int param_count ;
545+ MYSQLND_PARAM_BIND * params ;
546+
547+ if (!zend_array_is_list (input_params )) {
548+ mysqli_stmt_close (stmt -> stmt , false);
549+ stmt -> stmt = NULL ;
550+ efree (stmt );
551+ zend_argument_value_error (ERROR_ARG_POS (3 ), "must be a list array" );
552+ RETURN_THROWS ();
553+ }
554+
555+ hash_num_elements = zend_hash_num_elements (input_params );
556+ param_count = mysql_stmt_param_count (stmt -> stmt );
557+ if (hash_num_elements != param_count ) {
558+ mysqli_stmt_close (stmt -> stmt , false);
559+ stmt -> stmt = NULL ;
560+ efree (stmt );
561+ zend_argument_value_error (ERROR_ARG_POS (3 ), "must consist of exactly %d elements, %d present" , param_count , hash_num_elements );
562+ RETURN_THROWS ();
563+ }
564+
565+ params = mysqlnd_stmt_alloc_param_bind (stmt -> stmt );
566+ ZEND_ASSERT (params );
567+
568+ index = 0 ;
569+ ZEND_HASH_FOREACH_VAL (input_params , tmp ) {
570+ ZVAL_COPY_VALUE (& params [index ].zv , tmp );
571+ params [index ].type = MYSQL_TYPE_VAR_STRING ;
572+ index ++ ;
573+ } ZEND_HASH_FOREACH_END ();
574+
575+ if (mysqlnd_stmt_bind_param (stmt -> stmt , params )) {
576+ close_stmt_and_copy_errors (stmt , mysql );
577+ RETURN_FALSE ;
578+ }
579+
580+ }
581+
582+ if (mysql_stmt_execute (stmt -> stmt )) {
583+ MYSQLI_REPORT_STMT_ERROR (stmt -> stmt );
584+
585+ if (MyG (report_mode ) & MYSQLI_REPORT_INDEX ) {
586+ php_mysqli_report_index (stmt -> query , mysqli_stmt_server_status (stmt -> stmt ));
587+ }
588+
589+ close_stmt_and_copy_errors (stmt , mysql );
590+ RETURN_FALSE ;
591+ }
592+
593+ if (!mysql_stmt_field_count (stmt -> stmt )) {
594+ /* no result set - not a SELECT */
595+ close_stmt_and_copy_errors (stmt , mysql );
596+ RETURN_TRUE ;
597+ }
598+
599+ if (MyG (report_mode ) & MYSQLI_REPORT_INDEX ) {
600+ php_mysqli_report_index (stmt -> query , mysqli_stmt_server_status (stmt -> stmt ));
601+ }
602+
603+ /* get result */
604+ if (!(result = mysqlnd_stmt_get_result (stmt -> stmt ))) {
605+ MYSQLI_REPORT_STMT_ERROR (stmt -> stmt );
606+
607+ close_stmt_and_copy_errors (stmt , mysql );
608+ RETURN_FALSE ;
609+ }
610+
611+ mysqli_resource = (MYSQLI_RESOURCE * )ecalloc (1 , sizeof (MYSQLI_RESOURCE ));
612+ mysqli_resource -> ptr = (void * )result ;
613+ mysqli_resource -> status = MYSQLI_STATUS_VALID ;
614+ MYSQLI_RETVAL_RESOURCE (mysqli_resource , mysqli_result_class_entry );
615+
616+ close_stmt_and_copy_errors (stmt , mysql );
617+ }
618+
479619/* {{{ mixed mysqli_stmt_fetch_mysqlnd */
480620void mysqli_stmt_fetch_mysqlnd (INTERNAL_FUNCTION_PARAMETERS )
481621{
@@ -1188,9 +1328,7 @@ PHP_FUNCTION(mysqli_prepare)
11881328 /* don't initialize stmt->query with NULL, we ecalloc()-ed the memory */
11891329 /* Get performance boost if reporting is switched off */
11901330 if (stmt -> stmt && query_len && (MyG (report_mode ) & MYSQLI_REPORT_INDEX )) {
1191- stmt -> query = (char * )emalloc (query_len + 1 );
1192- memcpy (stmt -> query , query , query_len );
1193- stmt -> query [query_len ] = '\0' ;
1331+ stmt -> query = estrdup (query );
11941332 }
11951333
11961334 /* don't join to the previous if because it won't work if mysql_stmt_prepare_fails */
0 commit comments