/system/schema/sqlite/connection.php
PHP | 234 lines | 142 code | 20 blank | 72 comment | 26 complexity | 33794720554874949f6b42ddefa02a13 MD5 | raw file
Possible License(s): Apache-2.0
- <?php
- /**
- * Habari database specific connection class
- *
- * @package Habari
- */
- class SQLiteConnection extends DatabaseConnection
- {
- /**
- * database specific SQL translation function, loosely modelled on the
- * internationalization _t() function
- * Call with a database independent SQL string and it will be translated
- * to a SQLite specific SQL string
- *
- * @param sql database independent SQL
- * @return string translated SQL string
- */
- function sql_t( $sql )
- {
- $sql = preg_replace_callback( '%concat\(([^)]+?)\)%i', array( &$this, 'replace_concat' ), $sql );
- $sql = preg_replace( '%DATE_SUB\s*\(\s*NOW\(\s*\)\s*,\s*INTERVAL\s+([0-9]+)\s+DAY\s*\)%ims', 'date(\'now\', \'-${1} days\')', $sql );
- $sql = preg_replace( '%OPTIMIZE TABLE ([^ ]*)%i', 'VACUUM;', $sql );
- //$sql= preg_replace( '%YEAR\s*\(\s*([^ ]*)\s*\)%ims', 'strftime(\'%Y\', ${1})', $sql );
- //$sql= preg_replace( '%MONTH\s*\(\s*([^ ]*)\s*\)%ims', 'strftime(\'%m\', ${1})', $sql );
- //$sql= preg_replace( '%DAY\s*\(\s*([^ ]*)\s*\)%ims', 'strftime(\'%d\', ${1})', $sql );
- $sql = preg_replace( '%YEAR\s*\(\s*FROM_UNIXTIME\s*\(\s*([^ ]*)\s*\)\s*\)%ims', 'strftime(\'%Y\', ${1}, \'unixepoch\')', $sql );
- $sql = preg_replace( '%MONTH\s*\(\s*FROM_UNIXTIME\s*\(\s*([^ ]*)\s*\)\s*\)%ims', 'strftime(\'%m\', ${1}, \'unixepoch\')', $sql );
- $sql = preg_replace( '%DAY\s*\(\s*FROM_UNIXTIME\s*\(\s*([^ ]*)\s*\)\s*\)%ims', 'strftime(\'%d\', ${1}, \'unixepoch\')', $sql );
- $sql = preg_replace( '%TRUNCATE \s*([^ ]*)%i', 'DELETE FROM ${1}', $sql );
- $sql = preg_replace( '%RAND\s*\(\s*\)%i', 'RANDOM()', $sql );
- return $sql;
- }
- /**
- * Replaces the MySQL CONCAT function with SQLite-compatible statements
- * @todo needs work, kind of sucky conversion
- * @param array $matches Matches from the regex in sql_t()
- * @return string The replacement for the MySQL SQL
- * @see SQLiteConnection::sql_t()
- */
- function replace_concat( $matches )
- {
- $innards = explode( ',', $matches[1] );
- return implode( ' || ', $innards );
- }
- /**
- * Connect to SQLite
- * Overrides the DatabaseConnection to return false if the SQLite file doesn't exist.
- *
- * @param connection_string string a PDO connection string
- * @param db_user string the database user name
- * @param db_pass string the database user password
- * @return boolean True if connection succeeded, false if not.
- */
- public function connect( $connect_string, $db_user, $db_pass )
- {
- list( $type, $file )= explode( ':', $connect_string, 2 );
- if ( $file == basename( $file ) ) {
- if ( file_exists( HABARI_PATH . '/' . $file ) ) {
- $file = HABARI_PATH . '/' . $file;
- }
- else {
- $file = HABARI_PATH . '/' . Site::get_path( 'user', true ) . $file;
- }
- $connect_string = implode( ':', array( $type, $file ) );
- }
- if ( file_exists( $file ) && !is_writable( $file ) ) {
- die( _t( 'Database file "%s" must be writable.', array($file) ) );
- }
- $conn = parent::connect( $connect_string, $db_user, $db_pass );
- $this->exec( 'PRAGMA synchronous = OFF' );
- return $conn;
- }
- /**
- * automatic diffing function - used for determining required database upgrades
- * based on Owen Winkler's microwiki upgrade function
- *
- * @param queries array of create table and insert statements which constitute a fresh install
- * @param (optional) execute should the queries be executed against the database or just simulated. default = true
- * @param (optional) silent silent running with no messages printed? default = true
- * @return string translated SQL string
- */
- function dbdelta( $queries, $execute = true, $silent = true, $doinserts = false )
- {
- if ( !is_array( $queries ) ) {
- $queries = explode( ';', $queries );
- if ( '' == $queries[count( $queries ) - 1] ) {
- array_pop( $queries );
- }
- }
- $cqueries = array();
- $indexqueries = array();
- $iqueries = array();
- $pqueries = array();
- $for_update = array();
- $allqueries = array();
- foreach ( $queries as $qry ) {
- if ( preg_match( "|CREATE TABLE ([^ ]*)|", $qry, $matches ) ) {
- $cqueries[strtolower( $matches[1] )] = $qry;
- $for_update[$matches[1]] = 'Created table '.$matches[1];
- }
- else if ( preg_match( "|CREATE (UNIQUE )?INDEX ([^ ]*)|", $qry, $matches ) ) {
- $indexqueries[] = $qry;
- }
- else if ( preg_match( "|INSERT INTO ([^ ]*)|", $qry, $matches ) ) {
- $iqueries[] = $qry;
- }
- else if ( preg_match( "|UPDATE ([^ ]*)|", $qry, $matches ) ) {
- $iqueries[] = $qry;
- }
- else if ( preg_match ( "|PRAGMA ([^ ]*)|", $qry, $matches ) ) {
- $pqueries[] = $qry;
- }
- else {
- // Unrecognized query type
- }
- }
- // Merge the queries into allqueries; pragmas MUST go first
- $allqueries = array_merge($pqueries);
- $tables = $this->get_column( "SELECT name FROM sqlite_master WHERE type = 'table';" );
- foreach ( $cqueries as $tablename => $query ) {
- if ( in_array( $tablename, $tables ) ) {
- $sql = $this->get_value( "SELECT sql FROM sqlite_master WHERE type = 'table' AND name='" . $tablename . "';" );
- $sql = preg_replace( '%\s+%', ' ', $sql ) . ';';
- $query = preg_replace( '%\s+%', ' ', $query );
- if ( $sql != $query ) {
- $this->query("ALTER TABLE {$tablename} RENAME TO {$tablename}__temp;");
- $this->query($query);
- $new_fields_temp = $this->get_results( "pragma table_info({$tablename});" );
- $new_fields = array();
- foreach ( $new_fields_temp as $field ) {
- $new_fields[$field->name] = $field;
- }
- $old_fields = $this->get_results( "pragma table_info({$tablename}__temp);" );
- $new_field_names = array_map(array($this, 'filter_fieldnames'), $new_fields);
- $old_field_names = array_map(array($this, 'filter_fieldnames'), $old_fields);
- $used_field_names = array_intersect($new_field_names, $old_field_names);
- $used_field_names = implode(',', $used_field_names);
- $needed_fields = array_diff($new_field_names, $old_field_names);
- foreach ( $needed_fields as $needed_field_name ) {
- $used_field_names .= ",'" . $new_fields[$needed_field_name]->dflt_value . "' as " . $needed_field_name;
- }
- $this->query("INSERT INTO {$tablename} SELECT {$used_field_names} FROM {$tablename}__temp;");
- $this->query("DROP TABLE {$tablename}__temp;");
- }
- }
- else {
- $allqueries[] = $query;
- }
- }
- // Drop all indices that we created, they'll get recreated by indexqueries below.
- // The other option would be to loop through the indices, comparing with indexqueries, and only drop the ones that have changed.
- $indices = DB::get_column( "SELECT name FROM sqlite_master WHERE type='index' AND name NOT LIKE 'sqlite_autoindex_%'" );
- foreach ( $indices as $name ) {
- DB::exec( 'DROP INDEX ' . $name );
- }
- $allqueries = array_merge( $allqueries, $indexqueries );
- if ( $doinserts ) {
- $allqueries = array_merge( $allqueries, $iqueries );
- }
- if ( $execute ) {
- DB::exec( 'PRAGMA cache_size=4000' );
- foreach ( $allqueries as $query ) {
- if ( !$this->query( $query ) ) {
- $this->get_errors();
- return false;
- }
- }
- }
- return $allqueries;
- }
- /**
- * Execute a stored procedure
- *
- * @param procedure name of the stored procedure
- * @param args arguments for the procedure
- * @return mixed whatever the procedure returns...
- * Not supported with SQLite
- */
- public function execute_procedure( $procedure, $args = array() )
- {
- die( _t( 'not yet supported on SQLite' ) );
- }
- /**
- * Run all of the upgrades slated for pre-dbdelta since the last database revision.
- *
- * @param integer $old_version The current version of the database that is being upgraded
- * @return boolean True on success
- */
- public function upgrade_pre( $old_version, $upgrade_path = '' )
- {
- return parent::upgrade( $old_version, dirname(__FILE__) . '/upgrades/pre');
- }
- /**
- * Run all of the upgrades slated for post-dbdelta since the last database revision.
- *
- * @param integer $old_version The current version of the database that is being upgraded
- * @return boolean True on success
- */
- public function upgrade_post( $old_version, $upgrade_path = '' )
- {
- return parent::upgrade( $old_version, dirname(__FILE__) . '/upgrades/post');
- }
- /**
- * Filter out the fieldnames from whole pragma rows
- *
- * @param StdClass $row A row result from a SQLite PRAGMA table_info query
- * @return string The name of the associated field
- */
- protected function filter_fieldnames($row)
- {
- return $row->name;
- }
- }
- ?>