PageRenderTime 50ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

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