@@ -711,6 +711,87 @@ function ( string $sql, array $params ) {
711711 );
712712 }
713713
714+ /**
715+ * PDO API: Translate and execute a MySQL query in SQLite.
716+ *
717+ * A single MySQL query can be translated into zero or more SQLite queries.
718+ *
719+ * @param string $query Full SQL statement string.
720+ * @param int $fetch_mode PDO fetch mode. Default is PDO::FETCH_OBJ.
721+ * @param array ...$fetch_mode_args Additional fetch mode arguments.
722+ *
723+ * @return mixed Return value, depending on the query type.
724+ *
725+ * @throws WP_SQLite_Driver_Exception When the query execution fails.
726+ */
727+ #[ReturnTypeWillChange]
728+ public function query ( string $ query , ?int $ fetch_mode = PDO ::FETCH_COLUMN , ...$ fetch_mode_args ) {
729+ $ this ->flush ();
730+ $ this ->pdo_fetch_mode = $ fetch_mode ;
731+ $ this ->last_mysql_query = $ query ;
732+
733+ try {
734+ // Parse the MySQL query.
735+ $ parser = $ this ->create_parser ( $ query );
736+ $ parser ->next_query ();
737+ $ ast = $ parser ->get_query_ast ();
738+ if ( null === $ ast ) {
739+ throw $ this ->new_driver_exception ( 'Failed to parse the MySQL query. ' );
740+ }
741+
742+ if ( $ parser ->next_query () ) {
743+ throw $ this ->new_driver_exception ( 'Multi-query is not supported. ' );
744+ }
745+
746+ /*
747+ * Determine if we need to wrap the translated queries in a transaction.
748+ *
749+ * [GRAMMAR]
750+ * query:
751+ * EOF
752+ * | (simpleStatement | beginWork) (SEMICOLON_SYMBOL EOF? | EOF)
753+ */
754+ $ child_node = $ ast ->get_first_child_node ();
755+ if (
756+ null === $ child_node
757+ || 'beginWork ' === $ child_node ->rule_name
758+ || $ child_node ->has_child_node ( 'transactionOrLockingStatement ' )
759+ ) {
760+ $ wrap_in_transaction = false ;
761+ } else {
762+ $ wrap_in_transaction = true ;
763+ }
764+
765+ if ( $ wrap_in_transaction ) {
766+ $ this ->begin_wrapper_transaction ();
767+ }
768+
769+ $ this ->execute_mysql_query ( $ ast );
770+
771+ if ( $ wrap_in_transaction ) {
772+ $ this ->commit_wrapper_transaction ();
773+ }
774+
775+ $ affected_rows = is_int ( $ this ->last_return_value ) ? $ this ->last_return_value : 0 ;
776+ $ rows = is_array ( $ this ->last_result ) ? $ this ->last_result : array ();
777+ $ column_meta = is_array ( $ this ->last_column_meta ) ? $ this ->last_column_meta : array ();
778+ return new WP_PDO_Synthetic_Statement ( $ rows , $ column_meta , $ affected_rows );
779+ } catch ( Throwable $ e ) {
780+ try {
781+ $ this ->rollback_user_transaction ();
782+ $ this ->table_lock_active = false ;
783+ } catch ( Throwable $ rollback_exception ) {
784+ // Ignore rollback errors.
785+ }
786+ if ( $ e instanceof WP_SQLite_Driver_Exception ) {
787+ throw $ e ;
788+ } elseif ( $ e instanceof WP_SQLite_Information_Schema_Exception ) {
789+ throw $ this ->convert_information_schema_exception ( $ e );
790+ }
791+ throw $ this ->new_driver_exception ( $ e ->getMessage (), $ e ->getCode (), $ e );
792+ }
793+ }
794+
714795 /**
715796 * PDO API: Begin a transaction.
716797 *
@@ -867,87 +948,6 @@ public function get_insert_id() {
867948 return $ last_insert_id ;
868949 }
869950
870- /**
871- * PDO API: Translate and execute a MySQL query in SQLite.
872- *
873- * A single MySQL query can be translated into zero or more SQLite queries.
874- *
875- * @param string $query Full SQL statement string.
876- * @param int $fetch_mode PDO fetch mode. Default is PDO::FETCH_OBJ.
877- * @param array ...$fetch_mode_args Additional fetch mode arguments.
878- *
879- * @return mixed Return value, depending on the query type.
880- *
881- * @throws WP_SQLite_Driver_Exception When the query execution fails.
882- */
883- #[ReturnTypeWillChange]
884- public function query ( string $ query , ?int $ fetch_mode = PDO ::FETCH_COLUMN , ...$ fetch_mode_args ) {
885- $ this ->flush ();
886- $ this ->pdo_fetch_mode = $ fetch_mode ;
887- $ this ->last_mysql_query = $ query ;
888-
889- try {
890- // Parse the MySQL query.
891- $ parser = $ this ->create_parser ( $ query );
892- $ parser ->next_query ();
893- $ ast = $ parser ->get_query_ast ();
894- if ( null === $ ast ) {
895- throw $ this ->new_driver_exception ( 'Failed to parse the MySQL query. ' );
896- }
897-
898- if ( $ parser ->next_query () ) {
899- throw $ this ->new_driver_exception ( 'Multi-query is not supported. ' );
900- }
901-
902- /*
903- * Determine if we need to wrap the translated queries in a transaction.
904- *
905- * [GRAMMAR]
906- * query:
907- * EOF
908- * | (simpleStatement | beginWork) (SEMICOLON_SYMBOL EOF? | EOF)
909- */
910- $ child_node = $ ast ->get_first_child_node ();
911- if (
912- null === $ child_node
913- || 'beginWork ' === $ child_node ->rule_name
914- || $ child_node ->has_child_node ( 'transactionOrLockingStatement ' )
915- ) {
916- $ wrap_in_transaction = false ;
917- } else {
918- $ wrap_in_transaction = true ;
919- }
920-
921- if ( $ wrap_in_transaction ) {
922- $ this ->begin_wrapper_transaction ();
923- }
924-
925- $ this ->execute_mysql_query ( $ ast );
926-
927- if ( $ wrap_in_transaction ) {
928- $ this ->commit_wrapper_transaction ();
929- }
930-
931- $ affected_rows = is_int ( $ this ->last_return_value ) ? $ this ->last_return_value : 0 ;
932- $ rows = is_array ( $ this ->last_result ) ? $ this ->last_result : array ();
933- $ column_meta = is_array ( $ this ->last_column_meta ) ? $ this ->last_column_meta : array ();
934- return new WP_PDO_Synthetic_Statement ( $ rows , $ column_meta , $ affected_rows );
935- } catch ( Throwable $ e ) {
936- try {
937- $ this ->rollback_user_transaction ();
938- $ this ->table_lock_active = false ;
939- } catch ( Throwable $ rollback_exception ) {
940- // Ignore rollback errors.
941- }
942- if ( $ e instanceof WP_SQLite_Driver_Exception ) {
943- throw $ e ;
944- } elseif ( $ e instanceof WP_SQLite_Information_Schema_Exception ) {
945- throw $ this ->convert_information_schema_exception ( $ e );
946- }
947- throw $ this ->new_driver_exception ( $ e ->getMessage (), $ e ->getCode (), $ e );
948- }
949- }
950-
951951 /**
952952 * Tokenize a MySQL query and initialize a parser.
953953 *
0 commit comments