diff --git a/integrations/plugin-compatibility/boot.php b/integrations/plugin-compatibility/boot.php new file mode 100644 index 00000000..2783ce1f --- /dev/null +++ b/integrations/plugin-compatibility/boot.php @@ -0,0 +1,56 @@ + 8, ), array( - // TODO: Fix custom "RAND()" function to behave like in MySQL. - 'native_type' => 'LONGLONG', // DOUBLE in MySQL. - 'pdo_type' => PDO::PARAM_INT, // PARAM_STR in MySQL. + 'native_type' => 'DOUBLE', // DOUBLE in MySQL. + 'pdo_type' => PDO::PARAM_STR, // PARAM_STR in MySQL. 'flags' => array( 'not_null' ), 'table' => '', 'name' => 'col_expr_19', - 'len' => 21, // 23 in MySQL. - 'precision' => 0, // 31 in MySQL. + 'len' => 23, // 23 in MySQL. + 'precision' => 31, // 31 in MySQL. 'sqlite:decl_type' => '', // Additional MySQLi metadata. @@ -9084,7 +9083,7 @@ public function testColumnInfoForExpressions(): void { 'mysqli:db' => 'wp', 'mysqli:charsetnr' => 63, 'mysqli:flags' => 0, // 32769 in MySQL. - 'mysqli:type' => 8, // 5 in MySQL. + 'mysqli:type' => 5, // 5 in MySQL. ), array( 'native_type' => 'LONGLONG', diff --git a/wp-includes/sqlite-ast/class-wp-pdo-mysql-on-sqlite.php b/wp-includes/sqlite-ast/class-wp-pdo-mysql-on-sqlite.php index b70a0dd6..84ca1caa 100644 --- a/wp-includes/sqlite-ast/class-wp-pdo-mysql-on-sqlite.php +++ b/wp-includes/sqlite-ast/class-wp-pdo-mysql-on-sqlite.php @@ -4287,10 +4287,14 @@ private function translate_regexp_functions( WP_Parser_Node $node ): string { * be reasonably safe since PHP does not allow null bytes in * regular expressions anyway. */ + $pattern = $this->translate( $node->get_first_child_node() ); + // Fix double backslash escaping for REGEXP patterns. + $pattern = str_replace( '\\\\/', '/', $pattern ); + if ( true === $is_binary ) { - return 'REGEXP CHAR(0) || ' . $this->translate( $node->get_first_child_node() ); + return 'REGEXP CHAR(0) || ' . $pattern; } - return 'REGEXP ' . $this->translate( $node->get_first_child_node() ); + return 'REGEXP ' . $pattern; } /** @@ -4366,6 +4370,12 @@ private function translate_function_call( WP_Parser_Node $node ): string { } switch ( $name ) { + case 'RAND': + if ( empty( $args ) ) { + return '(ABS(RANDOM()) / 9223372036854775808.0)'; + } + // Seeded RAND() calls should be handled by the PHP UDF. + return $this->translate_sequence( $node->get_children() ); case 'DATE_FORMAT': list ( $date, $mysql_format ) = $args; diff --git a/wp-includes/sqlite/class-wp-sqlite-pdo-user-defined-functions.php b/wp-includes/sqlite/class-wp-sqlite-pdo-user-defined-functions.php index b72d787f..7b0874cc 100644 --- a/wp-includes/sqlite/class-wp-sqlite-pdo-user-defined-functions.php +++ b/wp-includes/sqlite/class-wp-sqlite-pdo-user-defined-functions.php @@ -176,10 +176,15 @@ public function md5( $field ) { * This function uses mt_rand() which is four times faster than rand() and returns * the random number between 0 and 1. * - * @return int + * @param int|null $seed The seed value (optional). + * + * @return float */ - public function rand() { - return mt_rand( 0, 1 ); + public function rand( $seed = null ) { + if ( null !== $seed ) { + mt_srand( intval( $seed ) ); + } + return mt_rand( 0, mt_getrandmax() ) / mt_getrandmax(); } /** diff --git a/wp-includes/sqlite/db.php b/wp-includes/sqlite/db.php index dc50d22e..ad50273a 100644 --- a/wp-includes/sqlite/db.php +++ b/wp-includes/sqlite/db.php @@ -85,4 +85,7 @@ // Boot the Query Monitor plugin if it is active. require_once dirname( __DIR__, 2 ) . '/integrations/query-monitor/boot.php'; + + // Boot the SQLite Plugin Compatibility Layer. + require_once dirname( __DIR__, 2 ) . '/integrations/plugin-compatibility/boot.php'; }