2013-07-07 06:49:38 +00:00
< ? php
/**
2014-01-29 09:35:06 +00:00
* This file defines PDOEngine class .
2014-07-14 08:46:32 +00:00
*
2013-07-07 06:49:38 +00:00
* @ package SQLite Integration
2014-01-29 09:35:06 +00:00
* @ author Kojima Toshiyasu
2013-07-07 06:49:38 +00:00
*
*/
/**
2014-01-29 09:35:06 +00:00
* This class extends PDO class and does the real work .
2014-07-14 08:46:32 +00:00
*
2014-01-29 09:35:06 +00:00
* It accepts a request from wpdb class , initialize PDO instance ,
* execute SQL statement , and returns the results to WordPress .
2013-07-07 06:49:38 +00:00
*/
class PDOEngine extends PDO {
2014-01-29 09:35:06 +00:00
/**
* Class variable to check if there is an error .
2014-07-14 08:46:32 +00:00
*
2014-01-29 09:35:06 +00:00
* @ var boolean
*/
2014-07-14 08:46:32 +00:00
public $is_error = false ;
/**
* Class variable which is used for CALC_FOUND_ROW query .
*
* @ var unsigned integer
*/
public $found_rows_result = null ;
2014-07-16 04:35:27 +00:00
/**
* Class variable used for query with ORDER BY FIELD ()
*
* @ var array of the object
*/
public $pre_ordered_results = null ;
2014-07-14 08:46:32 +00:00
/**
* Class variable to store the rewritten queries .
*
* @ var array
* @ access private
*/
private $rewritten_query ;
/**
* Class variable to have what kind of query to execute .
*
* @ var string
* @ access private
*/
private $query_type ;
/**
* Class variable to store the result of the query .
*
* @ var reference to the PHP object
* @ access private
*/
private $results = null ;
/**
* Class variable to store the results of the query .
*
* This is for the backward compatibility .
*
* @ var reference to the PHP object
* @ access private
*/
private $_results = null ;
/**
* Class variable to reference to the PDO instance .
*
* @ var PDO object
* @ access private
*/
private $pdo ;
/**
* Class variable to store the query string prepared to execute .
*
* @ var string | array
*/
private $prepared_query ;
/**
* Class variable to store the values in the query string .
*
* @ var array
* @ access private
*/
private $extracted_variables = array ();
/**
* Class variable to store the error messages .
*
* @ var array
* @ access private
*/
private $error_messages = array ();
/**
* Class variable to store the file name and function to cause error .
*
* @ var array
* @ access private
*/
private $errors ;
/**
* Class variable to store the query strings .
*
* @ var array
*/
public $queries = array ();
/**
* Class variable to store the affected row id .
*
* @ var unsigned integer
* @ access private
*/
private $last_insert_id ;
/**
* Class variable to store the number of rows affected .
*
* @ var unsigned integer
*/
private $affected_rows ;
/**
* Class variable to store the queried column info .
*
* @ var array
*/
private $column_data ;
/**
* Variable to emulate MySQL affected row .
*
* @ var integer
*/
private $num_rows ;
/**
* Return value from query () .
*
* Each query has its own return value .
*
* @ var mixed
*/
private $return_value ;
/**
* Variable to determine which insert query to use .
*
* Whether VALUES clause in the INSERT query can take multiple values or not
* depends on the version of SQLite library . We check the version and set
* this varable to true or false .
*
* @ var boolean
*/
private $can_insert_multiple_rows = false ;
/**
*
* @ var integer
*/
private $param_num ;
/**
* Varible to check if there is an active transaction .
* @ var boolean
* @ access protected
*/
protected $has_active_transaction = false ;
2013-07-07 06:49:38 +00:00
2014-07-14 08:46:32 +00:00
/**
* Constructor
*
2014-10-02 07:18:40 +00:00
* Create PDO object , set user defined functions and initialize other settings .
* Don ' t use parent :: __construct () because this class does not only returns
* PDO instance but many others jobs .
*
* Constructor definition is changed since version 1.7 . 1.
*
2014-07-14 08:46:32 +00:00
* @ param none
*/
function __construct () {
2014-07-30 23:44:12 +00:00
register_shutdown_function ( array ( $this , '__destruct' ));
2015-03-19 18:05:37 +00:00
if ( ! is_file ( FQDB )) {
2015-03-05 21:01:35 +00:00
$this -> prepare_directory ();
}
2014-10-06 00:19:56 +00:00
$dsn = 'sqlite:' . FQDB ;
2014-10-02 07:18:40 +00:00
if ( isset ( $GLOBALS [ '@pdo' ])) {
$this -> pdo = $GLOBALS [ '@pdo' ];
} else {
$locked = false ;
$status = 0 ;
do {
try {
$this -> pdo = new PDO ( $dsn , null , null , array ( PDO :: ATTR_ERRMODE => PDO :: ERRMODE_EXCEPTION ));
require_once UDF_FILE ;
new PDOSQLiteUDFS ( $this -> pdo );
$GLOBALS [ '@pdo' ] = $this -> pdo ;
} catch ( PDOException $ex ) {
$status = $ex -> getCode ();
if ( $status == 5 || $status == 6 ) {
$locked = true ;
} else {
$err_message = $ex -> getMessage ();
}
}
} while ( $locked );
if ( $status > 0 ) {
$message = 'Database initialization error!<br />' .
'Code: ' . $status . '<br />Error Message: ' . $err_message ;
$this -> set_error ( __LINE__ , __FILE__ , $message );
return false ;
}
}
2014-07-14 08:46:32 +00:00
$this -> init ();
}
/**
* Destructor
*
2014-07-30 23:44:12 +00:00
* If SQLITE_MEM_DEBUG constant is defined , append information about
* memory usage into database / mem_debug . txt .
*
2014-10-02 07:18:40 +00:00
* This definition is changed since version 1.7 .
*
2014-07-14 08:46:32 +00:00
* @ return boolean
*/
function __destruct () {
2014-07-30 23:44:12 +00:00
if ( defined ( 'SQLITE_MEM_DEBUG' ) && SQLITE_MEM_DEBUG ) {
$max = ini_get ( 'memory_limit' );
if ( is_null ( $max )) {
$message = sprintf ( " [%s] Memory_limit is not set in php.ini file. " , date ( 'Y-m-d H:i:s' , $_SERVER [ 'REQUEST_TIME' ]));
file_put_contents ( FQDBDIR . 'mem_debug.txt' , $message , FILE_APPEND );
return true ;
}
if ( stripos ( $max , 'M' ) !== false ) {
$max = ( int ) $max * 1024 * 1024 ;
}
$peak = memory_get_peak_usage ( true );
$used = round (( int ) $peak / ( int ) $max * 100 , 2 );
if ( $used > 90 ) {
$message = sprintf ( " [%s] Memory peak usage warning: %s %% used. (max: %sM, now: %sM) \n " , date ( 'Y-m-d H:i:s' , $_SERVER [ 'REQUEST_TIME' ]), $used , $max , $peak );
file_put_contents ( FQDBDIR . 'mem_debug.txt' , $message , FILE_APPEND );
}
}
//$this->pdo = null;
2014-07-14 08:46:32 +00:00
return true ;
}
/**
* Method to initialize database , executed in the contructor .
*
2014-10-02 07:18:40 +00:00
* It checks if WordPress is in the installing process and does the required
* jobs . SQLite library version specific settings are also in this function .
*
* Some developers use WP_INSTALLING constant for other purposes , if so , this
* function will do no harms .
2014-07-14 08:46:32 +00:00
*
* @ return boolean
*/
private function init () {
2014-10-02 07:18:40 +00:00
if ( defined ( 'WP_INSTALLING' ) && WP_INSTALLING ) {
$statement = $this -> pdo -> query ( " SELECT COUNT(*) FROM sqlite_master WHERE type='table' " );
$number_of_tables = $statement -> fetchColumn ( 0 );
$statement = null ;
if ( $number_of_tables == 0 ) $this -> make_sqlite_tables ();
}
if ( version_compare ( $this -> get_sqlite_version (), '3.7.11' , '>=' )) {
$this -> can_insert_multiple_rows = true ;
2014-07-14 08:46:32 +00:00
}
2014-10-02 07:18:40 +00:00
$statement = $this -> pdo -> query ( 'PRAGMA foreign_keys' );
if ( $statement -> fetchColumn ( 0 ) == '0' ) $this -> pdo -> query ( 'PRAGMA foreign_keys = ON' );
2014-07-14 08:46:32 +00:00
}
/**
* This method makes database direcotry and . htaccess file .
*
* It is executed only once when the installation begins .
*/
private function prepare_directory () {
global $wpdb ;
$u = umask ( 0000 );
if ( ! is_dir ( FQDBDIR )) {
2015-03-05 21:01:35 +00:00
if ( !@ mkdir ( FQDBDIR , 0704 , true )) {
2014-07-14 08:46:32 +00:00
umask ( $u );
$message = 'Unable to create the required directory! Please check your server settings.' ;
wp_die ( $message , 'Error!' );
}
}
if ( ! is_writable ( FQDBDIR )) {
umask ( $u );
$message = 'Unable to create a file in the directory! Please check your server settings.' ;
wp_die ( $message , 'Error!' );
}
if ( ! is_file ( FQDBDIR . '.htaccess' )) {
$fh = fopen ( FQDBDIR . '.htaccess' , " w " );
if ( ! $fh ) {
umask ( $u );
$message = 'Unable to create a file in the directory! Please check your server settings.' ;
echo $message ;
return false ;
}
fwrite ( $fh , 'DENY FROM ALL' );
fclose ( $fh );
}
if ( ! is_file ( FQDBDIR . 'index.php' )) {
$fh = fopen ( FQDBDIR . 'index.php' , " w " );
if ( ! $fh ) {
umask ( $u );
$message = 'Unable to create a file in the directory! Please check your server settings.' ;
echo $message ;
return false ;
}
fwrite ( $fh , '<?php // Silence is gold. ?>' );
fclose ( $fh );
}
umask ( $u );
return true ;
}
/**
* Method to call install () function which overrides WordPress install () .
*
* This function is executed only once during the installation process .
*/
private function make_sqlite_tables () {
require_once PDODIR . 'install.php' ;
}
/**
* Method to execute query () .
*
* Divide the query types into seven different ones . That is to say :
*
* 1. SELECT SQL_CALC_FOUND_ROWS
* 2. INSERT
* 3. CREATE TABLE ( INDEX )
* 4. ALTER TABLE
* 5. SHOW VARIABLES
* 6. DROP INDEX
* 7. THE OTHERS
*
* #1 is just a tricky play. See the private function handle_sql_count() in query.class.php.
* From #2 through #5 call different functions respectively.
* #6 call the ALTER TABLE query.
* #7 is a normal process: sequentially call prepare_query() and execute_query().
*
* #1 process has been changed since version 1.5.1.
*
* @ param $query full SQL statement string
* @ return mixed according to the query type
* @ see PDO :: query ()
*/
public function query ( $query ) {
$this -> flush ();
2013-07-07 06:49:38 +00:00
2014-07-14 08:46:32 +00:00
$this -> queries [] = " Raw query: \n $query " ;
$res = $this -> determine_query_type ( $query );
if ( ! $res && defined ( PDO_DEBUG ) && PDO_DEBUG ) {
$bailoutString = sprintf ( __ ( " <h1>Unknown query type</h1><p>Sorry, we cannot determine the type of query that is requested.</p><p>The query is %s</p> " , 'sqlite-integration' ), $query );
$this -> set_error ( __LINE__ , __FUNCTION__ , $bailoutString );
}
switch ( strtolower ( $this -> query_type )) {
case 'set' :
$this -> return_value = false ;
break ;
case 'foundrows' :
2014-01-29 09:35:06 +00:00
$_column = array ( 'FOUND_ROWS()' => '' );
2014-02-05 19:29:23 +00:00
$column = array ();
2014-01-29 09:35:06 +00:00
if ( ! is_null ( $this -> found_rows_result )) {
2014-03-18 10:06:36 +00:00
$this -> num_rows = $this -> found_rows_result ;
$_column [ 'FOUND_ROWS()' ] = $this -> num_rows ;
2014-07-14 08:46:32 +00:00
//foreach ($this->found_rows_result[0] as $key => $value) {
//$_column['FOUND_ROWS()'] = $value;
//}
2014-02-05 19:29:23 +00:00
$column [] = new ObjectArray ( $_column );
$this -> results = $column ;
2014-01-29 09:35:06 +00:00
$this -> found_rows_result = null ;
}
2014-07-14 08:46:32 +00:00
break ;
case 'insert' :
if ( $this -> can_insert_multiple_rows ) {
$this -> execute_insert_query_new ( $query );
} else {
$this -> execute_insert_query ( $query );
}
break ;
case 'create' :
$result = $this -> execute_create_query ( $query );
$this -> return_value = $result ;
break ;
case 'alter' :
$result = $this -> execute_alter_query ( $query );
$this -> return_value = $result ;
break ;
case 'show_variables' :
$result = $this -> show_variables_workaround ( $query );
break ;
case 'showstatus' :
$result = $this -> show_status_workaround ( $query );
break ;
case 'drop_index' :
$pattern = '/^\\s*(DROP\\s*INDEX\\s*.*?)\\s*ON\\s*(.*)/im' ;
if ( preg_match ( $pattern , $query , $match )) {
$drop_query = 'ALTER TABLE ' . trim ( $match [ 2 ]) . ' ' . trim ( $match [ 1 ]);
$this -> query_type = 'alter' ;
$result = $this -> execute_alter_query ( $drop_query );
$this -> return_value = $result ;
} else {
$this -> return_value = false ;
}
break ;
default :
$engine = $this -> prepare_engine ( $this -> query_type );
$this -> rewritten_query = $engine -> rewrite_query ( $query , $this -> query_type );
2014-07-16 04:35:27 +00:00
if ( ! is_null ( $this -> pre_ordered_results )) {
$this -> results = $this -> pre_ordered_results ;
$this -> num_rows = $this -> return_value = count ( $this -> results );
$this -> pre_ordered_results = null ;
break ;
}
2014-07-14 08:46:32 +00:00
$this -> queries [] = " Rewritten: \n $this->rewritten_query " ;
$this -> extract_variables ();
$statement = $this -> prepare_query ();
$this -> execute_query ( $statement );
if ( ! $this -> is_error ) {
$this -> process_results ( $engine );
} else { // Error
;
}
break ;
}
if ( defined ( 'PDO_DEBUG' ) && PDO_DEBUG === true ) {
file_put_contents ( FQDBDIR . 'debug.txt' , $this -> get_debug_info (), FILE_APPEND );
}
return $this -> return_value ;
}
2014-01-29 09:35:06 +00:00
/**
2014-04-17 02:45:32 +00:00
* Method to return inserted row id .
2014-07-14 08:46:32 +00:00
*
2014-01-29 09:35:06 +00:00
* @ return unsigned integer
*/
2014-07-14 08:46:32 +00:00
public function get_insert_id () {
return $this -> last_insert_id ;
}
/**
* Method to return the number of rows affected .
*
* @ return unsigned integer
*/
public function get_affected_rows () {
return $this -> affected_rows ;
}
/**
* Method to return the queried column names .
*
* These data are meaningless for SQLite . So they are dummy emulating
* MySQL columns data .
*
* @ return array of the object
*/
public function get_columns () {
if ( ! empty ( $this -> results )) {
$primary_key = array (
'meta_id' , 'comment_ID' , 'link_ID' , 'option_id' ,
'blog_id' , 'option_name' , 'ID' , 'term_id' , 'object_id' ,
'term_taxonomy_id' , 'umeta_id' , 'id' );
$unique_key = array ( 'term_id' , 'taxonomy' , 'slug' );
$data = array (
'name' => '' , // column name
'table' => '' , // table name
'max_length' => 0 , // max length of the column
'not_null' => 1 , // 1 if not null
'primary_key' => 0 , // 1 if column has primary key
'unique_key' => 0 , // 1 if column has unique key
'multiple_key' => 0 , // 1 if column doesn't have unique key
'numeric' => 0 , // 1 if column has numeric value
'blob' => 0 , // 1 if column is blob
'type' => '' , // type of the column
'unsigned' => 0 , // 1 if column is unsigned integer
'zerofill' => 0 // 1 if column is zero-filled
);
if ( preg_match ( " / \ s*FROM \ s*(.*)? \ s*/i " , $this -> rewritten_query , $match )) {
$table_name = trim ( $match [ 1 ]);
} else {
$table_name = '' ;
}
foreach ( $this -> results [ 0 ] as $key => $value ) {
$data [ 'name' ] = $key ;
$data [ 'table' ] = $table_name ;
if ( in_array ( $key , $primary_key )) {
$data [ 'primary_key' ] = 1 ;
} elseif ( in_array ( $key , $unique_key )) {
$data [ 'unique_key' ] = 1 ;
} else {
$data [ 'multiple_key' ] = 1 ;
}
$this -> column_data [] = new ObjectArray ( $data );
$data [ 'name' ] = '' ;
$data [ 'table' ] = '' ;
$data [ 'primary_key' ] = 0 ;
$data [ 'unique_key' ] = 0 ;
$data [ 'multiple_key' ] = 0 ;
}
return $this -> column_data ;
} else {
return null ;
}
}
/**
* Method to return the queried result data .
*
* @ return mixed
*/
public function get_query_results () {
return $this -> results ;
}
/**
* Method to return the number of rows from the queried result .
*
* @ return unsigned integer
*/
public function get_num_rows () {
return $this -> num_rows ;
}
/**
* Method to return the queried results according to the query types .
*
* @ return mixed
*/
public function get_return_value () {
return $this -> return_value ;
}
2014-01-29 09:35:06 +00:00
/**
2014-04-17 02:45:32 +00:00
* Method to return error messages .
2014-07-14 08:46:32 +00:00
*
2014-01-29 09:35:06 +00:00
* @ return string
*/
2013-07-07 06:49:38 +00:00
public function get_error_message (){
if ( count ( $this -> error_messages ) === 0 ){
2014-02-05 19:29:23 +00:00
$this -> is_error = false ;
2013-07-07 06:49:38 +00:00
$this -> error_messages = array ();
return '' ;
}
$output = '<div style="clear:both"> </div>' ;
if ( $this -> is_error === false ){
2014-07-14 08:46:32 +00:00
//return $output;
return '' ;
2013-07-07 06:49:38 +00:00
}
$output .= " <div class= \" queries \" style= \" clear:both; margin_bottom:2px; border: red dotted thin; \" >Queries made or created this session were<br/> \r \n \t <ol> \r \n " ;
foreach ( $this -> queries as $q ){
$output .= " \t \t <li> " . $q . " </li> \r \n " ;
}
$output .= " \t </ol> \r \n </div> " ;
foreach ( $this -> error_messages as $num => $m ){
$output .= " <div style= \" clear:both; margin_bottom:2px; border: red dotted thin; \" class= \" error_message \" style= \" border-bottom:dotted blue thin; \" >Error occurred at line { $this -> errors [ $num ][ 'line' ] } in Function { $this -> errors [ $num ][ 'function' ] } . <br/> Error message was: $m </div> " ;
}
2014-07-14 08:46:32 +00:00
2013-07-07 06:49:38 +00:00
ob_start ();
debug_print_backtrace ();
2013-09-25 07:40:16 +00:00
$output .= '<pre>' . ob_get_contents () . '</pre>' ;
2013-07-07 06:49:38 +00:00
ob_end_clean ();
return $output ;
2014-07-14 08:46:32 +00:00
2013-07-07 06:49:38 +00:00
}
2014-01-29 09:35:06 +00:00
/**
2014-04-17 02:45:32 +00:00
* Method to return information about query string for debugging .
2014-07-14 08:46:32 +00:00
*
2014-01-29 09:35:06 +00:00
* @ return string
*/
2013-07-07 06:49:38 +00:00
private function get_debug_info (){
2014-07-14 08:46:32 +00:00
$output = '' ;
foreach ( $this -> queries as $q ){
$output .= $q . " \n " ;
}
return $output ;
2013-07-07 06:49:38 +00:00
}
2014-01-29 09:35:06 +00:00
/**
2014-04-17 02:45:32 +00:00
* Method to clear previous data .
2014-01-29 09:35:06 +00:00
*/
2013-07-07 06:49:38 +00:00
private function flush (){
2014-07-14 08:46:32 +00:00
$this -> rewritten_query = '' ;
$this -> query_type = '' ;
$this -> results = null ;
$this -> _results = null ;
$this -> last_insert_id = null ;
$this -> affected_rows = null ;
$this -> column_data = array ();
$this -> num_rows = null ;
$this -> return_value = null ;
$this -> extracted_variables = array ();
$this -> error_messages = array ();
$this -> is_error = false ;
$this -> queries = array ();
$this -> param_num = 0 ;
2013-07-07 06:49:38 +00:00
}
2014-01-29 09:35:06 +00:00
/**
2014-04-17 02:45:32 +00:00
* Method to include the apropreate class files .
2014-07-14 08:46:32 +00:00
*
2014-01-29 09:35:06 +00:00
* It is not a good habit to change the include files programatically .
* Needs to be fixed some other way .
2014-07-14 08:46:32 +00:00
*
2014-01-29 09:35:06 +00:00
* @ param string $query_type
* @ return object reference to apropreate driver
*/
2013-07-07 06:49:38 +00:00
private function prepare_engine ( $query_type = null ) {
2014-07-14 08:46:32 +00:00
if ( stripos ( $query_type , 'create' ) !== false ) {
require_once PDODIR . 'query_create.class.php' ;
$engine = new CreateQuery ();
} elseif ( stripos ( $query_type , 'alter' ) !== false ) {
require_once PDODIR . 'query_alter.class.php' ;
$engine = new AlterQuery ();
} else {
require_once PDODIR . 'query.class.php' ;
$engine = new PDOSQLiteDriver ();
}
return $engine ;
2013-07-07 06:49:38 +00:00
}
2014-01-29 09:35:06 +00:00
/**
2014-04-17 02:45:32 +00:00
* Method to create a PDO statement object from the query string .
2014-07-14 08:46:32 +00:00
*
2014-01-29 09:35:06 +00:00
* @ return PDOStatement
*/
2014-07-14 08:46:32 +00:00
private function prepare_query (){
2014-02-05 19:29:23 +00:00
$this -> queries [] = " Prepare: \n " . $this -> prepared_query ;
$reason = 0 ;
$message = '' ;
$statement = null ;
2013-07-07 06:49:38 +00:00
do {
2014-07-14 08:46:32 +00:00
try {
$statement = $this -> pdo -> prepare ( $this -> prepared_query );
} catch ( PDOException $err ) {
$reason = $err -> getCode ();
$message = $err -> getMessage ();
}
2013-07-07 06:49:38 +00:00
} while ( 5 == $reason || 6 == $reason );
2014-07-14 08:46:32 +00:00
2013-07-07 06:49:38 +00:00
if ( $reason > 0 ){
2013-09-25 07:40:16 +00:00
$err_message = sprintf ( " Problem preparing the PDO SQL Statement. Error was: %s " , $message );
2014-07-14 08:46:32 +00:00
$this -> set_error ( __LINE__ , __FUNCTION__ , $err_message );
2013-07-07 06:49:38 +00:00
}
return $statement ;
}
2014-01-29 09:35:06 +00:00
/**
2014-04-17 02:45:32 +00:00
* Method to execute PDO statement object .
2014-07-14 08:46:32 +00:00
*
2014-01-29 09:35:06 +00:00
* This function executes query and sets the variables to give back to WordPress .
* The variables are class fields . So if success , no return value . If failure , it
* returns void and stops .
2014-07-14 08:46:32 +00:00
*
2014-01-29 09:35:06 +00:00
* @ param object $statement of PDO statement
* @ return boolean
*/
2013-07-07 06:49:38 +00:00
private function execute_query ( $statement ) {
2014-02-05 19:29:23 +00:00
$reason = 0 ;
2013-07-07 06:49:38 +00:00
$message = '' ;
if ( ! is_object ( $statement ))
2014-01-29 09:35:06 +00:00
return false ;
2013-07-07 06:49:38 +00:00
if ( count ( $this -> extracted_variables ) > 0 ) {
2014-02-05 19:29:23 +00:00
$this -> queries [] = " Executing: \n " . var_export ( $this -> extracted_variables , true );
2013-07-07 06:49:38 +00:00
do {
if ( $this -> query_type == 'update' || $this -> query_type == 'replace' ) {
try {
$this -> beginTransaction ();
$statement -> execute ( $this -> extracted_variables );
$this -> commit ();
} catch ( PDOException $err ) {
2014-02-05 19:29:23 +00:00
$reason = $err -> getCode ();
2013-07-07 06:49:38 +00:00
$message = $err -> getMessage ();
$this -> rollBack ();
}
} else {
2014-07-14 08:46:32 +00:00
try {
$statement -> execute ( $this -> extracted_variables );
} catch ( PDOException $err ) {
$reason = $err -> getCode ();
$message = $err -> getMessage ();
}
2013-07-07 06:49:38 +00:00
}
} while ( 5 == $reason || 6 == $reason );
} else {
2013-09-25 07:40:16 +00:00
$this -> queries [] = 'Executing: (no parameters)' ;
2013-07-07 06:49:38 +00:00
do {
2014-07-14 08:46:32 +00:00
if ( $this -> query_type == 'update' || $this -> query_type == 'replace' ) {
try {
$this -> beginTransaction ();
$statement -> execute ();
$this -> commit ();
} catch ( PDOException $err ) {
$reason = $err -> getCode ();
$message = $err -> getMessage ();
$this -> rollBack ();
}
} else {
2013-07-07 06:49:38 +00:00
try {
2014-07-14 08:46:32 +00:00
$statement -> execute ();
} catch ( PDOException $err ) {
$reason = $err -> getCode ();
$message = $err -> getMessage ();
}
}
2013-07-07 06:49:38 +00:00
} while ( 5 == $reason || 6 == $reason );
}
if ( $reason > 0 ) {
2013-09-25 07:40:16 +00:00
$err_message = sprintf ( " Error while executing query! Error message was: %s " , $message );
2013-07-07 06:49:38 +00:00
$this -> set_error ( __LINE__ , __FUNCTION__ , $err_message );
return false ;
} else {
$this -> _results = $statement -> fetchAll ( PDO :: FETCH_OBJ );
}
//generate the results that $wpdb will want to see
switch ( $this -> query_type ) {
2013-09-25 07:40:16 +00:00
case 'insert' :
case 'update' :
case 'replace' :
2013-07-07 06:49:38 +00:00
$this -> last_insert_id = $this -> pdo -> lastInsertId ();
2014-02-05 19:29:23 +00:00
$this -> affected_rows = $statement -> rowCount ();
$this -> return_value = $this -> affected_rows ;
2013-07-07 06:49:38 +00:00
break ;
2013-09-25 07:40:16 +00:00
case 'select' :
case 'show' :
case 'showcolumns' :
case 'showindex' :
case 'describe' :
2014-07-14 08:46:32 +00:00
case 'desc' :
case 'check' :
case 'analyze' :
//case "foundrows":
2014-02-05 19:29:23 +00:00
$this -> num_rows = count ( $this -> _results );
2013-07-07 06:49:38 +00:00
$this -> return_value = $this -> num_rows ;
2014-07-14 08:46:32 +00:00
break ;
2013-09-25 07:40:16 +00:00
case 'delete' :
2013-07-07 06:49:38 +00:00
$this -> affected_rows = $statement -> rowCount ();
2014-02-05 19:29:23 +00:00
$this -> return_value = $this -> affected_rows ;
2014-07-14 08:46:32 +00:00
break ;
2013-09-25 07:40:16 +00:00
case 'alter' :
case 'drop' :
case 'create' :
case 'optimize' :
case 'truncate' :
2013-07-07 06:49:38 +00:00
if ( $this -> is_error ) {
$this -> return_value = false ;
} else {
$this -> return_value = true ;
}
break ;
}
}
2014-01-29 09:35:06 +00:00
/**
2014-04-17 02:45:32 +00:00
* Method to extract field data to an array and prepare the query statement .
2014-07-14 08:46:32 +00:00
*
2014-01-29 09:35:06 +00:00
* If original SQL statement is CREATE query , this function do nothing and return
* true . This returned value is not used .
2014-07-14 08:46:32 +00:00
*
2014-01-29 09:35:06 +00:00
* @ return boolean
*/
2013-07-07 06:49:38 +00:00
private function extract_variables () {
if ( $this -> query_type == 'create' ) {
$this -> prepared_query = $this -> rewritten_query ;
2014-01-29 09:35:06 +00:00
return true ;
2013-07-07 06:49:38 +00:00
}
2014-07-14 08:46:32 +00:00
2013-07-07 06:49:38 +00:00
//long queries can really kill this
$pattern = '/(?<!\\\\)([\'"])(.*?)(?<!\\\\)\\1/imsx' ;
2014-02-05 19:29:23 +00:00
$_limit = $limit = ini_get ( 'pcre.backtrack_limit' );
2014-07-30 23:44:12 +00:00
// if user's setting is more than default * 10, make PHP do the job.
if ( $limit > 10000000 ) {
$query = preg_replace_callback ( $pattern , array ( $this , 'replace_variables_with_placeholders' ), $this -> rewritten_query );
} else {
do {
if ( $limit > 10000000 ) {
$message = 'The query is too big to parse properly' ;
$this -> set_error ( __LINE__ , __FUNCTION__ , $message );
break ; //no point in continuing execution, would get into a loop
} else {
ini_set ( 'pcre.backtrack_limit' , $limit );
$query = preg_replace_callback ( $pattern , array ( $this , 'replace_variables_with_placeholders' ), $this -> rewritten_query );
}
$limit = $limit * 10 ;
} while ( is_null ( $query ));
2014-07-14 08:46:32 +00:00
2014-07-30 23:44:12 +00:00
//reset the pcre.backtrack_limist
ini_set ( 'pcre.backtrack_limit' , $_limit );
}
2014-02-05 19:29:23 +00:00
$this -> queries [] = " With Placeholders: \n " . $query ;
2013-07-07 06:49:38 +00:00
$this -> prepared_query = $query ;
}
2014-01-29 09:35:06 +00:00
/**
* Call back function to replace field data with PDO parameter .
2014-07-14 08:46:32 +00:00
*
2014-01-29 09:35:06 +00:00
* @ param string $matches
* @ return string
*/
2013-07-07 06:49:38 +00:00
private function replace_variables_with_placeholders ( $matches ) {
//remove the wordpress escaping mechanism
$param = stripslashes ( $matches [ 0 ]);
2014-07-14 08:46:32 +00:00
2013-07-07 06:49:38 +00:00
//remove trailing spaces
2014-07-14 08:46:32 +00:00
$param = trim ( $param );
2013-07-07 06:49:38 +00:00
//remove the quotes at the end and the beginning
if ( in_array ( $param { strlen ( $param ) - 1 }, array ( " ' " , '"' ))) {
$param = substr ( $param , 0 , - 1 ) ; //end
}
if ( in_array ( $param { 0 }, array ( " ' " , '"' ))) {
$param = substr ( $param , 1 ); //start
}
//$this->extracted_variables[] = $param;
$key = ':param_' . $this -> param_num ++ ;
$this -> extracted_variables [] = $param ;
//return the placeholder
//return ' ? ';
return ' ' . $key . ' ' ;
}
/**
2014-04-17 02:45:32 +00:00
* Method to determine which query type the argument is .
2014-07-14 08:46:32 +00:00
*
* It takes the query string , determines the type and returns the type string .
* If the query is the type that SQLite Integration can ' t executes , returns false .
*
* @ param string $query
* @ return boolean | string
*/
private function determine_query_type ( $query ) {
$result = preg_match ( '/^\\s*(SET|EXPLAIN|PRAGMA|SELECT\\s*FOUND_ROWS|SELECT|INSERT|UPDATE|REPLACE|DELETE|ALTER|CREATE|DROP\\s*INDEX|DROP|SHOW\\s*\\w+\\s*\\w+\\s*|DESCRIBE|DESC|TRUNCATE|OPTIMIZE|CHECK|ANALYZE)/i' , $query , $match );
if ( ! $result ) {
return false ;
}
$this -> query_type = strtolower ( $match [ 1 ]);
if ( stripos ( $this -> query_type , 'found' ) !== false ) {
$this -> query_type = 'foundrows' ;
}
if ( stripos ( $this -> query_type , 'show' ) !== false ) {
if ( stripos ( $this -> query_type , 'show table status' ) !== false ) {
$this -> query_type = 'showstatus' ;
} elseif ( stripos ( $this -> query_type , 'show tables' ) !== false || stripos ( $this -> query_type , 'show full tables' ) !== false ) {
$this -> query_type = 'show' ;
} elseif ( stripos ( $this -> query_type , 'show columns' ) !== false || stripos ( $this -> query_type , 'show fields' ) !== false || stripos ( $this -> query_type , 'show full columns' ) !== false ) {
$this -> query_type = 'showcolumns' ;
} elseif ( stripos ( $this -> query_type , 'show index' ) !== false || stripos ( $this -> query_type , 'show indexes' ) !== false || stripos ( $this -> query_type , 'show keys' ) !== false ) {
$this -> query_type = 'showindex' ;
} elseif ( stripos ( $this -> query_type , 'show variables' ) !== false || stripos ( $this -> query_type , 'show global variables' ) !== false || stripos ( $this -> query_type , 'show session variables' ) !== false ) {
$this -> query_type = 'show_variables' ;
} else {
return false ;
}
}
if ( stripos ( $this -> query_type , 'drop index' ) !== false ) {
$this -> query_type = 'drop_index' ;
}
return true ;
}
2013-07-07 06:49:38 +00:00
2014-07-14 08:46:32 +00:00
/**
* Method to execute INSERT query for SQLite version 3.7 . 11 or later .
*
* SQLite version 3.7 . 11 began to support multiple rows insert with values
* clause . This is for that version or later .
*
* @ param string $query
*/
private function execute_insert_query_new ( $query ) {
$engine = $this -> prepare_engine ( $this -> query_type );
$this -> rewritten_query = $engine -> rewrite_query ( $query , $this -> query_type );
$this -> queries [] = " Rewritten: \n " . $this -> rewritten_query ;
$this -> extract_variables ();
$statement = $this -> prepare_query ();
$this -> execute_query ( $statement );
}
/**
* Method to execute INSERT query for SQLite version 3.7 . 10 or lesser .
*
* It executes the INSERT query for SQLite version 3.7 . 10 or lesser . It is
* necessary to rewrite multiple row values .
*
* @ param string $query
*/
private function execute_insert_query ( $query ) {
global $wpdb ;
$multi_insert = false ;
$statement = null ;
$engine = $this -> prepare_engine ( $this -> query_type );
if ( preg_match ( '/(INSERT.*?VALUES\\s*)(\(.*\))/imsx' , $query , $matched )) {
$query_prefix = $matched [ 1 ];
$values_data = $matched [ 2 ];
if ( stripos ( $values_data , 'ON DUPLICATE KEY' ) !== false ) {
$exploded_parts = $values_data ;
} elseif ( stripos ( $query_prefix , " INSERT INTO $wpdb->comments " ) !== false ) {
$exploded_parts = $values_data ;
} else {
$exploded_parts = $this -> parse_multiple_inserts ( $values_data );
}
$count = count ( $exploded_parts );
if ( $count > 1 ) {
$multi_insert = true ;
}
}
if ( $multi_insert ) {
$first = true ;
foreach ( $exploded_parts as $value ) {
if ( substr ( $value , - 1 , 1 ) === ')' ) {
$suffix = '' ;
} else {
$suffix = ')' ;
}
$query_string = $query_prefix . ' ' . $value . $suffix ;
$this -> rewritten_query = $engine -> rewrite_query ( $query_string , $this -> query_type );
$this -> queries [] = " Rewritten: \n " . $this -> rewritten_query ;
$this -> extracted_variables = array ();
$this -> extract_variables ();
if ( $first ) {
$statement = $this -> prepare_query ();