PageRenderTime 149ms CodeModel.GetById 80ms app.highlight 28ms RepoModel.GetById 32ms app.codeStats 1ms

/system/classes/databaseconnection.php

https://github.com/HabariMag/habarimag-old
PHP | 843 lines | 445 code | 73 blank | 325 comment | 57 complexity | 107ac59cdced650d11ae8f3a10bd348e MD5 | raw file
  1<?php
  2/**
  3 * @package Habari
  4 *
  5 */
  6
  7/**
  8 * Habari DatabaseConnection Class
  9 *
 10 * Actual database connection.
 11 */
 12class DatabaseConnection
 13{
 14	private $fetch_mode = PDO::FETCH_CLASS;          // PDO Fetch mode
 15	private $fetch_class_name = 'QueryRecord';       // The default class name for fetching classes
 16	private $driver;                                 // PDO driver name
 17	private $keep_profile = DEBUG;                   // keep profiling and timing information?
 18	protected $pdo = null;                           // handle to the PDO interface
 19	private $pdo_statement = null;                   // handle for a PDOStatement
 20	private $pdo_transaction = false;                // handle for transaction status
 21
 22	/**
 23	 * @var array tables Habari knows about
 24	 */
 25	private $tables = array(
 26		'blocks',
 27		'blocks_areas',
 28		'commentinfo',
 29		'comments',
 30		'crontab',
 31		'groups',
 32		'group_token_permissions',
 33		'log',
 34		'log_types',
 35		'object_terms',
 36		'object_types',
 37		'options',
 38		'post_tokens',
 39		'postinfo',
 40		'posts',
 41		'poststatus',
 42		'posttype',
 43		'rewrite_rules',
 44		'scopes',
 45		'sessions',
 46		'tags',
 47		'tag2post',
 48		'terms',
 49		'terminfo',
 50		'tokens',
 51		'userinfo',
 52		'users',
 53		'user_token_permissions',
 54		'users_groups',
 55		'vocabularies',
 56	);
 57
 58	/**
 59	 * @var array mapping of table name -> prefixed table name
 60	 */
 61	private $sql_tables = array();
 62	private $sql_tables_repl = array();
 63	private $errors = array();                       // an array of errors related to queries
 64	private $profiles = array();                     // an array of query profiles
 65
 66	protected $prefix = '';                          // class protected storage of the database table prefix, defaults to ''
 67	private $current_table;
 68
 69	/**
 70	 * Returns the appropriate type of Connection class for the connect string passed or null on failure
 71	 *
 72	 * @param connection_string a PDO connection string
 73	 * @return  mixed returns appropriate DatabaseConnection child class instance or errors out if requiring the db class fails
 74	 */
 75	public static function ConnectionFactory( $connect_string )
 76	{
 77		list( $engine ) = explode( ':', $connect_string, 2 );
 78		require_once( HABARI_PATH . "/system/schema/{$engine}/connection.php" );
 79		$engine .= 'Connection';
 80		return new $engine();
 81	}
 82
 83	/**
 84	 * Populate the table mapping.
 85	 *
 86	 * @return void
 87	 */
 88	protected function load_tables()
 89	{
 90		if ( isset( Config::get( 'db_connection' )->prefix ) ) {
 91			$prefix = Config::get( 'db_connection' )->prefix;
 92		}
 93		else {
 94			$prefix = $this->prefix;
 95		}
 96		$this->prefix = $prefix;
 97
 98		// build the mapping with prefixes
 99		foreach ( $this->tables as $t ) {
100			$this->sql_tables[$t] = $prefix . $t;
101			$this->sql_tables_repl[$t] = '{' . $t . '}';
102		}
103	}
104
105	/**
106	 * Connect to a database server
107	 *
108	 * @param string $connect_string a PDO connection string
109	 * @param string $db_user the database user name
110	 * @param string $db_pass the database user password
111	 * @return boolean true on success, false on error
112	 */
113	public function connect ( $connect_string, $db_user, $db_pass )
114	{
115		$this->pdo = @new PDO( $connect_string, $db_user, $db_pass );
116		$this->pdo->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING );
117		$this->load_tables();
118		return true;
119	}
120
121	/**
122	 * Disconnect from the database server.
123	 *
124	 * @return boolean true
125	 */
126	public function disconnect()
127	{
128		$this->pdo = null; // this is the canonical way :o
129
130		return true;
131	}
132
133	/**
134	 * Check whether there is an existing connection to a database.
135	 *
136	 * @return boolean
137	 */
138	public function is_connected()
139	{
140		return ( null != $this->pdo );
141	}
142
143	/**
144	 * Check whether there is a transaction underway.
145	 *
146	 * @return boolean
147	 */
148	public function in_transaction()
149	{
150		return $this->pdo_transaction;
151	}
152
153	/**
154	 * Get the full table name for the given table.
155	 *
156	 * @param string $name name of the table
157	 * @return string the full table name, or false if the table was not found
158	 */
159	public function table( $name )
160	{
161		if ( isset( $this->sql_tables[$name] ) ) {
162			return $this->sql_tables[$name];
163		}
164		else {
165			return false;
166		}
167	}
168
169	/**
170	 * Adds a table to the list of tables known to Habari.  Used
171	 * by Theme and Plugin classes to inform the DB class about
172	 * custom tables used by the plugin
173	 *
174	 * @param name the table name
175	 */
176	public function register_table( $name )
177	{
178		$this->tables[] = $name;
179		$this->load_tables();
180	}
181
182	/**
183	 * Sets the fetch mode for return calls from PDOStatement
184	 *
185	 * @param mode  One of the PDO::FETCH_MODE integers
186	 */
187	public function set_fetch_mode( $mode )
188	{
189		$this->fetch_mode = $mode;
190	}
191
192	/**
193	 * Sets the class to fetch, if fetch mode is PDO::FETCH_CLASS
194	 *
195	 * @param class_name  Name of class to create during fetch
196	 */
197	public function set_fetch_class( $class_name )
198	{
199		$this->fetch_class_name = $class_name;
200	}
201
202	/**
203	 * Execute the given query on the database. Encapsulates PDO::exec.
204	 * WARNING: Make sure you don't call this with a SELECT statement.
205	 * PDO will buffer the results and leave your cursor dangling.
206	 *
207	 * @param string $query the query to run
208	 * @return boolean true on success, false on error
209	 */
210	public function exec( $query )
211	{
212		// Allow plugins to modify the query
213		$query = Plugins::filter( 'db_exec', $query, array() );
214		// Translate the query for the database engine
215		$query = $this->sql_t( $query, array() );
216		// Replace braced table names in the query with their prefixed counterparts
217		$query = self::filter_tables( $query );
218		// Allow plugins to modify the query after it has been processed
219		$query = Plugins::filter( 'db_exec_postprocess', $query, array() );
220
221		return ( $this->pdo->exec( $query ) !== false );
222	}
223
224	/**
225	 * Execute a SQL statement.
226	 *
227	 * @param string $query the SQL statement
228	 * @param array $args values for the bound parameters
229	 * @return boolean true on success, false on failure
230	 */
231	public function query( $query, $args = array() )
232	{
233		if ( $this->pdo_statement != null ) {
234			$this->pdo_statement->closeCursor();
235		}
236
237		// Allow plugins to modify the query
238		$query = Plugins::filter( 'query', $query, $args );
239		// Translate the query for the database engine
240		$query = $this->sql_t( $query, $args );
241		// Replace braced table names in the query with their prefixed counterparts
242		$query = self::filter_tables( $query );
243		// Allow plugins to modify the query after it has been processed
244		$query = Plugins::filter( 'query_postprocess', $query, $args );
245
246		if ( $this->pdo_statement = $this->pdo->prepare( $query ) ) {
247			if ( $this->fetch_mode == PDO::FETCH_CLASS ) {
248				/* Try to get the result class autoloaded. */
249				if ( ! class_exists( strtolower( $this->fetch_class_name ) ) ) {
250					$tmp = $this->fetch_class_name;
251					new $tmp();
252				}
253				/* Ensure that the class is actually available now, otherwise segfault happens (if we haven't died earlier anyway). */
254				if ( class_exists( strtolower( $this->fetch_class_name ) ) ) {
255					$this->pdo_statement->setFetchMode( PDO::FETCH_CLASS, $this->fetch_class_name, array() );
256				}
257				else {
258					/* Die gracefully before the segfault occurs */
259					echo '<br><br>' . _t( 'Attempt to fetch in class mode with a non-included class' ) . '<br><br>';
260					return false;
261				}
262			}
263			else {
264				$this->pdo_statement->setFetchMode( $this->fetch_mode );
265			}
266
267			/* If we are profiling, then time the query */
268			if ( $this->keep_profile ) {
269				$profile = new QueryProfile( $query );
270				$profile->params = $args;
271				$profile->start();
272			}
273			if ( ! $this->pdo_statement->execute( $args ) ) {
274				$this->add_error( array( 'query'=>$query,'error'=>$this->pdo_statement->errorInfo() ) );
275				return false;
276			}
277			if ( $this->keep_profile ) {
278				$profile->stop();
279				$this->profiles[] = $profile;
280			}
281			return true;
282		}
283		else {
284			$this->add_error( array(
285				'query' => $query,
286				'error' => $this->pdo->errorInfo(),
287			) );
288			return false;
289		}
290	}
291
292	/**
293	 * Execute a stored procedure
294	 *
295	 * @param   procedure   name of the stored procedure
296	 * @param   args        arguments for the procedure
297	 * @return  mixed       whatever the procedure returns...
298	 * @experimental
299	 * @todo  EVERYTHING... :)
300	 * Implemented in child classes. Most RDBMS use ANSI-92 syntax,
301	 * @todo Make sure it's MultiByte safe
302	 * ( CALL procname ( param1, param2, ... ),
303	 * so they return the call to here. Those that don't, handle the call individually
304	 */
305	public function execute_procedure( $procedure, $args = array() )
306	{
307		/* Local scope caching */
308		$pdo = $this->pdo;
309		$pdo_statement = $this->pdo_statement;
310
311		if ( $pdo_statement != null ) {
312			$pdo_statement->closeCursor();
313		}
314
315		$query = 'CALL ' . $procedure . '( ';
316		if ( count( $args ) > 0 ) {
317			$query .= str_repeat( '?,', count( $args ) ); // Add the placeholders
318			$query = substr( $query, 0, strlen( $query ) - 1 ); // Strip the last comma
319		}
320		$query .= ' )';
321		$query = $this->sql_t( $query, $args );
322
323		if ( $pdo_statement = $pdo->prepare( $query ) ) {
324			/* If we are profiling, then time the query */
325			if ( $this->keep_profile ) {
326				$profile = new QueryProfile( $query );
327				$profile->start();
328			}
329			if ( ! $pdo_statement->execute( $args ) ) {
330				$this->add_error( array( 'query'=>$query,'error'=>$pdo_statement->errorInfo() ) );
331				return false;
332			}
333			if ( $this->keep_profile ) {
334				$profile->stop();
335				$this->profiles[] = $profile;
336			}
337			return true;
338		}
339		else {
340			$this->add_error( array( 'query'=>$query,'error'=>$pdo_statement->errorInfo() ) );
341			return false;
342		}
343	}
344
345	/**
346	 * Start a transaction against the RDBMS in order to wrap multiple
347	 * statements in a safe ACID-compliant container
348	 */
349	public function begin_transaction()
350	{
351		if ( ! $this->pdo_transaction ) {
352			$this->pdo->beginTransaction();
353			$this->pdo_transaction = true;
354		}
355	}
356
357	/**
358	 * Rolls a currently running transaction back to the
359	 * prexisting state, or, if the RDBMS supports it, whenever
360	 * a savepoint was committed.
361	 */
362	public function rollback()
363	{
364		if ( $this->pdo_transaction ) {
365			$this->pdo->rollBack();
366			$this->pdo_transaction = false;
367		}
368	}
369
370	/**
371	 * Commit a currently running transaction
372	 */
373	public function commit()
374	{
375		if ( $this->pdo_transaction ) {
376			$this->pdo->commit();
377			$this->pdo_transaction = false;
378		}
379	}
380
381	/**
382	 * Returns query profiles
383	 *
384	 * @return  array an array of query profiles
385	 */
386	public function get_profiles()
387	{
388		return $this->profiles;
389	}
390
391	/**
392	 * Adds an error to the internal collection
393	 *
394	 * @param   error   array( 'query'=>query, 'error'=>errorInfo )
395	 */
396	private function add_error( $error )
397	{
398		$backtrace1 = debug_backtrace();
399		$backtrace = array();
400		foreach ( $backtrace1 as $trace ) {
401			$backtrace[] = array_intersect_key( $trace, array('file'=>1, 'line'=>1, 'function'=>1, 'class'=>1) );
402		}
403		$this->errors[] = array_merge( $error, array( 'backtrace'=> $backtrace ) );
404	}
405
406	/**
407	 * Returns error data gathered from database connection
408	 * @return array An array of error data
409	 */
410	public function get_errors()
411	{
412		return $this->errors;
413	}
414
415	/**
416	 * Determines if there have been errors since the last clear_errors() call
417	 * @return boolean True if there were errors, false if not
418	 */
419	public function has_errors()
420	{
421		return ( count( $this->errors ) > 0 );
422	}
423
424	/**
425	 * Updates the last error pointer to simulate resetting the error array
426	 */
427	public function clear_errors()
428	{
429		$this->errors = array();
430	}
431
432	/**
433	 * Returns only the last error info
434	 * @return array Data for the last error
435	 */
436	public function get_last_error()
437	{
438		$error = end( $this->errors );
439		return ( array( 'query'=>$error['query'], 'message'=>$error['error'][2] ) );
440	}
441
442	/**
443	 * Execute a query and return the results as an array of objects
444	 * @param query   the query to execute
445	 * @param args    array of arguments to pass for prepared statements
446	 * @param string Optional class name for row result objects
447	 * @return array An array of QueryRecord or the named class each containing the row data
448	 * <code>$ary= DB::get_results( 'SELECT * FROM tablename WHERE foo= ?', array( 'fieldvalue' ), 'extendedQueryRecord' );</code>
449	 */
450	public function get_results( $query, $args = array() )
451	{
452		if ( func_num_args() == 3 ) {
453			/* Called expecting specific class return type */
454			$class_name = func_get_arg( 2 );
455		}
456		else {
457			$class_name = 'QueryRecord';
458		}
459		$this->set_fetch_mode( PDO::FETCH_CLASS );
460		$this->set_fetch_class( $class_name );
461		if ( $this->query( $query, $args ) ) {
462			return $this->pdo_statement->fetchAll();
463		}
464		else {
465			return false;
466		}
467	}
468
469	/**
470	 * Returns a single row (the first in a multi-result set) object for a query
471	 * @param string The query to execute
472	 * @param array Arguments to pass for prepared statements
473	 * @param string Optional class name for row result object
474	 * @return object A QueryRecord or an instance of the named class containing the row data
475	 * <code>$obj= DB::get_row( 'SELECT * FROM tablename WHERE foo= ?', array( 'fieldvalue' ), 'extendedQueryRecord' );</code>
476	 */
477	public function get_row( $query, $args = array() )
478	{
479		if ( func_num_args() == 3 ) {
480			/* Called expecting specific class return type */
481			$class_name = func_get_arg( 2 );
482		}
483		else {
484			$class_name = 'QueryRecord';
485		}
486
487		$this->set_fetch_mode( PDO::FETCH_CLASS );
488		$this->set_fetch_class( $class_name );
489
490		if ( $this->query( $query, $args ) ) {
491			return $this->pdo_statement->fetch();
492		}
493		else {
494			return false;
495		}
496	}
497
498	/**
499	 * Returns all values for a column for a query
500	 *
501	 * @param string The query to execute
502	 * @param array Arguments to pass for prepared statements
503	 * @return array An array containing the column data
504	 * <code>$ary= DB::get_column( 'SELECT col1 FROM tablename WHERE foo= ?', array( 'fieldvalue' ) );</code>
505	 */
506	public function get_column( $query, $args = array() )
507	{
508		if ( $this->query( $query, $args ) ) {
509			return $this->pdo_statement->fetchAll( PDO::FETCH_COLUMN );
510		}
511		else {
512			return false;
513		}
514	}
515
516	/**
517	 * Return a single value from the database
518	 *
519	 * @param string the query to execute
520	 * @param array Arguments to pass for prepared statements
521	 * @return mixed a single value ( int, string )
522	 */
523	public function get_value( $query, $args = array() )
524	{
525		if ( $this->query( $query, $args ) ) {
526			$result = $this->pdo_statement->fetch( PDO::FETCH_NUM );
527			return $result[0];
528		}
529		else {
530			return false;
531		}
532	}
533
534	/**
535	 * Returns an associative array using the first returned column as the array key and the second as the array value
536	 *
537	 * @param string The query to execute
538	 * @param array Arguments to pass for prepared statements
539	 * @return array An array containing the associative data
540	 * <code>$ary= $dbconnection->get_keyvalue( 'SELECT keyfield, valuefield FROM tablename');</code>
541	 */
542	public function get_keyvalue( $query, $args = array() )
543	{
544		if ( $this->query( $query, $args ) ) {
545			$result = $this->pdo_statement->fetchAll( PDO::FETCH_NUM );
546			$output = array();
547			foreach ( $result as $item ) {
548				$output[$item[0]] = $item[1];
549			}
550			return $output;
551		}
552		else {
553			return false;
554		}
555	}
556
557	/**
558	 * Inserts into the specified table values associated to the key fields
559	 * @param string The table name
560	 * @param array An associative array of fields and values to insert
561	 * @return boolean True on success, false if not
562	 * <code>DB::insert( 'mytable', array( 'fieldname' => 'value' ) );</code>
563	 */
564	public function insert( $table, $fieldvalues )
565	{
566		ksort( $fieldvalues );
567
568		$fields = array_keys( $fieldvalues );
569		$values = array_values( $fieldvalues );
570		
571		$query = "INSERT INTO {$table} ( " . implode( ', ', $fields ) . ' ) VALUES ( ' . implode( ', ', array_fill( 0, count( $values ), '?' ) ) . ' )';
572
573		// need to pass $table on to the $o singleton object;
574		$this->current_table = $table;
575
576		return $this->query( $query, $values );
577	}
578
579	/**
580	 * Checks for a record that matches the specific criteria
581	 * @param string Table to check
582	 * @param array Associative array of field values to match
583	 * @return boolean True if any matching record exists, false if not
584	 * <code>DB::exists( 'mytable', array( 'fieldname' => 'value' ) );</code>
585	 */
586	public function exists( $table, $keyfieldvalues )
587	{
588		$qry = "SELECT 1 as c FROM {$table} WHERE 1=1 ";
589
590		$values = array();
591		foreach ( $keyfieldvalues as $keyfield => $keyvalue ) {
592			$qry .= " AND {$keyfield} = ? ";
593			$values[] = $keyvalue;
594		}
595		$result = $this->get_row( $qry, $values );
596		return ( $result !== false );
597	}
598
599	/**
600	 * function update
601	 * Updates any record that matches the specific criteria
602	 * A new row is inserted if no existing record matches the criteria
603	 * @param string Table to update
604	 * @param array Associative array of field values to set
605	 * @param array Associative array of field values to match
606	 * @return boolean True on success, false if not
607	 * <code>DB::update( 'mytable', array( 'fieldname' => 'newvalue' ), array( 'fieldname' => 'value' ) );</code>
608	 */
609	public function update( $table, $fieldvalues, $keyfields )
610	{
611		ksort( $fieldvalues );
612		ksort( $keyfields );
613
614		$keyfieldvalues = array();
615		foreach ( $keyfields as $keyfield => $keyvalue ) {
616			if ( is_numeric( $keyfield ) ) {
617				// if the key is numeric, assume we were handed a simple list of fields that are keys and fetch its value from $fieldvalues
618				$keyfieldvalues[$keyvalue] = $fieldvalues[$keyvalue];
619			}
620			else {
621				// otherwise we were handed a key => value pair, use it as-is
622				$keyfieldvalues[$keyfield] = $keyvalue;
623			}
624		}
625		if ( $this->exists( $table, $keyfieldvalues ) ) {
626			$qry = "UPDATE {$table} SET";
627			$values = array();
628			$comma = '';
629			foreach ( $fieldvalues as $fieldname => $fieldvalue ) {
630				$qry .= $comma . " {$fieldname} = ?";
631				$values[] = $fieldvalue;
632				$comma = ' ,';
633			}
634			$qry .= ' WHERE 1=1 ';
635
636			foreach ( $keyfields as $keyfield => $keyvalue ) {
637				$qry .= "AND {$keyfield} = ? ";
638				$values[] = $keyvalue;
639			}
640			return $this->query( $qry, $values );
641		}
642		else {
643			// We want the keyfieldvalues to be included in
644			// the insert, with fieldvalues taking precedence.
645			$fieldvalues = $fieldvalues + $keyfieldvalues;
646			return $this->insert( $table, $fieldvalues );
647		}
648	}
649
650	/**
651	 * Deletes any record that matches the specific criteria
652	 * @param string Table to delete from
653	 * @param array Associative array of field values to match
654	 * @return boolean True on success, false if not
655	 * <code>DB::delete( 'mytable', array( 'fieldname' => 'value' ) );</code>
656	 */
657	public function delete( $table, $keyfields )
658	{
659		$qry = "DELETE FROM {$table} WHERE 1=1 ";
660		foreach ( $keyfields as $keyfield => $keyvalue ) {
661			$qry .= "AND {$keyfield} = ? ";
662			$values[] = $keyvalue;
663		}
664
665		return $this->query( $qry, $values );
666	}
667
668	/**
669	 * Helper function to return the last inserted sequence or
670	 * auto_increment field.  Useful when doing multiple inserts
671	 * within a single transaction -- for example, adding dependent
672	 * related rows.
673	 *
674	 * @return  mixed The last sequence value ( RDBMS-dependent! )
675	 * @see     http://us2.php.net/manual/en/function.pdo-lastinsertid.php
676	 */
677	public function last_insert_id()
678	{
679		if ( $this->pdo->getAttribute( PDO::ATTR_DRIVER_NAME ) == 'pgsql' ) {
680			return $this->pdo->lastInsertId( $this->current_table. '_pkey_seq' );
681		}
682		else {
683			return $this->pdo->lastInsertId( func_num_args() == 1 ? func_get_arg( 0 ) : '' );
684		}
685	}
686
687	/**
688	 * Automatic diffing function, used for determining required database upgrades.
689	 * Implemented in child classes.
690	 */
691	public function dbdelta( $queries, $execute = true, $silent = true ){}
692
693	public function upgrade_pre( $old_version ){}
694
695	public function upgrade_post( $old_version ){}
696
697
698	/**
699	 * Updates the content of the database between versions.
700	 * Implemented in child classes.
701	 *
702	 * @param integer $old_version The old Version::DB_VERSION
703	 */
704	public function upgrade( $old_version, $upgrade_path = '' )
705	{
706		// Get all the upgrade files
707		$upgrade_files = Utils::glob( "{$upgrade_path}/*.sql" );
708
709		// Put the upgrade files into an array using the 0-padded revision + '_0' as the key
710		$upgrades = array();
711		foreach ( $upgrade_files as $file ) {
712			if ( intval( basename( $file, '.sql' ) ) > $old_version ) {
713				$upgrades[ sprintf( '%010s_0', basename( $file, '.sql' ) )] = $file;
714			}
715		}
716		// Put the upgrade functions into an array using the 0-padded revision + '_1' as the key
717		$upgrade_functions = get_class_methods( $this );
718		foreach ( $upgrade_functions as $fn ) {
719			if ( preg_match( '%^upgrade_([0-9]+)$%i', $fn, $matches ) ) {
720				if ( intval( $matches[1] ) > $old_version ) {
721					$upgrades[ sprintf( '%010s_1', $matches[1] )] = array( $this, $fn );
722				}
723			}
724		}
725
726		// Sort the upgrades by revision, ascending
727		ksort( $upgrades );
728
729		// Execute all of the upgrade functions
730		$result = true;
731		foreach ( $upgrades as $upgrade ) {
732			if ( is_array( $upgrade ) ) {
733				$result &= $upgrade();
734			}
735			else {
736				$result &= $this->query_file( $upgrade );
737			}
738			if ( !$result ) {
739				break;
740			}
741		}
742
743		return $result;
744	}
745
746	/**
747	 * Load a file containing queries, replace the prefix, execute all queries present
748	 *
749	 * @param string $file The filename containing the queries
750	 * @return boolean True on successful execution of all queries
751	 */
752	public function query_file( $file )
753	{
754		$upgrade_sql = trim( file_get_contents( $file ) );
755		$upgrade_sql = str_replace( '{$prefix}', $this->prefix, $upgrade_sql );
756
757		// Split up the queries
758		$queries = explode( ';', $upgrade_sql );
759
760		foreach ( $queries as $query ) {
761			if ( trim( $query ) != '' ) {
762				if ( !$this->query( $query ) ) {
763					return false;
764				}
765			}
766		}
767
768		return true;
769	}
770
771
772	/**
773	 * Translates the query for the current database engine
774	 *
775	 * @param string $query The query to translate for the current database engine
776	 * @param array $args Arguments to the query
777	 * @return string The translated query
778	 */
779	public function sql_t( $query )
780	{
781		return $query;
782	}
783
784	/**
785	 * Replace braced table names with their prefixed counterparts
786	 *
787	 * @param string $query The query with {braced} table names
788	 * @return string The translated query
789	 */
790	public function filter_tables( $query )
791	{
792		return str_replace( $this->sql_tables_repl, $this->sql_tables, $query );
793	}
794
795	public function get_driver_name()
796	{
797		if ( ! $this->driver ) {
798			$this->driver = $this->pdo->getAttribute( PDO::ATTR_DRIVER_NAME );
799		}
800		return $this->driver;
801	}
802
803	public function get_driver_version()
804	{
805		return $this->pdo->getAttribute( PDO::ATTR_SERVER_VERSION );
806	}
807
808	/**
809	 * Returns number of rows affected by the last DELETE, INSERT, or UPDATE
810	 *
811	 * @return int The number of rows affected.
812	 */
813	public function row_count()
814	{
815		return $this->pdo_statement->rowCount();
816	}
817
818	/**
819	 * Returns a list of tables the DB currently knows about.
820	 *
821	 * @return array The list of tables.
822	 */
823	public function list_tables()
824	{
825		return $this->sql_tables;
826	}
827
828	/**
829	 * Return a PDO-quoted string appropriate for the DB backend we're using.
830	 *
831	 * If you're using this then there's 99+% probability you're building your queries the wrong way!
832	 *
833	 * @param string $string The string to quote.
834	 * @return string A DB-safe quoted string.
835	 */
836	public function quote ( $string )
837	{
838		return $this->pdo->quote( $string );
839	}
840
841}
842
843?>