@@ -73,151 +73,52 @@ public function set_charset( $dbh, $charset = null, $collate = null ) {
7373 /**
7474 * Retrieves the character set for the given column.
7575 *
76- * @since 2.3.0
76+ * This overrides wpdb::get_col_charset() to enable the parent's implementation
77+ * for SQLite by temporarily setting the is_mysql flag.
78+ *
79+ * @see wpdb::get_col_charset()
7780 *
7881 * @param string $table Table name.
7982 * @param string $column Column name.
80- * @return string|false Column character set as a string. False if the column has
81- * no character set (e.g., numeric or binary columns) .
83+ * @return string|false|WP_Error Column character set as a string. False if the column has
84+ * no character set. WP_Error object on failure .
8285 */
8386 public function get_col_charset ( $ table , $ column ) {
84- $ table_key = strtolower ( $ table );
85- $ column_key = strtolower ( $ column );
86-
87- /**
88- * Filters the column charset value before the DB is checked.
89- *
90- * @since 2.3.0
91- *
92- * @param string|null|false $charset The character set to use. Default null.
93- * @param string $table The name of the table being checked.
94- * @param string $column The name of the column being checked.
87+ /*
88+ * The parent method returns early when `$this->is_mysql` is falsy.
89+ * Since SQLite doesn't set this flag, we enable it temporarily so
90+ * the parent can run its full logic — querying column metadata via
91+ * SHOW FULL COLUMNS (which the SQLite driver translates) and
92+ * populating the `$this->col_meta` cache.
9593 */
96- $ charset = apply_filters ( 'pre_get_col_charset ' , null , $ table , $ column );
97- if ( null !== $ charset ) {
98- return $ charset ;
99- }
100-
101- // Use SHOW FULL COLUMNS to get column metadata with collation info.
102- // This works because the driver translates this to query the information schema.
103- $ results = $ this ->get_results ( "SHOW FULL COLUMNS FROM ` {$ table_key }` " );
104-
105- if ( ! $ results ) {
106- return false ;
107- }
108-
109- // Build column metadata cache.
110- $ columns = array ();
111- foreach ( $ results as $ col ) {
112- $ columns [ strtolower ( $ col ->Field ) ] = $ col ;
113- }
114- $ this ->col_meta [ $ table_key ] = $ columns ;
115-
116- // Check if column exists.
117- if ( ! isset ( $ columns [ $ column_key ] ) ) {
118- return false ;
119- }
120-
121- // Return false for non-string columns (no collation).
122- if ( empty ( $ columns [ $ column_key ]->Collation ) ) {
123- return false ;
94+ try {
95+ $ this ->is_mysql = true ;
96+ return parent ::get_col_charset ( $ table , $ column );
97+ } finally {
98+ $ this ->is_mysql = null ;
12499 }
125-
126- // Extract charset from collation (e.g., 'utf8mb4_general_ci' -> 'utf8mb4').
127- list ( $ charset ) = explode ( '_ ' , $ columns [ $ column_key ]->Collation );
128- return $ charset ;
129100 }
130101
131102 /**
132103 * Retrieves the maximum string length allowed in a given column.
133104 *
134- * @since 2.3.0
105+ * This overrides wpdb::get_col_length() to enable the parent's implementation
106+ * for SQLite by temporarily setting the is_mysql flag.
107+ *
108+ * @see wpdb::get_col_length()
135109 *
136110 * @param string $table Table name.
137111 * @param string $column Column name.
138- * @return array|false {
139- * Array of column length information, false if the column has no length
140- * (for example, numeric column).
141- *
142- * @type string $type One of 'byte' or 'char'.
143- * @type int $length The column length.
144- * }
112+ * @return array|false|WP_Error Column length information, false if the column has
113+ * no length. WP_Error object on failure.
145114 */
146115 public function get_col_length ( $ table , $ column ) {
147- $ table_key = strtolower ( $ table );
148- $ column_key = strtolower ( $ column );
149-
150- // Check cached column metadata first.
151- if ( isset ( $ this ->col_meta [ $ table_key ][ $ column_key ] ) ) {
152- $ type = $ this ->col_meta [ $ table_key ][ $ column_key ]->Type ;
153- } else {
154- // Query column info if not cached.
155- $ results = $ this ->get_results ( "SHOW FULL COLUMNS FROM ` {$ table_key }` " );
156- if ( ! $ results ) {
157- return false ;
158- }
159-
160- $ columns = array ();
161- foreach ( $ results as $ col ) {
162- $ columns [ strtolower ( $ col ->Field ) ] = $ col ;
163- }
164- $ this ->col_meta [ $ table_key ] = $ columns ;
165-
166- if ( ! isset ( $ columns [ $ column_key ] ) ) {
167- return false ;
168- }
169- $ type = $ columns [ $ column_key ]->Type ;
170- }
171-
172- // Parse the type to get length info.
173- $ typeinfo = explode ( '( ' , $ type );
174- $ basetype = strtolower ( $ typeinfo [0 ] );
175-
176- if ( ! empty ( $ typeinfo [1 ] ) ) {
177- $ length = (int ) trim ( $ typeinfo [1 ], ') ' );
178- } else {
179- $ length = false ;
180- }
181-
182- switch ( $ basetype ) {
183- case 'char ' :
184- case 'varchar ' :
185- return array (
186- 'type ' => 'char ' ,
187- 'length ' => $ length ,
188- );
189- case 'binary ' :
190- case 'varbinary ' :
191- return array (
192- 'type ' => 'byte ' ,
193- 'length ' => $ length ,
194- );
195- case 'tinyblob ' :
196- case 'tinytext ' :
197- return array (
198- 'type ' => 'byte ' ,
199- 'length ' => 255 ,
200- );
201- case 'blob ' :
202- case 'text ' :
203- return array (
204- 'type ' => 'byte ' ,
205- 'length ' => 65535 ,
206- );
207- case 'mediumblob ' :
208- case 'mediumtext ' :
209- return array (
210- 'type ' => 'byte ' ,
211- 'length ' => 16777215 ,
212- );
213- case 'longblob ' :
214- case 'longtext ' :
215- return array (
216- 'type ' => 'byte ' ,
217- 'length ' => 4294967295 ,
218- );
219- default :
220- return false ;
116+ // See get_col_charset() for an explanation of the is_mysql flag.
117+ try {
118+ $ this ->is_mysql = true ;
119+ return parent ::get_col_length ( $ table , $ column );
120+ } finally {
121+ $ this ->is_mysql = null ;
221122 }
222123 }
223124
@@ -271,16 +172,13 @@ public function set_sql_mode( $modes = array() ) {
271172
272173 /**
273174 * Closes the current database connection.
274- * Noop in SQLite.
275175 *
276- * @return bool True to indicate the connection was successfully closed.
277- */
278- /**
279- * Close the database connection.
176+ * This overrides wpdb::close() while closely mirroring its implementation.
280177 *
281- * @since 2.3.0
178+ * @see wpdb::close()
282179 *
283- * @return bool True if connection was closed successfully.
180+ * @return bool True if the connection was successfully closed,
181+ * false if it wasn't, or if the connection doesn't exist.
284182 */
285183 public function close () {
286184 if ( ! $ this ->dbh ) {
@@ -295,20 +193,20 @@ public function close() {
295193 }
296194
297195 /**
298- * Determines the best charset and collation for the database connection .
196+ * Determines the best charset and collation to use given a charset and collation .
299197 *
300- * This overrides wpdb::determine_charset() to handle SQLite's lack of mysqli.
301- * WordPress expects utf8 to be upgraded to utf8mb4 when supported.
198+ * For example, when able, utf8mb4 should be used instead of utf8.
302199 *
303- * @since 2.3.0
200+ * This overrides wpdb::determine_charset() while closely mirroring its implementation.
201+ * The override is needed because the parent checks for a mysqli connection object.
304202 *
305203 * @param string $charset The character set to check.
306204 * @param string $collate The collation to check.
307205 * @return array {
308- * Array containing the determined charset and collation.
206+ * The most appropriate character set and collation to use .
309207 *
310- * @type string $charset The determined character set.
311- * @type string $collate The determined collation .
208+ * @type string $charset Character set.
209+ * @type string $collate Collation .
312210 * }
313211 */
314212 public function determine_charset ( $ charset , $ collate ) {
@@ -634,14 +532,23 @@ public function query( $query ) {
634532 // Save the query count before running another query.
635533 $ last_query_count = count ( $ this ->queries ?? array () );
636534
637- // Check for invalid text in the query, similar to parent wpdb behavior.
535+ /*
536+ * Strip invalid UTF-8 characters from non-ASCII queries.
537+ *
538+ * SQLite stores all text as UTF-8, so we simply ensure the query
539+ * contains only valid UTF-8 sequences rather than using the parent's
540+ * MySQL-specific charset detection pipeline.
541+ */
638542 if ( $ this ->check_current_query && ! $ this ->check_ascii ( $ query ) ) {
639- $ stripped_query = $ this ->strip_invalid_text_from_query ( $ query );
640- /*
641- * strip_invalid_text_from_query() can perform queries, so we need
642- * to flush again, just to make sure everything is clear.
643- */
644- $ this ->flush ();
543+ if ( function_exists ( 'mb_convert_encoding ' ) ) {
544+ $ stripped_query = mb_convert_encoding ( $ query , 'UTF-8 ' , 'UTF-8 ' );
545+ } else {
546+ $ stripped_query = htmlspecialchars_decode (
547+ htmlspecialchars ( $ query , ENT_NOQUOTES | ENT_SUBSTITUTE , 'UTF-8 ' ),
548+ ENT_NOQUOTES
549+ );
550+ }
551+
645552 if ( $ stripped_query !== $ query ) {
646553 $ this ->insert_id = 0 ;
647554 $ this ->last_query = $ query ;
@@ -801,17 +708,18 @@ protected function load_col_info() {
801708 }
802709
803710 /**
804- * Method to return what the database can do .
711+ * Determines whether the database supports a given feature .
805712 *
806- * This overrides wpdb::has_cap() to avoid using MySQL functions.
807- * SQLite via this driver supports all common MySQL capabilities.
713+ * This overrides wpdb::has_cap() while closely mirroring its implementation.
714+ * The override is needed because the parent's 'utf8mb4' capability check calls
715+ * mysqli_get_client_info(), which is environment-dependent and not applicable
716+ * for SQLite.
808717 *
809718 * @see wpdb::has_cap()
810719 *
811720 * @param string $db_cap The feature to check for. Accepts 'collation',
812721 * 'group_concat', 'subqueries', 'set_charset',
813- * 'utf8mb4', 'utf8mb4_520', or 'identifier_placeholders'.
814- *
722+ * 'utf8mb4', or 'utf8mb4_520'.
815723 * @return bool Whether the database feature is supported, false otherwise.
816724 */
817725 public function has_cap ( $ db_cap ) {
@@ -823,9 +731,9 @@ public function has_cap( $db_cap ) {
823731 case 'subqueries ' :
824732 case 'set_charset ' :
825733 case 'utf8mb4 ' :
826- case 'utf8mb4_520 ' :
827- case 'identifier_placeholders ' :
828734 return true ;
735+ case 'utf8mb4_520 ' :
736+ return version_compare ( $ GLOBALS ['wp_version ' ], '4.6 ' , '>= ' );
829737 }
830738
831739 return false ;
0 commit comments