diff --git a/.gitignore b/.gitignore index 9794b52..3a27885 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ composer.lock .idea/ build/ vendor/ +test/temp/ diff --git a/composer.json b/composer.json index ce86305..920418d 100644 --- a/composer.json +++ b/composer.json @@ -14,15 +14,18 @@ } ], "require": { - "php": ">=7.1.0" + "php": ">=7.1.0", + "fuzeworks/core": "1.2.0-RC2", + "fuzeworks/mvcr": "1.2.0-RC2", + "ext-pdo": "*" }, "require-dev": { "phpunit/phpunit": "^7", - "fuzeworks/core": "1.2.0-BETA" + "fuzeworks/tracycomponent": "1.2.0-RC2" }, "autoload": { "psr-4": { "FuzeWorks\\": "src/FuzeWorks/" } } -} \ No newline at end of file +} diff --git a/src/Database/drivers/sqlite/sqlite_utility.php b/src/Config/config.database.php similarity index 63% rename from src/Database/drivers/sqlite/sqlite_utility.php rename to src/Config/config.database.php index d703bb1..c45a902 100644 --- a/src/Database/drivers/sqlite/sqlite_utility.php +++ b/src/Config/config.database.php @@ -1,10 +1,10 @@ db->display_error('db_unsupported_feature'); - } - -} +return [ + 'active_group' => 'default', + 'connections' => [ + 'default' => [ + 'engineName' => 'pdo', + 'dsn' => '', + 'hostname' => '', + 'username' => '', + 'password' => '', + 'database' => '', + 'prefix' => '', + 'persistent' => false, + 'debug' => false, + 'charset' => 'utf8', + 'collation' => 'utf8_general_ci' + ] + ] +]; \ No newline at end of file diff --git a/src/Database/DB.php b/src/Database/DB.php deleted file mode 100644 index 406a1fd..0000000 --- a/src/Database/DB.php +++ /dev/null @@ -1,207 +0,0 @@ -config->get('database'); - } catch (ConfigException $e) { - throw new DatabaseException($e->getMessage(), 1); - } - - // Determine if there are actually settings in the config file - if ( ! isset($config->databases) OR count($config->databases) === 0) - { - throw new DatabaseException('No database connection settings were found in the database config file.', 1); - } - - // Define the active group - $active_group = ($params !== '' ? $params : $config->active_group); - - if ( ! isset($active_group)) - { - throw new DatabaseException('You have not specified a database connection group via $active_group in your config.database.php file.', 1); - } - elseif ( ! isset($config->databases[$active_group])) - { - throw new DatabaseException('You have specified an invalid database connection group ('.$active_group.') in your config.database.php file.', 1); - } - - $params = $config->databases[$active_group]; - } - elseif (is_string($params)) - { - /** - * Parse the URL from the DSN string - * Database settings can be passed as discreet - * parameters or as a data source name in the first - * parameter. DSNs must have this prototype: - * $dsn = 'driver://username:password@hostname/database'; - */ - if (($dsn = @parse_url($params)) === FALSE) - { - throw new DatabaseException('Invalid DB Connection String', 1); - } - - $params = array( - 'dbdriver' => $dsn['scheme'], - 'hostname' => isset($dsn['host']) ? rawurldecode($dsn['host']) : '', - 'port' => isset($dsn['port']) ? rawurldecode($dsn['port']) : '', - 'username' => isset($dsn['user']) ? rawurldecode($dsn['user']) : '', - 'password' => isset($dsn['pass']) ? rawurldecode($dsn['pass']) : '', - 'database' => isset($dsn['path']) ? rawurldecode(substr($dsn['path'], 1)) : '' - ); - - // Were additional config items set? - if (isset($dsn['query'])) - { - parse_str($dsn['query'], $extra); - - foreach ($extra as $key => $val) - { - if (is_string($val) && in_array(strtoupper($val), array('TRUE', 'FALSE', 'NULL'))) - { - $val = var_export($val, TRUE); - } - - $params[$key] = $val; - } - } - } - - // No DB specified yet? Beat them senseless... - if (empty($params['dbdriver'])) - { - throw new DatabaseException('You have not selected a database type to connect to.', 1); - } - - // Load the DB classes. Note: Since the query builder class is optional - // we need to dynamically create a class that extends proper parent class - // based on whether we're using the query builder class or not. - if ($query_builder_override !== NULL) - { - $query_builder = $query_builder_override; - } - // Backwards compatibility work-around for keeping the - // $active_record config variable working. Should be - // removed in v3.1 - elseif ( ! isset($query_builder) && isset($active_record)) - { - $query_builder = $active_record; - } - - require_once(dirname(__DIR__) . DS . 'Database'.DS.'DB_driver.php'); - - if ( ! isset($query_builder) OR $query_builder === TRUE) - { - require_once(dirname(__DIR__) . DS . 'Database'.DS.'DB_query_builder.php'); - if ( ! class_exists('FW_DB', FALSE)) - { - /** - * FW_DB - * - * Acts as an alias for both FW_DB_driver and FW_DB_query_builder. - * - * @see FW_DB_query_builder - * @see FW_DB_driver - */ - class FW_DB extends FW_DB_query_builder { } - } - } - elseif ( ! class_exists('FW_DB', FALSE)) - { - /** - * @ignore - */ - class FW_DB extends FW_DB_driver { } - } - - // Load the DB driver - $driver_file = dirname(__DIR__) . DS . 'Database'.DS.'drivers'.DS.$params['dbdriver'].DS.$params['dbdriver'].'_driver.php'; - - if (!file_exists($driver_file)) - { - throw new DatabaseException("Invalid DB Driver", 1); - } - - require_once($driver_file); - - // Instantiate the DB adapter - $driver = 'FW_DB_'.$params['dbdriver'].'_driver'; - $DB = new $driver($params); - - // Check for a subdriver - if ( ! empty($DB->subdriver)) - { - $driver_file = dirname(__DIR__) . DS . 'Database'.DS.'drivers'.DS.$DB->dbdriver.DS.'subdrivers'.DS.$DB->dbdriver.'_'.$DB->subdriver.'_driver.php'; - - if (file_exists($driver_file)) - { - require_once($driver_file); - $driver = 'FW_DB_'.$DB->dbdriver.'_'.$DB->subdriver.'_driver'; - $DB = new $driver($params); - } - } - - $DB->initialize(); - return $DB; -} diff --git a/src/Database/DB_cache.php b/src/Database/DB_cache.php deleted file mode 100644 index a94b921..0000000 --- a/src/Database/DB_cache.php +++ /dev/null @@ -1,220 +0,0 @@ -db =& $db; - $this->factory = Factory::getInstance(); - $this->factory->helpers->load('file'); - - $this->check_path(); - } - - // -------------------------------------------------------------------- - - /** - * Set Cache Directory Path - * - * @param string $path Path to the cache directory - * @return bool - */ - public function check_path($path = '') - { - $path = ($path === '' ? Core::$tempDir . DS . 'Database' : $path); - - // Add a trailing slash to the path if needed - $path = realpath($path) - ? rtrim(realpath($path), DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR - : rtrim($path, '/').'/'; - - if ( ! is_dir($path)) - { - if (!mkdir($path, 0777, false)) - { - Logger::logDebug('DB cache path error: '.$path); - - // If the path is wrong we'll turn off caching - return $this->db->cache_off(); - } - } - - if ( ! Core::isReallyWritable($path)) - { - Logger::logDebug('DB cache dir not writable: '.$path); - - // If the path is not really writable we'll turn off caching - return $this->db->cache_off(); - } - - $this->db->cachedir = $path; - return TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Retrieve a cached query - * - * The URI being requested will become the name of the cache sub-folder. - * An MD5 hash of the SQL statement will become the cache file name. - * - * @param string $sql - * @return string - */ - public function read($sql) - { - $segment_one = ($this->factory->uri->segment(1) == FALSE) ? 'default' : $this->factory->uri->segment(1); - $segment_two = ($this->factory->uri->segment(2) == FALSE) ? 'index' : $this->factory->uri->segment(2); - $filepath = $this->db->cachedir.$segment_one.'+'.$segment_two.'/'.md5($sql); - - if (FALSE === ($cachedata = @file_get_contents($filepath))) - { - return FALSE; - } - - return unserialize($cachedata); - } - - // -------------------------------------------------------------------- - - /** - * Write a query to a cache file - * - * @param string $sql - * @param object $object - * @return bool - */ - public function write($sql, $object) - { - $segment_one = ($this->factory->uri->segment(1) == FALSE) ? 'default' : $this->factory->uri->segment(1); - $segment_two = ($this->factory->uri->segment(2) == FALSE) ? 'index' : $this->factory->uri->segment(2); - $dir_path = $this->db->cachedir.$segment_one.'+'.$segment_two.'/'; - $filename = md5($sql); - - if ( ! is_dir($dir_path) && ! @mkdir($dir_path, 0750)) - { - return FALSE; - } - - if (write_file($dir_path.$filename, serialize($object)) === FALSE) - { - return FALSE; - } - - chmod($dir_path.$filename, 0640); - return TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Delete cache files within a particular directory - * - * @param string $segment_one - * @param string $segment_two - * @return void - */ - public function delete($segment_one = '', $segment_two = '') - { - if ($segment_one === '') - { - $segment_one = ($this->factory->uri->segment(1) == FALSE) ? 'default' : $this->factory->uri->segment(1); - } - - if ($segment_two === '') - { - $segment_two = ($this->factory->uri->segment(2) == FALSE) ? 'index' : $this->factory->uri->segment(2); - } - - $dir_path = $this->db->cachedir.$segment_one.'+'.$segment_two.'/'; - delete_files($dir_path, TRUE); - } - - // -------------------------------------------------------------------- - - /** - * Delete all existing cache files - * - * @return void - */ - public function delete_all() - { - delete_files($this->db->cachedir, TRUE, TRUE); - } - -} diff --git a/src/Database/DB_driver.php b/src/Database/DB_driver.php deleted file mode 100644 index ff42036..0000000 --- a/src/Database/DB_driver.php +++ /dev/null @@ -1,2001 +0,0 @@ - $val) - { - $this->$key = $val; - } - } - - Logger::log('Database Driver ' . get_class($this) . ' Initialized'); - } - - // -------------------------------------------------------------------- - - /** - * Initialize Database Settings - * - * @return bool - */ - public function initialize() - { - /* If an established connection is available, then there's - * no need to connect and select the database. - * - * Depending on the database driver, conn_id can be either - * boolean TRUE, a resource or an object. - */ - if ($this->conn_id) - { - return TRUE; - } - - // ---------------------------------------------------------------- - - // Connect to the database and set the connection ID - $this->conn_id = $this->db_connect($this->pconnect); - - // No connection resource? Check if there is a failover else throw an error - if ( ! $this->conn_id) - { - // Check if there is a failover set - if ( ! empty($this->failover) && is_array($this->failover)) - { - // Go over all the failovers - foreach ($this->failover as $failover) - { - // Replace the current settings with those of the failover - foreach ($failover as $key => $val) - { - $this->$key = $val; - } - - // Try to connect - $this->conn_id = $this->db_connect($this->pconnect); - - // If a connection is made break the foreach loop - if ($this->conn_id) - { - break; - } - } - } - - // We still don't have a connection? - if ( ! $this->conn_id) - { - Logger::logError('Unable to connect to the database'); - - if ($this->db_debug) - { - $this->display_error('db_unable_to_connect'); - } - - return FALSE; - } - } - - // Now we set the character set and that's all - return $this->db_set_charset($this->char_set); - } - - // -------------------------------------------------------------------- - - /** - * DB connect - * - * This is just a dummy method that all drivers will override. - * - * @return mixed - */ - public function db_connect() - { - return TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Persistent database connection - * - * @return mixed - */ - public function db_pconnect() - { - return $this->db_connect(TRUE); - } - - // -------------------------------------------------------------------- - - /** - * Reconnect - * - * Keep / reestablish the db connection if no queries have been - * sent for a length of time exceeding the server's idle timeout. - * - * This is just a dummy method to allow drivers without such - * functionality to not declare it, while others will override it. - * - * @return void - */ - public function reconnect() - { - } - - // -------------------------------------------------------------------- - - /** - * Select database - * - * This is just a dummy method to allow drivers without such - * functionality to not declare it, while others will override it. - * - * @return bool - */ - public function db_select() - { - return TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Last error - * - * @return array - */ - public function error() - { - return array('code' => NULL, 'message' => NULL); - } - - // -------------------------------------------------------------------- - - /** - * Set client character set - * - * @param string - * @return bool - */ - public function db_set_charset($charset) - { - if (method_exists($this, '_db_set_charset') && ! $this->_db_set_charset($charset)) - { - Logger::logError('Unable to set database connection charset: '.$charset); - - if ($this->db_debug) - { - $this->display_error('db_unable_to_set_charset', $charset); - } - - return FALSE; - } - - return TRUE; - } - - // -------------------------------------------------------------------- - - /** - * The name of the platform in use (mysql, mssql, etc...) - * - * @return string - */ - public function platform() - { - return $this->dbdriver; - } - - // -------------------------------------------------------------------- - - /** - * Database version number - * - * Returns a string containing the version of the database being used. - * Most drivers will override this method. - * - * @return string - */ - public function version() - { - if (isset($this->data_cache['version'])) - { - return $this->data_cache['version']; - } - - if (FALSE === ($sql = $this->_version())) - { - return ($this->db_debug) ? $this->display_error('db_unsupported_function') : FALSE; - } - - $query = $this->query($sql)->row(); - return $this->data_cache['version'] = $query->ver; - } - - // -------------------------------------------------------------------- - - /** - * Version number query string - * - * @return string - */ - protected function _version() - { - return 'SELECT VERSION() AS ver'; - } - - // -------------------------------------------------------------------- - - /** - * Execute the query - * - * Accepts an SQL string as input and returns a result object upon - * successful execution of a "read" type query. Returns boolean TRUE - * upon successful execution of a "write" type query. Returns boolean - * FALSE upon failure, and if the $db_debug variable is set to TRUE - * will raise an error. - * - * @param string $sql - * @param array $binds = FALSE An array of binding data - * @param bool $return_object = NULL - * @return mixed - */ - public function query($sql, $binds = FALSE, $return_object = NULL) - { - if ($sql === '') - { - return ($this->db_debug) ? $this->display_error('db_invalid_query') : FALSE; - } - elseif ( ! is_bool($return_object)) - { - $return_object = ! $this->is_write_type($sql); - } - - // Verify table prefix and replace if necessary - if ($this->dbprefix !== '' && $this->swap_pre !== '' && $this->dbprefix !== $this->swap_pre) - { - $sql = preg_replace('/(\W)'.$this->swap_pre.'(\S+?)/', '\\1'.$this->dbprefix.'\\2', $sql); - } - - // Compile binds if needed - if ($binds !== FALSE) - { - $sql = $this->compile_binds($sql, $binds); - } - - // Is query caching enabled? If the query is a "read type" - // we will load the caching class and return the previously - // cached query if it exists - if ($this->cache_on === TRUE && $return_object === TRUE && $this->_cache_init()) - { - $this->load_rdriver(); - if (FALSE !== ($cache = $this->CACHE->read($sql))) - { - return $cache; - } - } - - // Save the query for debugging - if ($this->save_queries === TRUE) - { - $this->queries[] = $sql; - } - - // Start the Query Timer - $time_start = microtime(TRUE); - - // Run the Query - if (FALSE === ($this->result_id = $this->simple_query($sql))) - { - if ($this->save_queries === TRUE) - { - $this->query_times[] = 0; - $this->query_data[] = array('error' => $this->error(), 'rows' => 0); - } - - // This will trigger a rollback if transactions are being used - if ($this->_trans_depth !== 0) - { - $this->_trans_status = FALSE; - } - - // Grab the error now, as we might run some additional queries before displaying the error - $error = $this->error(); - - if ($this->db_debug) - { - // We call this function in order to roll-back queries - // if transactions are enabled. If we don't call this here - // the error message will trigger an exit, causing the - // transactions to remain in limbo. - while ($this->_trans_depth !== 0) - { - $trans_depth = $this->_trans_depth; - $this->trans_complete(); - if ($trans_depth === $this->_trans_depth) - { - Logger::logError('Database: Failure during an automated transaction commit/rollback!'); - break; - } - } - - // Display errors - return $this->display_error(array('Error Number: '.$error['code'], $error['message'], $sql)); - } - - return FALSE; - } - - // Stop and aggregate the query time results - $time_end = microtime(TRUE); - $this->benchmark += $time_end - $time_start; - - // Increment the query counter - $this->query_count++; - - // Will we have a result object instantiated? If not - we'll simply return TRUE - if ($return_object !== TRUE) - { - // If caching is enabled we'll auto-cleanup any existing files related to this particular URI - if ($this->cache_on === TRUE && $this->cache_autodel === TRUE && $this->_cache_init()) - { - $this->CACHE->delete(); - } - - return TRUE; - } - - // Load and instantiate the result driver - $driver = $this->load_rdriver(); - $RES = new $driver($this); - - if ($this->save_queries === TRUE) - { - $this->query_times[] = $time_end - $time_start; - $this->query_data[] = array('error' => $this->error(), 'rows' => $RES->num_rows()); - } - - // Is query caching enabled? If so, we'll serialize the - // result object and save it to a cache file. - if ($this->cache_on === TRUE && $this->_cache_init()) - { - // We'll create a new instance of the result object - // only without the platform specific driver since - // we can't use it with cached data (the query result - // resource ID won't be any good once we've cached the - // result object, so we'll have to compile the data - // and save it) - $CR = new FW_DB_result($this); - $CR->result_object = $RES->result_object(); - $CR->result_array = $RES->result_array(); - $CR->num_rows = $RES->num_rows(); - - // Reset these since cached objects can not utilize resource IDs. - $CR->conn_id = NULL; - $CR->result_id = NULL; - - $this->CACHE->write($sql, $CR); - } - - return $RES; - } - - // -------------------------------------------------------------------- - - /** - * Load the result drivers - * - * @return string the name of the result class - */ - public function load_rdriver() - { - $driver = 'FW_DB_'.$this->dbdriver.'_result'; - - if ( ! class_exists($driver, FALSE)) - { - require_once(dirname(__DIR__) . DS . 'Database'.DS.'DB_result.php'); - require_once(dirname(__DIR__) . DS . 'Database'.DS.'drivers'.DS.$this->dbdriver.DS.$this->dbdriver.'_result.php'); - } - - return $driver; - } - - // -------------------------------------------------------------------- - - /** - * Simple Query - * This is a simplified version of the query() function. Internally - * we only use it when running transaction commands since they do - * not require all the features of the main query() function. - * - * @param string the sql query - * @return mixed - */ - public function simple_query($sql) - { - if ( ! $this->conn_id) - { - if ( ! $this->initialize()) - { - return FALSE; - } - } - - return $this->_execute($sql); - } - - // -------------------------------------------------------------------- - - /** - * Disable Transactions - * This permits transactions to be disabled at run-time. - * - * @return void - */ - public function trans_off() - { - $this->trans_enabled = FALSE; - } - - // -------------------------------------------------------------------- - - /** - * Enable/disable Transaction Strict Mode - * - * When strict mode is enabled, if you are running multiple groups of - * transactions, if one group fails all subsequent groups will be - * rolled back. - * - * If strict mode is disabled, each group is treated autonomously, - * meaning a failure of one group will not affect any others - * - * @param bool $mode = TRUE - * @return void - */ - public function trans_strict($mode = TRUE) - { - $this->trans_strict = is_bool($mode) ? $mode : TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Start Transaction - * - * @param bool $test_mode = FALSE - * @return bool - */ - public function trans_start($test_mode = FALSE) - { - if ( ! $this->trans_enabled) - { - return FALSE; - } - - return $this->trans_begin($test_mode); - } - - // -------------------------------------------------------------------- - - /** - * Complete Transaction - * - * @return bool - */ - public function trans_complete() - { - if ( ! $this->trans_enabled) - { - return FALSE; - } - - // The query() function will set this flag to FALSE in the event that a query failed - if ($this->_trans_status === FALSE OR $this->_trans_failure === TRUE) - { - $this->trans_rollback(); - - // If we are NOT running in strict mode, we will reset - // the _trans_status flag so that subsequent groups of - // transactions will be permitted. - if ($this->trans_strict === FALSE) - { - $this->_trans_status = TRUE; - } - - Logger::logDebug('DB Transaction Failure'); - return FALSE; - } - - return $this->trans_commit(); - } - - // -------------------------------------------------------------------- - - /** - * Lets you retrieve the transaction flag to determine if it has failed - * - * @return bool - */ - public function trans_status() - { - return $this->_trans_status; - } - - // -------------------------------------------------------------------- - - /** - * Begin Transaction - * - * @param bool $test_mode - * @return bool - */ - public function trans_begin($test_mode = FALSE) - { - if ( ! $this->trans_enabled) - { - return FALSE; - } - // When transactions are nested we only begin/commit/rollback the outermost ones - elseif ($this->_trans_depth > 0) - { - $this->_trans_depth++; - return TRUE; - } - - // Reset the transaction failure flag. - // If the $test_mode flag is set to TRUE transactions will be rolled back - // even if the queries produce a successful result. - $this->_trans_failure = ($test_mode === TRUE); - - if ($this->_trans_begin()) - { - $this->_trans_depth++; - return TRUE; - } - - return FALSE; - } - - // -------------------------------------------------------------------- - - /** - * Commit Transaction - * - * @return bool - */ - public function trans_commit() - { - if ( ! $this->trans_enabled OR $this->_trans_depth === 0) - { - return FALSE; - } - // When transactions are nested we only begin/commit/rollback the outermost ones - elseif ($this->_trans_depth > 1 OR $this->_trans_commit()) - { - $this->_trans_depth--; - return TRUE; - } - - return FALSE; - } - - // -------------------------------------------------------------------- - - /** - * Rollback Transaction - * - * @return bool - */ - public function trans_rollback() - { - if ( ! $this->trans_enabled OR $this->_trans_depth === 0) - { - return FALSE; - } - // When transactions are nested we only begin/commit/rollback the outermost ones - elseif ($this->_trans_depth > 1 OR $this->_trans_rollback()) - { - $this->_trans_depth--; - return TRUE; - } - - return FALSE; - } - - // -------------------------------------------------------------------- - - /** - * Compile Bindings - * - * @param string the sql statement - * @param array an array of bind data - * @return string - */ - public function compile_binds($sql, $binds) - { - if (empty($binds) OR empty($this->bind_marker) OR strpos($sql, $this->bind_marker) === FALSE) - { - return $sql; - } - elseif ( ! is_array($binds)) - { - $binds = array($binds); - $bind_count = 1; - } - else - { - // Make sure we're using numeric keys - $binds = array_values($binds); - $bind_count = count($binds); - } - - // We'll need the marker length later - $ml = strlen($this->bind_marker); - - // Make sure not to replace a chunk inside a string that happens to match the bind marker - if ($c = preg_match_all("/'[^']*'/i", $sql, $matches)) - { - $c = preg_match_all('/'.preg_quote($this->bind_marker, '/').'/i', - str_replace($matches[0], - str_replace($this->bind_marker, str_repeat(' ', $ml), $matches[0]), - $sql, $c), - $matches, PREG_OFFSET_CAPTURE); - - // Bind values' count must match the count of markers in the query - if ($bind_count !== $c) - { - return $sql; - } - } - elseif (($c = preg_match_all('/'.preg_quote($this->bind_marker, '/').'/i', $sql, $matches, PREG_OFFSET_CAPTURE)) !== $bind_count) - { - return $sql; - } - - do - { - $c--; - $escaped_value = $this->escape($binds[$c]); - if (is_array($escaped_value)) - { - $escaped_value = '('.implode(',', $escaped_value).')'; - } - $sql = substr_replace($sql, $escaped_value, $matches[0][$c][1], $ml); - } - while ($c !== 0); - - return $sql; - } - - // -------------------------------------------------------------------- - - /** - * Determines if a query is a "write" type. - * - * @param string An SQL query string - * @return bool - */ - public function is_write_type($sql) - { - return (bool) preg_match('/^\s*"?(SET|INSERT|UPDATE|DELETE|REPLACE|CREATE|DROP|TRUNCATE|LOAD|COPY|ALTER|RENAME|GRANT|REVOKE|LOCK|UNLOCK|REINDEX)\s/i', $sql); - } - - // -------------------------------------------------------------------- - - /** - * Calculate the aggregate query elapsed time - * - * @param int The number of decimal places - * @return string - */ - public function elapsed_time($decimals = 6) - { - return number_format($this->benchmark, $decimals); - } - - // -------------------------------------------------------------------- - - /** - * Returns the total number of queries - * - * @return int - */ - public function total_queries() - { - return $this->query_count; - } - - // -------------------------------------------------------------------- - - /** - * Returns the last query that was executed - * - * @return string - */ - public function last_query() - { - return end($this->queries); - } - - // -------------------------------------------------------------------- - - /** - * "Smart" Escape String - * - * Escapes data based on type - * Sets boolean and null types - * - * @param string - * @return mixed - */ - public function escape($str) - { - if (is_array($str)) - { - $str = array_map(array(&$this, 'escape'), $str); - return $str; - } - elseif (is_string($str) OR (is_object($str) && method_exists($str, '__toString'))) - { - return "'".$this->escape_str($str)."'"; - } - elseif (is_bool($str)) - { - return ($str === FALSE) ? 0 : 1; - } - elseif ($str === NULL) - { - return 'NULL'; - } - - return $str; - } - - // -------------------------------------------------------------------- - - /** - * Escape String - * - * @param string|string[] $str Input string - * @param bool $like Whether or not the string will be used in a LIKE condition - * @return string - */ - public function escape_str($str, $like = FALSE) - { - if (is_array($str)) - { - foreach ($str as $key => $val) - { - $str[$key] = $this->escape_str($val, $like); - } - - return $str; - } - - $str = $this->_escape_str($str); - - // escape LIKE condition wildcards - if ($like === TRUE) - { - return str_replace( - array($this->_like_escape_chr, '%', '_'), - array($this->_like_escape_chr.$this->_like_escape_chr, $this->_like_escape_chr.'%', $this->_like_escape_chr.'_'), - $str - ); - } - - return $str; - } - - // -------------------------------------------------------------------- - - /** - * Escape LIKE String - * - * Calls the individual driver for platform - * specific escaping for LIKE conditions - * - * @param string|string[] - * @return mixed - */ - public function escape_like_str($str) - { - return $this->escape_str($str, TRUE); - } - - // -------------------------------------------------------------------- - - /** - * Platform-dependant string escape - * - * @param string - * @return string - */ - protected function _escape_str($str) - { - return str_replace("'", "''", Utf8::remove_invisible_characters($str)); - } - - // -------------------------------------------------------------------- - - /** - * Primary - * - * Retrieves the primary key. It assumes that the row in the first - * position is the primary key - * - * @param string $table Table name - * @return string - */ - public function primary($table) - { - $fields = $this->list_fields($table); - return is_array($fields) ? current($fields) : FALSE; - } - - // -------------------------------------------------------------------- - - /** - * "Count All" query - * - * Generates a platform-specific query string that counts all records in - * the specified database - * - * @param string - * @return int - */ - public function count_all($table = '') - { - if ($table === '') - { - return 0; - } - - $query = $this->query($this->_count_string.$this->escape_identifiers('numrows').' FROM '.$this->protect_identifiers($table, TRUE, NULL, FALSE)); - if ($query->num_rows() === 0) - { - return 0; - } - - $query = $query->row(); - $this->_reset_select(); - return (int) $query->numrows; - } - - // -------------------------------------------------------------------- - - /** - * Returns an array of table names - * - * @param string $constrain_by_prefix = FALSE - * @return array - */ - public function list_tables($constrain_by_prefix = FALSE) - { - // Is there a cached result? - if (isset($this->data_cache['table_names'])) - { - return $this->data_cache['table_names']; - } - - if (FALSE === ($sql = $this->_list_tables($constrain_by_prefix))) - { - return ($this->db_debug) ? $this->display_error('db_unsupported_function') : FALSE; - } - - $this->data_cache['table_names'] = array(); - $query = $this->query($sql); - - foreach ($query->result_array() as $row) - { - // Do we know from which column to get the table name? - if ( ! isset($key)) - { - if (isset($row['table_name'])) - { - $key = 'table_name'; - } - elseif (isset($row['TABLE_NAME'])) - { - $key = 'TABLE_NAME'; - } - else - { - /* We have no other choice but to just get the first element's key. - * Due to array_shift() accepting its argument by reference, if - * E_STRICT is on, this would trigger a warning. So we'll have to - * assign it first. - */ - $key = array_keys($row); - $key = array_shift($key); - } - } - - $this->data_cache['table_names'][] = $row[$key]; - } - - return $this->data_cache['table_names']; - } - - // -------------------------------------------------------------------- - - /** - * Determine if a particular table exists - * - * @param string $table_name - * @return bool - */ - public function table_exists($table_name) - { - return in_array($this->protect_identifiers($table_name, TRUE, FALSE, FALSE), $this->list_tables()); - } - - // -------------------------------------------------------------------- - - /** - * Fetch Field Names - * - * @param string $table Table name - * @return array - */ - public function list_fields($table) - { - // Is there a cached result? - if (isset($this->data_cache['field_names'][$table])) - { - return $this->data_cache['field_names'][$table]; - } - - if (FALSE === ($sql = $this->_list_columns($table))) - { - return ($this->db_debug) ? $this->display_error('db_unsupported_function') : FALSE; - } - - $query = $this->query($sql); - $this->data_cache['field_names'][$table] = array(); - - foreach ($query->result_array() as $row) - { - // Do we know from where to get the column's name? - if ( ! isset($key)) - { - if (isset($row['column_name'])) - { - $key = 'column_name'; - } - elseif (isset($row['COLUMN_NAME'])) - { - $key = 'COLUMN_NAME'; - } - else - { - // We have no other choice but to just get the first element's key. - $key = key($row); - } - } - - $this->data_cache['field_names'][$table][] = $row[$key]; - } - - return $this->data_cache['field_names'][$table]; - } - - // -------------------------------------------------------------------- - - /** - * Determine if a particular field exists - * - * @param string - * @param string - * @return bool - */ - public function field_exists($field_name, $table_name) - { - return in_array($field_name, $this->list_fields($table_name)); - } - - // -------------------------------------------------------------------- - - /** - * Returns an object with field data - * - * @param string $table the table name - * @return array - */ - public function field_data($table) - { - $query = $this->query($this->_field_data($this->protect_identifiers($table, TRUE, NULL, FALSE))); - return ($query) ? $query->field_data() : FALSE; - } - - // -------------------------------------------------------------------- - - /** - * Escape the SQL Identifiers - * - * This function escapes column and table names - * - * @param mixed - * @return mixed - */ - public function escape_identifiers($item) - { - if ($this->_escape_char === '' OR empty($item) OR in_array($item, $this->_reserved_identifiers)) - { - return $item; - } - elseif (is_array($item)) - { - foreach ($item as $key => $value) - { - $item[$key] = $this->escape_identifiers($value); - } - - return $item; - } - // Avoid breaking functions and literal values inside queries - elseif (ctype_digit($item) OR $item[0] === "'" OR ($this->_escape_char !== '"' && $item[0] === '"') OR strpos($item, '(') !== FALSE) - { - return $item; - } - - static $preg_ec = array(); - - if (empty($preg_ec)) - { - if (is_array($this->_escape_char)) - { - $preg_ec = array( - preg_quote($this->_escape_char[0], '/'), - preg_quote($this->_escape_char[1], '/'), - $this->_escape_char[0], - $this->_escape_char[1] - ); - } - else - { - $preg_ec[0] = $preg_ec[1] = preg_quote($this->_escape_char, '/'); - $preg_ec[2] = $preg_ec[3] = $this->_escape_char; - } - } - - foreach ($this->_reserved_identifiers as $id) - { - if (strpos($item, '.'.$id) !== FALSE) - { - return preg_replace('/'.$preg_ec[0].'?([^'.$preg_ec[1].'\.]+)'.$preg_ec[1].'?\./i', $preg_ec[2].'$1'.$preg_ec[3].'.', $item); - } - } - - return preg_replace('/'.$preg_ec[0].'?([^'.$preg_ec[1].'\.]+)'.$preg_ec[1].'?(\.)?/i', $preg_ec[2].'$1'.$preg_ec[3].'$2', $item); - } - - // -------------------------------------------------------------------- - - /** - * Generate an insert string - * - * @param string the table upon which the query will be performed - * @param array an associative array data of key/values - * @return string - */ - public function insert_string($table, $data) - { - $fields = $values = array(); - - foreach ($data as $key => $val) - { - $fields[] = $this->escape_identifiers($key); - $values[] = $this->escape($val); - } - - return $this->_insert($this->protect_identifiers($table, TRUE, NULL, FALSE), $fields, $values); - } - - // -------------------------------------------------------------------- - - /** - * Insert statement - * - * Generates a platform-specific insert string from the supplied data - * - * @param string the table name - * @param array the insert keys - * @param array the insert values - * @return string - */ - protected function _insert($table, $keys, $values) - { - return 'INSERT INTO '.$table.' ('.implode(', ', $keys).') VALUES ('.implode(', ', $values).')'; - } - - // -------------------------------------------------------------------- - - /** - * Generate an update string - * - * @param string the table upon which the query will be performed - * @param array an associative array data of key/values - * @param mixed the "where" statement - * @return string - */ - public function update_string($table, $data, $where) - { - if (empty($where)) - { - return FALSE; - } - - $this->where($where); - - $fields = array(); - foreach ($data as $key => $val) - { - $fields[$this->protect_identifiers($key)] = $this->escape($val); - } - - $sql = $this->_update($this->protect_identifiers($table, TRUE, NULL, FALSE), $fields); - $this->_reset_write(); - return $sql; - } - - // -------------------------------------------------------------------- - - /** - * Update statement - * - * Generates a platform-specific update string from the supplied data - * - * @param string the table name - * @param array the update data - * @return string - */ - protected function _update($table, $values) - { - foreach ($values as $key => $val) - { - $valstr[] = $key.' = '.$val; - } - - return 'UPDATE '.$table.' SET '.implode(', ', $valstr) - .$this->_compile_wh('qb_where') - .$this->_compile_order_by() - .($this->qb_limit ? ' LIMIT '.$this->qb_limit : ''); - } - - // -------------------------------------------------------------------- - - /** - * Tests whether the string has an SQL operator - * - * @param string - * @return bool - */ - protected function _has_operator($str) - { - return (bool) preg_match('/(<|>|!|=|\sIS NULL|\sIS NOT NULL|\sEXISTS|\sBETWEEN|\sLIKE|\sIN\s*\(|\s)/i', trim($str)); - } - - // -------------------------------------------------------------------- - - /** - * Returns the SQL string operator - * - * @param string - * @return string - */ - protected function _get_operator($str) - { - static $_operators; - - if (empty($_operators)) - { - $_les = ($this->_like_escape_str !== '') - ? '\s+'.preg_quote(trim(sprintf($this->_like_escape_str, $this->_like_escape_chr)), '/') - : ''; - $_operators = array( - '\s*(?:<|>|!)?=\s*', // =, <=, >=, != - '\s*<>?\s*', // <, <> - '\s*>\s*', // > - '\s+IS NULL', // IS NULL - '\s+IS NOT NULL', // IS NOT NULL - '\s+EXISTS\s*\(.*\)', // EXISTS(sql) - '\s+NOT EXISTS\s*\(.*\)', // NOT EXISTS(sql) - '\s+BETWEEN\s+', // BETWEEN value AND value - '\s+IN\s*\(.*\)', // IN(list) - '\s+NOT IN\s*\(.*\)', // NOT IN (list) - '\s+LIKE\s+\S.*('.$_les.')?', // LIKE 'expr'[ ESCAPE '%s'] - '\s+NOT LIKE\s+\S.*('.$_les.')?' // NOT LIKE 'expr'[ ESCAPE '%s'] - ); - - } - - return preg_match('/'.implode('|', $_operators).'/i', $str, $match) - ? $match[0] : FALSE; - } - - // -------------------------------------------------------------------- - - /** - * Enables a native PHP function to be run, using a platform agnostic wrapper. - * - * @param string $function Function name - * @return mixed - */ - public function call_function($function) - { - $driver = ($this->dbdriver === 'postgre') ? 'pg_' : $this->dbdriver.'_'; - - if (FALSE === strpos($driver, $function)) - { - $function = $driver.$function; - } - - if ( ! function_exists($function)) - { - return ($this->db_debug) ? $this->display_error('db_unsupported_function') : FALSE; - } - - return (func_num_args() > 1) - ? call_user_func_array($function, array_slice(func_get_args(), 1)) - : call_user_func($function); - } - - // -------------------------------------------------------------------- - - /** - * Set Cache Directory Path - * - * @param string the path to the cache directory - * @return void - */ - public function cache_set_path($path = '') - { - $this->cachedir = $path; - } - - // -------------------------------------------------------------------- - - /** - * Enable Query Caching - * - * @return bool cache_on value - */ - public function cache_on() - { - return $this->cache_on = TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Disable Query Caching - * - * @return bool cache_on value - */ - public function cache_off() - { - return $this->cache_on = FALSE; - } - - // -------------------------------------------------------------------- - - /** - * Delete the cache files associated with a particular URI - * - * @param string $segment_one = '' - * @param string $segment_two = '' - * @return bool - */ - public function cache_delete($segment_one = '', $segment_two = '') - { - return $this->_cache_init() - ? $this->CACHE->delete($segment_one, $segment_two) - : FALSE; - } - - // -------------------------------------------------------------------- - - /** - * Delete All cache files - * - * @return bool - */ - public function cache_delete_all() - { - return $this->_cache_init() - ? $this->CACHE->delete_all() - : FALSE; - } - - // -------------------------------------------------------------------- - - /** - * Initialize the Cache Class - * - * @return bool - */ - protected function _cache_init() - { - if ( ! class_exists('FW_DB_Cache', FALSE)) - { - require_once(dirname(__DIR__) . DS . 'Database'.DS.'DB_cache.php'); - } - elseif (is_object($this->CACHE)) - { - return TRUE; - } - - $this->CACHE = new FW_DB_Cache($this); // pass db object to support multiple db connections and returned db objects - return TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Close DB Connection - * - * @return void - */ - public function close() - { - if ($this->conn_id) - { - $this->_close(); - $this->conn_id = FALSE; - } - } - - // -------------------------------------------------------------------- - - /** - * Close DB Connection - * - * This method would be overridden by most of the drivers. - * - * @return void - */ - protected function _close() - { - $this->conn_id = FALSE; - } - - // -------------------------------------------------------------------- - - /** - * Display an error message - * - * @param string the error message - * @param string any "swap" values - * @param bool whether to localize the message - * @return string sends the application/layout/errors/error_db.php template - */ - public function display_error($error = '', $swap = '', $native = FALSE) - { - // First load the language - Language::get('db'); - - $heading = Language::line('db_error_heading'); - - if ($native === TRUE) - { - $message = (array) $error; - } - else - { - $message = is_array($error) ? $error : array(str_replace('%s', $swap, Language::line($error))); - } - - // Find the most likely culprit of the error by going through - // the backtrace until the source file is no longer in the - // database folder. - $trace = debug_backtrace(); - $file = ''; - $line = ''; - foreach ($trace as $call) - { - if (isset($call['file'], $call['class'])) - { - // We'll need this on Windows, as APPPATH and BASEPATH will always use forward slashes - if (DIRECTORY_SEPARATOR !== '/') - { - $call['file'] = str_replace('\\', '/', $call['file']); - } - - if (strpos($call['file'], dirname(__DIR__) . DS . 'Database') === FALSE && strpos($call['class'], 'Loader') === FALSE) - { - // Found it - use a relative path for safety - $file = str_replace(array('Application', 'Core'), '', $call['file']); - $line = $call['line']; - break; - } - } - } - - Logger::logError($heading . " | " . implode(' | ', $message), null, $file, $line); - throw new DatabaseException($heading . ": " . implode(' ', $this->error()), 1); - - } - - // -------------------------------------------------------------------- - - /** - * Protect Identifiers - * - * This function is used extensively by the Query Builder class, and by - * a couple functions in this class. - * It takes a column or table name (optionally with an alias) and inserts - * the table prefix onto it. Some logic is necessary in order to deal with - * column names that include the path. Consider a query like this: - * - * SELECT hostname.database.table.column AS c FROM hostname.database.table - * - * Or a query with aliasing: - * - * SELECT m.member_id, m.member_name FROM members AS m - * - * Since the column name can include up to four segments (host, DB, table, column) - * or also have an alias prefix, we need to do a bit of work to figure this out and - * insert the table prefix (if it exists) in the proper position, and escape only - * the correct identifiers. - * - * @param string - * @param bool - * @param mixed - * @param bool - * @return string - */ - public function protect_identifiers($item, $prefix_single = FALSE, $protect_identifiers = NULL, $field_exists = TRUE) - { - if ( ! is_bool($protect_identifiers)) - { - $protect_identifiers = $this->_protect_identifiers; - } - - if (is_array($item)) - { - $escaped_array = array(); - foreach ($item as $k => $v) - { - $escaped_array[$this->protect_identifiers($k)] = $this->protect_identifiers($v, $prefix_single, $protect_identifiers, $field_exists); - } - - return $escaped_array; - } - - // This is basically a bug fix for queries that use MAX, MIN, etc. - // If a parenthesis is found we know that we do not need to - // escape the data or add a prefix. There's probably a more graceful - // way to deal with this, but I'm not thinking of it -- Rick - // - // Added exception for single quotes as well, we don't want to alter - // literal strings. -- Narf - if (strcspn($item, "()'") !== strlen($item)) - { - return $item; - } - - // Convert tabs or multiple spaces into single spaces - $item = preg_replace('/\s+/', ' ', trim($item)); - - // If the item has an alias declaration we remove it and set it aside. - // Note: strripos() is used in order to support spaces in table names - if ($offset = strripos($item, ' AS ')) - { - $alias = ($protect_identifiers) - ? substr($item, $offset, 4).$this->escape_identifiers(substr($item, $offset + 4)) - : substr($item, $offset); - $item = substr($item, 0, $offset); - } - elseif ($offset = strrpos($item, ' ')) - { - $alias = ($protect_identifiers) - ? ' '.$this->escape_identifiers(substr($item, $offset + 1)) - : substr($item, $offset); - $item = substr($item, 0, $offset); - } - else - { - $alias = ''; - } - - // Break the string apart if it contains periods, then insert the table prefix - // in the correct location, assuming the period doesn't indicate that we're dealing - // with an alias. While we're at it, we will escape the components - if (strpos($item, '.') !== FALSE) - { - $parts = explode('.', $item); - - // Does the first segment of the exploded item match - // one of the aliases previously identified? If so, - // we have nothing more to do other than escape the item - // - // NOTE: The ! empty() condition prevents this method - // from breaking when QB isn't enabled. - if ( ! empty($this->qb_aliased_tables) && in_array($parts[0], $this->qb_aliased_tables)) - { - if ($protect_identifiers === TRUE) - { - foreach ($parts as $key => $val) - { - if ( ! in_array($val, $this->_reserved_identifiers)) - { - $parts[$key] = $this->escape_identifiers($val); - } - } - - $item = implode('.', $parts); - } - - return $item.$alias; - } - - // Is there a table prefix defined in the config file? If not, no need to do anything - if ($this->dbprefix !== '') - { - // We now add the table prefix based on some logic. - // Do we have 4 segments (hostname.database.table.column)? - // If so, we add the table prefix to the column name in the 3rd segment. - if (isset($parts[3])) - { - $i = 2; - } - // Do we have 3 segments (database.table.column)? - // If so, we add the table prefix to the column name in 2nd position - elseif (isset($parts[2])) - { - $i = 1; - } - // Do we have 2 segments (table.column)? - // If so, we add the table prefix to the column name in 1st segment - else - { - $i = 0; - } - - // This flag is set when the supplied $item does not contain a field name. - // This can happen when this function is being called from a JOIN. - if ($field_exists === FALSE) - { - $i++; - } - - // Verify table prefix and replace if necessary - if ($this->swap_pre !== '' && strpos($parts[$i], $this->swap_pre) === 0) - { - $parts[$i] = preg_replace('/^'.$this->swap_pre.'(\S+?)/', $this->dbprefix.'\\1', $parts[$i]); - } - // We only add the table prefix if it does not already exist - elseif (strpos($parts[$i], $this->dbprefix) !== 0) - { - $parts[$i] = $this->dbprefix.$parts[$i]; - } - - // Put the parts back together - $item = implode('.', $parts); - } - - if ($protect_identifiers === TRUE) - { - $item = $this->escape_identifiers($item); - } - - return $item.$alias; - } - - // Is there a table prefix? If not, no need to insert it - if ($this->dbprefix !== '') - { - // Verify table prefix and replace if necessary - if ($this->swap_pre !== '' && strpos($item, $this->swap_pre) === 0) - { - $item = preg_replace('/^'.$this->swap_pre.'(\S+?)/', $this->dbprefix.'\\1', $item); - } - // Do we prefix an item with no segments? - elseif ($prefix_single === TRUE && strpos($item, $this->dbprefix) !== 0) - { - $item = $this->dbprefix.$item; - } - } - - if ($protect_identifiers === TRUE && ! in_array($item, $this->_reserved_identifiers)) - { - $item = $this->escape_identifiers($item); - } - - return $item.$alias; - } - - // -------------------------------------------------------------------- - - /** - * Dummy method that allows Query Builder class to be disabled - * and keep count_all() working. - * - * @return void - */ - protected function _reset_select() - { - } - -} diff --git a/src/Database/DB_forge.php b/src/Database/DB_forge.php deleted file mode 100644 index 7ae25ac..0000000 --- a/src/Database/DB_forge.php +++ /dev/null @@ -1,1036 +0,0 @@ -db =& $db; - Logger::log('Database Forge Class Initialized'); - } - - // -------------------------------------------------------------------- - - /** - * Create database - * - * @param string $db_name - * @return bool - */ - public function create_database($db_name) - { - if ($this->_create_database === FALSE) - { - return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE; - } - elseif ( ! $this->db->query(sprintf($this->_create_database, $db_name, $this->db->char_set, $this->db->dbcollat))) - { - return ($this->db->db_debug) ? $this->db->display_error('db_unable_to_drop') : FALSE; - } - - if ( ! empty($this->db->data_cache['db_names'])) - { - $this->db->data_cache['db_names'][] = $db_name; - } - - return TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Drop database - * - * @param string $db_name - * @return bool - */ - public function drop_database($db_name) - { - if ($this->_drop_database === FALSE) - { - return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE; - } - elseif ( ! $this->db->query(sprintf($this->_drop_database, $db_name))) - { - return ($this->db->db_debug) ? $this->db->display_error('db_unable_to_drop') : FALSE; - } - - if ( ! empty($this->db->data_cache['db_names'])) - { - $key = array_search(strtolower($db_name), array_map('strtolower', $this->db->data_cache['db_names']), TRUE); - if ($key !== FALSE) - { - unset($this->db->data_cache['db_names'][$key]); - } - } - - return TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Add Key - * - * @param string $key - * @param bool $primary - * @return FW_DB_forge - */ - public function add_key($key, $primary = FALSE) - { - // DO NOT change this! This condition is only applicable - // for PRIMARY keys because you can only have one such, - // and therefore all fields you add to it will be included - // in the same, composite PRIMARY KEY. - // - // It's not the same for regular indexes. - if ($primary === TRUE && is_array($key)) - { - foreach ($key as $one) - { - $this->add_key($one, $primary); - } - - return $this; - } - - if ($primary === TRUE) - { - $this->primary_keys[] = $key; - } - else - { - $this->keys[] = $key; - } - - return $this; - } - - // -------------------------------------------------------------------- - - /** - * Add Field - * - * @param array $field - * @return FW_DB_forge - */ - public function add_field($field) - { - if (is_string($field)) - { - if ($field === 'id') - { - $this->add_field(array( - 'id' => array( - 'type' => 'INT', - 'constraint' => 9, - 'auto_increment' => TRUE - ) - )); - $this->add_key('id', TRUE); - } - else - { - if (strpos($field, ' ') === FALSE) - { - throw new DatabaseException('Field information is required for that operation.', 1); - } - - $this->fields[] = $field; - } - } - - if (is_array($field)) - { - $this->fields = array_merge($this->fields, $field); - } - - return $this; - } - - // -------------------------------------------------------------------- - - /** - * Create Table - * - * @param string $table Table name - * @param bool $if_not_exists Whether to add IF NOT EXISTS condition - * @param array $attributes Associative array of table attributes - * @return bool - */ - public function create_table($table, $if_not_exists = FALSE, array $attributes = array()) - { - if ($table === '') - { - throw new DatabaseException('A table name is required for that operation.', 1); - } - else - { - $table = $this->db->dbprefix.$table; - } - - if (count($this->fields) === 0) - { - throw new DatabaseException('Field information is required.', 1); - } - - $sql = $this->_create_table($table, $if_not_exists, $attributes); - - if (is_bool($sql)) - { - $this->_reset(); - if ($sql === FALSE) - { - return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE; - } - } - - if (($result = $this->db->query($sql)) !== FALSE) - { - empty($this->db->data_cache['table_names']) OR $this->db->data_cache['table_names'][] = $table; - - // Most databases don't support creating indexes from within the CREATE TABLE statement - if ( ! empty($this->keys)) - { - for ($i = 0, $sqls = $this->_process_indexes($table), $c = count($sqls); $i < $c; $i++) - { - $this->db->query($sqls[$i]); - } - } - } - - $this->_reset(); - return $result; - } - - // -------------------------------------------------------------------- - - /** - * Create Table - * - * @param string $table Table name - * @param bool $if_not_exists Whether to add 'IF NOT EXISTS' condition - * @param array $attributes Associative array of table attributes - * @return mixed - */ - protected function _create_table($table, $if_not_exists, $attributes) - { - if ($if_not_exists === TRUE && $this->_create_table_if === FALSE) - { - if ($this->db->table_exists($table)) - { - return TRUE; - } - else - { - $if_not_exists = FALSE; - } - } - - $sql = ($if_not_exists) - ? sprintf($this->_create_table_if, $this->db->escape_identifiers($table)) - : 'CREATE TABLE'; - - $columns = $this->_process_fields(TRUE); - for ($i = 0, $c = count($columns); $i < $c; $i++) - { - $columns[$i] = ($columns[$i]['_literal'] !== FALSE) - ? "\n\t".$columns[$i]['_literal'] - : "\n\t".$this->_process_column($columns[$i]); - } - - $columns = implode(',', $columns) - .$this->_process_primary_keys($table); - - // Are indexes created from within the CREATE TABLE statement? (e.g. in MySQL) - if ($this->_create_table_keys === TRUE) - { - $columns .= $this->_process_indexes($table); - } - - // _create_table will usually have the following format: "%s %s (%s\n)" - $sql = sprintf($this->_create_table.'%s', - $sql, - $this->db->escape_identifiers($table), - $columns, - $this->_create_table_attr($attributes) - ); - - return $sql; - } - - // -------------------------------------------------------------------- - - /** - * CREATE TABLE attributes - * - * @param array $attributes Associative array of table attributes - * @return string - */ - protected function _create_table_attr($attributes) - { - $sql = ''; - - foreach (array_keys($attributes) as $key) - { - if (is_string($key)) - { - $sql .= ' '.strtoupper($key).' '.$attributes[$key]; - } - } - - return $sql; - } - - // -------------------------------------------------------------------- - - /** - * Drop Table - * - * @param string $table_name Table name - * @param bool $if_exists Whether to add an IF EXISTS condition - * @return bool - */ - public function drop_table($table_name, $if_exists = FALSE) - { - if ($table_name === '') - { - return ($this->db->db_debug) ? $this->db->display_error('db_table_name_required') : FALSE; - } - - if (($query = $this->_drop_table($this->db->dbprefix.$table_name, $if_exists)) === TRUE) - { - return TRUE; - } - - $query = $this->db->query($query); - - // Update table list cache - if ($query && ! empty($this->db->data_cache['table_names'])) - { - $key = array_search(strtolower($this->db->dbprefix.$table_name), array_map('strtolower', $this->db->data_cache['table_names']), TRUE); - if ($key !== FALSE) - { - unset($this->db->data_cache['table_names'][$key]); - } - } - - return $query; - } - - // -------------------------------------------------------------------- - - /** - * Drop Table - * - * Generates a platform-specific DROP TABLE string - * - * @param string $table Table name - * @param bool $if_exists Whether to add an IF EXISTS condition - * @return string - */ - protected function _drop_table($table, $if_exists) - { - $sql = 'DROP TABLE'; - - if ($if_exists) - { - if ($this->_drop_table_if === FALSE) - { - if ( ! $this->db->table_exists($table)) - { - return TRUE; - } - } - else - { - $sql = sprintf($this->_drop_table_if, $this->db->escape_identifiers($table)); - } - } - - return $sql.' '.$this->db->escape_identifiers($table); - } - - // -------------------------------------------------------------------- - - /** - * Rename Table - * - * @param string $table_name Old table name - * @param string $new_table_name New table name - * @return bool - */ - public function rename_table($table_name, $new_table_name) - { - if ($table_name === '' OR $new_table_name === '') - { - throw new DatabaseException('A table name is required for that operation.', 1); - return FALSE; - } - elseif ($this->_rename_table === FALSE) - { - return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE; - } - - $result = $this->db->query(sprintf($this->_rename_table, - $this->db->escape_identifiers($this->db->dbprefix.$table_name), - $this->db->escape_identifiers($this->db->dbprefix.$new_table_name)) - ); - - if ($result && ! empty($this->db->data_cache['table_names'])) - { - $key = array_search(strtolower($this->db->dbprefix.$table_name), array_map('strtolower', $this->db->data_cache['table_names']), TRUE); - if ($key !== FALSE) - { - $this->db->data_cache['table_names'][$key] = $this->db->dbprefix.$new_table_name; - } - } - - return $result; - } - - // -------------------------------------------------------------------- - - /** - * Column Add - * - * @todo Remove deprecated $_after option in 3.1+ - * @param string $table Table name - * @param array $field Column definition - * @param string $_after Column for AFTER clause (deprecated) - * @return bool - */ - public function add_column($table, $field, $_after = NULL) - { - // Work-around for literal column definitions - is_array($field) OR $field = array($field); - - foreach (array_keys($field) as $k) - { - // Backwards-compatibility work-around for MySQL/CUBRID AFTER clause (remove in 3.1+) - if ($_after !== NULL && is_array($field[$k]) && ! isset($field[$k]['after'])) - { - $field[$k]['after'] = $_after; - } - - $this->add_field(array($k => $field[$k])); - } - - $sqls = $this->_alter_table('ADD', $this->db->dbprefix.$table, $this->_process_fields()); - $this->_reset(); - if ($sqls === FALSE) - { - return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE; - } - - for ($i = 0, $c = count($sqls); $i < $c; $i++) - { - if ($this->db->query($sqls[$i]) === FALSE) - { - return FALSE; - } - } - - return TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Column Drop - * - * @param string $table Table name - * @param string $column_name Column name - * @return bool - */ - public function drop_column($table, $column_name) - { - $sql = $this->_alter_table('DROP', $this->db->dbprefix.$table, $column_name); - if ($sql === FALSE) - { - return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE; - } - - return $this->db->query($sql); - } - - // -------------------------------------------------------------------- - - /** - * Column Modify - * - * @param string $table Table name - * @param string $field Column definition - * @return bool - */ - public function modify_column($table, $field) - { - // Work-around for literal column definitions - is_array($field) OR $field = array($field); - - foreach (array_keys($field) as $k) - { - $this->add_field(array($k => $field[$k])); - } - - if (count($this->fields) === 0) - { - throw new DatabaseException('Field information is required.', 1); - } - - $sqls = $this->_alter_table('CHANGE', $this->db->dbprefix.$table, $this->_process_fields()); - $this->_reset(); - if ($sqls === FALSE) - { - return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE; - } - - for ($i = 0, $c = count($sqls); $i < $c; $i++) - { - if ($this->db->query($sqls[$i]) === FALSE) - { - return FALSE; - } - } - - return TRUE; - } - - // -------------------------------------------------------------------- - - /** - * ALTER TABLE - * - * @param string $alter_type ALTER type - * @param string $table Table name - * @param mixed $field Column definition - * @return string|string[] - */ - protected function _alter_table($alter_type, $table, $field) - { - $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table).' '; - - // DROP has everything it needs now. - if ($alter_type === 'DROP') - { - return $sql.'DROP COLUMN '.$this->db->escape_identifiers($field); - } - - $sql .= ($alter_type === 'ADD') - ? 'ADD ' - : $alter_type.' COLUMN '; - - $sqls = array(); - for ($i = 0, $c = count($field); $i < $c; $i++) - { - $sqls[] = $sql - .($field[$i]['_literal'] !== FALSE ? $field[$i]['_literal'] : $this->_process_column($field[$i])); - } - - return $sqls; - } - - // -------------------------------------------------------------------- - - /** - * Process fields - * - * @param bool $create_table - * @return array - */ - protected function _process_fields($create_table = FALSE) - { - $fields = array(); - - foreach ($this->fields as $key => $attributes) - { - if (is_int($key) && ! is_array($attributes)) - { - $fields[] = array('_literal' => $attributes); - continue; - } - - $attributes = array_change_key_case($attributes, CASE_UPPER); - - if ($create_table === TRUE && empty($attributes['TYPE'])) - { - continue; - } - - isset($attributes['TYPE']) && $this->_attr_type($attributes); - - $field = array( - 'name' => $key, - 'new_name' => isset($attributes['NAME']) ? $attributes['NAME'] : NULL, - 'type' => isset($attributes['TYPE']) ? $attributes['TYPE'] : NULL, - 'length' => '', - 'unsigned' => '', - 'null' => '', - 'unique' => '', - 'default' => '', - 'auto_increment' => '', - '_literal' => FALSE - ); - - isset($attributes['TYPE']) && $this->_attr_unsigned($attributes, $field); - - if ($create_table === FALSE) - { - if (isset($attributes['AFTER'])) - { - $field['after'] = $attributes['AFTER']; - } - elseif (isset($attributes['FIRST'])) - { - $field['first'] = (bool) $attributes['FIRST']; - } - } - - $this->_attr_default($attributes, $field); - - if (isset($attributes['NULL'])) - { - if ($attributes['NULL'] === TRUE) - { - $field['null'] = empty($this->_null) ? '' : ' '.$this->_null; - } - else - { - $field['null'] = ' NOT NULL'; - } - } - elseif ($create_table === TRUE) - { - $field['null'] = ' NOT NULL'; - } - - $this->_attr_auto_increment($attributes, $field); - $this->_attr_unique($attributes, $field); - - if (isset($attributes['COMMENT'])) - { - $field['comment'] = $this->db->escape($attributes['COMMENT']); - } - - if (isset($attributes['TYPE']) && ! empty($attributes['CONSTRAINT'])) - { - switch (strtoupper($attributes['TYPE'])) - { - case 'ENUM': - case 'SET': - $attributes['CONSTRAINT'] = $this->db->escape($attributes['CONSTRAINT']); - default: - $field['length'] = is_array($attributes['CONSTRAINT']) - ? '('.implode(',', $attributes['CONSTRAINT']).')' - : '('.$attributes['CONSTRAINT'].')'; - break; - } - } - - $fields[] = $field; - } - - return $fields; - } - - // -------------------------------------------------------------------- - - /** - * Process column - * - * @param array $field - * @return string - */ - protected function _process_column($field) - { - return $this->db->escape_identifiers($field['name']) - .' '.$field['type'].$field['length'] - .$field['unsigned'] - .$field['default'] - .$field['null'] - .$field['auto_increment'] - .$field['unique']; - } - - // -------------------------------------------------------------------- - - /** - * Field attribute TYPE - * - * Performs a data type mapping between different databases. - * - * @param array &$attributes - * @return void - */ - protected function _attr_type(&$attributes) - { - // Usually overridden by drivers - } - - // -------------------------------------------------------------------- - - /** - * Field attribute UNSIGNED - * - * Depending on the _unsigned property value: - * - * - TRUE will always set $field['unsigned'] to 'UNSIGNED' - * - FALSE will always set $field['unsigned'] to '' - * - array(TYPE) will set $field['unsigned'] to 'UNSIGNED', - * if $attributes['TYPE'] is found in the array - * - array(TYPE => UTYPE) will change $field['type'], - * from TYPE to UTYPE in case of a match - * - * @param array &$attributes - * @param array &$field - * @return void - */ - protected function _attr_unsigned(&$attributes, &$field) - { - if (empty($attributes['UNSIGNED']) OR $attributes['UNSIGNED'] !== TRUE) - { - return; - } - - // Reset the attribute in order to avoid issues if we do type conversion - $attributes['UNSIGNED'] = FALSE; - - if (is_array($this->_unsigned)) - { - foreach (array_keys($this->_unsigned) as $key) - { - if (is_int($key) && strcasecmp($attributes['TYPE'], $this->_unsigned[$key]) === 0) - { - $field['unsigned'] = ' UNSIGNED'; - return; - } - elseif (is_string($key) && strcasecmp($attributes['TYPE'], $key) === 0) - { - $field['type'] = $key; - return; - } - } - - return; - } - - $field['unsigned'] = ($this->_unsigned === TRUE) ? ' UNSIGNED' : ''; - } - - // -------------------------------------------------------------------- - - /** - * Field attribute DEFAULT - * - * @param array &$attributes - * @param array &$field - * @return void - */ - protected function _attr_default(&$attributes, &$field) - { - if ($this->_default === FALSE) - { - return; - } - - if (array_key_exists('DEFAULT', $attributes)) - { - if ($attributes['DEFAULT'] === NULL) - { - $field['default'] = empty($this->_null) ? '' : $this->_default.$this->_null; - - // Override the NULL attribute if that's our default - $attributes['NULL'] = TRUE; - $field['null'] = empty($this->_null) ? '' : ' '.$this->_null; - } - else - { - $field['default'] = $this->_default.$this->db->escape($attributes['DEFAULT']); - } - } - } - - // -------------------------------------------------------------------- - - /** - * Field attribute UNIQUE - * - * @param array &$attributes - * @param array &$field - * @return void - */ - protected function _attr_unique(&$attributes, &$field) - { - if ( ! empty($attributes['UNIQUE']) && $attributes['UNIQUE'] === TRUE) - { - $field['unique'] = ' UNIQUE'; - } - } - - // -------------------------------------------------------------------- - - /** - * Field attribute AUTO_INCREMENT - * - * @param array &$attributes - * @param array &$field - * @return void - */ - protected function _attr_auto_increment(&$attributes, &$field) - { - if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE && stripos($field['type'], 'int') !== FALSE) - { - $field['auto_increment'] = ' AUTO_INCREMENT'; - } - } - - // -------------------------------------------------------------------- - - /** - * Process primary keys - * - * @param string $table Table name - * @return string - */ - protected function _process_primary_keys($table) - { - $sql = ''; - - for ($i = 0, $c = count($this->primary_keys); $i < $c; $i++) - { - if ( ! isset($this->fields[$this->primary_keys[$i]])) - { - unset($this->primary_keys[$i]); - } - } - - if (count($this->primary_keys) > 0) - { - $sql .= ",\n\tCONSTRAINT ".$this->db->escape_identifiers('pk_'.$table) - .' PRIMARY KEY('.implode(', ', $this->db->escape_identifiers($this->primary_keys)).')'; - } - - return $sql; - } - - // -------------------------------------------------------------------- - - /** - * Process indexes - * - * @param string $table - * @return string - */ - protected function _process_indexes($table) - { - $sqls = array(); - - for ($i = 0, $c = count($this->keys); $i < $c; $i++) - { - if (is_array($this->keys[$i])) - { - for ($i2 = 0, $c2 = count($this->keys[$i]); $i2 < $c2; $i2++) - { - if ( ! isset($this->fields[$this->keys[$i][$i2]])) - { - unset($this->keys[$i][$i2]); - continue; - } - } - } - elseif ( ! isset($this->fields[$this->keys[$i]])) - { - unset($this->keys[$i]); - continue; - } - - is_array($this->keys[$i]) OR $this->keys[$i] = array($this->keys[$i]); - - $sqls[] = 'CREATE INDEX '.$this->db->escape_identifiers($table.'_'.implode('_', $this->keys[$i])) - .' ON '.$this->db->escape_identifiers($table) - .' ('.implode(', ', $this->db->escape_identifiers($this->keys[$i])).');'; - } - - return $sqls; - } - - // -------------------------------------------------------------------- - - /** - * Reset - * - * Resets table creation vars - * - * @return void - */ - protected function _reset() - { - $this->fields = $this->keys = $this->primary_keys = array(); - } - -} diff --git a/src/Database/DB_query_builder.php b/src/Database/DB_query_builder.php deleted file mode 100644 index 4675112..0000000 --- a/src/Database/DB_query_builder.php +++ /dev/null @@ -1,2785 +0,0 @@ -_protect_identifiers; - - foreach ($select as $val) - { - $val = trim($val); - - if ($val !== '') - { - $this->qb_select[] = $val; - $this->qb_no_escape[] = $escape; - - if ($this->qb_caching === TRUE) - { - $this->qb_cache_select[] = $val; - $this->qb_cache_exists[] = 'select'; - $this->qb_cache_no_escape[] = $escape; - } - } - } - - return $this; - } - - // -------------------------------------------------------------------- - - /** - * Select Max - * - * Generates a SELECT MAX(field) portion of a query - * - * @param string the field - * @param string an alias - * @return FW_DB_query_builder - */ - public function select_max($select = '', $alias = '') - { - return $this->_max_min_avg_sum($select, $alias, 'MAX'); - } - - // -------------------------------------------------------------------- - - /** - * Select Min - * - * Generates a SELECT MIN(field) portion of a query - * - * @param string the field - * @param string an alias - * @return FW_DB_query_builder - */ - public function select_min($select = '', $alias = '') - { - return $this->_max_min_avg_sum($select, $alias, 'MIN'); - } - - // -------------------------------------------------------------------- - - /** - * Select Average - * - * Generates a SELECT AVG(field) portion of a query - * - * @param string the field - * @param string an alias - * @return FW_DB_query_builder - */ - public function select_avg($select = '', $alias = '') - { - return $this->_max_min_avg_sum($select, $alias, 'AVG'); - } - - // -------------------------------------------------------------------- - - /** - * Select Sum - * - * Generates a SELECT SUM(field) portion of a query - * - * @param string the field - * @param string an alias - * @return FW_DB_query_builder - */ - public function select_sum($select = '', $alias = '') - { - return $this->_max_min_avg_sum($select, $alias, 'SUM'); - } - - // -------------------------------------------------------------------- - - /** - * SELECT [MAX|MIN|AVG|SUM]() - * - * @used-by select_max() - * @used-by select_min() - * @used-by select_avg() - * @used-by select_sum() - * - * @param string $select Field name - * @param string $alias - * @param string $type - * @return FW_DB_query_builder - */ - protected function _max_min_avg_sum($select = '', $alias = '', $type = 'MAX') - { - if ( ! is_string($select) OR $select === '') - { - $this->display_error('db_invalid_query'); - } - - $type = strtoupper($type); - - if ( ! in_array($type, array('MAX', 'MIN', 'AVG', 'SUM'))) - { - throw new DatabaseException('Invalid function type: '.$type, 1); - } - - if ($alias === '') - { - $alias = $this->_create_alias_from_table(trim($select)); - } - - $sql = $type.'('.$this->protect_identifiers(trim($select)).') AS '.$this->escape_identifiers(trim($alias)); - - $this->qb_select[] = $sql; - $this->qb_no_escape[] = NULL; - - if ($this->qb_caching === TRUE) - { - $this->qb_cache_select[] = $sql; - $this->qb_cache_exists[] = 'select'; - } - - return $this; - } - - // -------------------------------------------------------------------- - - /** - * Determines the alias name based on the table - * - * @param string $item - * @return string - */ - protected function _create_alias_from_table($item) - { - if (strpos($item, '.') !== FALSE) - { - $item = explode('.', $item); - return end($item); - } - - return $item; - } - - // -------------------------------------------------------------------- - - /** - * DISTINCT - * - * Sets a flag which tells the query string compiler to add DISTINCT - * - * @param bool $val - * @return FW_DB_query_builder - */ - public function distinct($val = TRUE) - { - $this->qb_distinct = is_bool($val) ? $val : TRUE; - return $this; - } - - // -------------------------------------------------------------------- - - /** - * From - * - * Generates the FROM portion of the query - * - * @param mixed $from can be a string or array - * @return FW_DB_query_builder - */ - public function from($from) - { - foreach ((array) $from as $val) - { - if (strpos($val, ',') !== FALSE) - { - foreach (explode(',', $val) as $v) - { - $v = trim($v); - $this->_track_aliases($v); - - $this->qb_from[] = $v = $this->protect_identifiers($v, TRUE, NULL, FALSE); - - if ($this->qb_caching === TRUE) - { - $this->qb_cache_from[] = $v; - $this->qb_cache_exists[] = 'from'; - } - } - } - else - { - $val = trim($val); - - // Extract any aliases that might exist. We use this information - // in the protect_identifiers to know whether to add a table prefix - $this->_track_aliases($val); - - $this->qb_from[] = $val = $this->protect_identifiers($val, TRUE, NULL, FALSE); - - if ($this->qb_caching === TRUE) - { - $this->qb_cache_from[] = $val; - $this->qb_cache_exists[] = 'from'; - } - } - } - - return $this; - } - - // -------------------------------------------------------------------- - - /** - * JOIN - * - * Generates the JOIN portion of the query - * - * @param string - * @param string the join condition - * @param string the type of join - * @param string whether not to try to escape identifiers - * @return FW_DB_query_builder - */ - public function join($table, $cond, $type = '', $escape = NULL) - { - if ($type !== '') - { - $type = strtoupper(trim($type)); - - if ( ! in_array($type, array('LEFT', 'RIGHT', 'OUTER', 'INNER', 'LEFT OUTER', 'RIGHT OUTER'), TRUE)) - { - $type = ''; - } - else - { - $type .= ' '; - } - } - - // Extract any aliases that might exist. We use this information - // in the protect_identifiers to know whether to add a table prefix - $this->_track_aliases($table); - - is_bool($escape) OR $escape = $this->_protect_identifiers; - - if ( ! $this->_has_operator($cond)) - { - $cond = ' USING ('.($escape ? $this->escape_identifiers($cond) : $cond).')'; - } - elseif ($escape === FALSE) - { - $cond = ' ON '.$cond; - } - else - { - // Split multiple conditions - if (preg_match_all('/\sAND\s|\sOR\s/i', $cond, $joints, PREG_OFFSET_CAPTURE)) - { - $conditions = array(); - $joints = $joints[0]; - array_unshift($joints, array('', 0)); - - for ($i = count($joints) - 1, $pos = strlen($cond); $i >= 0; $i--) - { - $joints[$i][1] += strlen($joints[$i][0]); // offset - $conditions[$i] = substr($cond, $joints[$i][1], $pos - $joints[$i][1]); - $pos = $joints[$i][1] - strlen($joints[$i][0]); - $joints[$i] = $joints[$i][0]; - } - } - else - { - $conditions = array($cond); - $joints = array(''); - } - - $cond = ' ON '; - for ($i = 0, $c = count($conditions); $i < $c; $i++) - { - $operator = $this->_get_operator($conditions[$i]); - $cond .= $joints[$i]; - $cond .= preg_match("/(\(*)?([\[\]\w\.'-]+)".preg_quote($operator)."(.*)/i", $conditions[$i], $match) - ? $match[1].$this->protect_identifiers($match[2]).$operator.$this->protect_identifiers($match[3]) - : $conditions[$i]; - } - } - - // Do we want to escape the table name? - if ($escape === TRUE) - { - $table = $this->protect_identifiers($table, TRUE, NULL, FALSE); - } - - // Assemble the JOIN statement - $this->qb_join[] = $join = $type.'JOIN '.$table.$cond; - - if ($this->qb_caching === TRUE) - { - $this->qb_cache_join[] = $join; - $this->qb_cache_exists[] = 'join'; - } - - return $this; - } - - // -------------------------------------------------------------------- - - /** - * WHERE - * - * Generates the WHERE portion of the query. - * Separates multiple calls with 'AND'. - * - * @param mixed - * @param mixed - * @param bool - * @return FW_DB_query_builder - */ - public function where($key, $value = NULL, $escape = NULL) - { - return $this->_wh('qb_where', $key, $value, 'AND ', $escape); - } - - // -------------------------------------------------------------------- - - /** - * OR WHERE - * - * Generates the WHERE portion of the query. - * Separates multiple calls with 'OR'. - * - * @param mixed - * @param mixed - * @param bool - * @return FW_DB_query_builder - */ - public function or_where($key, $value = NULL, $escape = NULL) - { - return $this->_wh('qb_where', $key, $value, 'OR ', $escape); - } - - // -------------------------------------------------------------------- - - /** - * WHERE, HAVING - * - * @used-by where() - * @used-by or_where() - * @used-by having() - * @used-by or_having() - * - * @param string $qb_key 'qb_where' or 'qb_having' - * @param mixed $key - * @param mixed $value - * @param string $type - * @param bool $escape - * @return FW_DB_query_builder - */ - protected function _wh($qb_key, $key, $value = NULL, $type = 'AND ', $escape = NULL) - { - $qb_cache_key = ($qb_key === 'qb_having') ? 'qb_cache_having' : 'qb_cache_where'; - - if ( ! is_array($key)) - { - $key = array($key => $value); - } - - // If the escape value was not set will base it on the global setting - is_bool($escape) OR $escape = $this->_protect_identifiers; - - foreach ($key as $k => $v) - { - $prefix = (count($this->$qb_key) === 0 && count($this->$qb_cache_key) === 0) - ? $this->_group_get_type('') - : $this->_group_get_type($type); - - if ($v !== NULL) - { - if ($escape === TRUE) - { - $v = ' '.$this->escape($v); - } - - if ( ! $this->_has_operator($k)) - { - $k .= ' = '; - } - } - elseif ( ! $this->_has_operator($k)) - { - // value appears not to have been set, assign the test to IS NULL - $k .= ' IS NULL'; - } - elseif (preg_match('/\s*(!?=|<>|IS(?:\s+NOT)?)\s*$/i', $k, $match, PREG_OFFSET_CAPTURE)) - { - $k = substr($k, 0, $match[0][1]).($match[1][0] === '=' ? ' IS NULL' : ' IS NOT NULL'); - } - - $this->{$qb_key}[] = array('condition' => $prefix.$k.$v, 'escape' => $escape); - if ($this->qb_caching === TRUE) - { - $this->{$qb_cache_key}[] = array('condition' => $prefix.$k.$v, 'escape' => $escape); - $this->qb_cache_exists[] = substr($qb_key, 3); - } - - } - - return $this; - } - - // -------------------------------------------------------------------- - - /** - * WHERE IN - * - * Generates a WHERE field IN('item', 'item') SQL query, - * joined with 'AND' if appropriate. - * - * @param string $key The field to search - * @param array $values The values searched on - * @param bool $escape - * @return FW_DB_query_builder - */ - public function where_in($key = NULL, $values = NULL, $escape = NULL) - { - return $this->_where_in($key, $values, FALSE, 'AND ', $escape); - } - - // -------------------------------------------------------------------- - - /** - * OR WHERE IN - * - * Generates a WHERE field IN('item', 'item') SQL query, - * joined with 'OR' if appropriate. - * - * @param string $key The field to search - * @param array $values The values searched on - * @param bool $escape - * @return FW_DB_query_builder - */ - public function or_where_in($key = NULL, $values = NULL, $escape = NULL) - { - return $this->_where_in($key, $values, FALSE, 'OR ', $escape); - } - - // -------------------------------------------------------------------- - - /** - * WHERE NOT IN - * - * Generates a WHERE field NOT IN('item', 'item') SQL query, - * joined with 'AND' if appropriate. - * - * @param string $key The field to search - * @param array $values The values searched on - * @param bool $escape - * @return FW_DB_query_builder - */ - public function where_not_in($key = NULL, $values = NULL, $escape = NULL) - { - return $this->_where_in($key, $values, TRUE, 'AND ', $escape); - } - - // -------------------------------------------------------------------- - - /** - * OR WHERE NOT IN - * - * Generates a WHERE field NOT IN('item', 'item') SQL query, - * joined with 'OR' if appropriate. - * - * @param string $key The field to search - * @param array $values The values searched on - * @param bool $escape - * @return FW_DB_query_builder - */ - public function or_where_not_in($key = NULL, $values = NULL, $escape = NULL) - { - return $this->_where_in($key, $values, TRUE, 'OR ', $escape); - } - - // -------------------------------------------------------------------- - - /** - * Internal WHERE IN - * - * @used-by where_in() - * @used-by or_where_in() - * @used-by where_not_in() - * @used-by or_where_not_in() - * - * @param string $key The field to search - * @param array $values The values searched on - * @param bool $not If the statement would be IN or NOT IN - * @param string $type - * @param bool $escape - * @return FW_DB_query_builder - */ - protected function _where_in($key = NULL, $values = NULL, $not = FALSE, $type = 'AND ', $escape = NULL) - { - if ($key === NULL OR $values === NULL) - { - return $this; - } - - if ( ! is_array($values)) - { - $values = array($values); - } - - is_bool($escape) OR $escape = $this->_protect_identifiers; - - $not = ($not) ? ' NOT' : ''; - - if ($escape === TRUE) - { - $where_in = array(); - foreach ($values as $value) - { - $where_in[] = $this->escape($value); - } - } - else - { - $where_in = array_values($values); - } - - $prefix = (count($this->qb_where) === 0 && count($this->qb_cache_where) === 0) - ? $this->_group_get_type('') - : $this->_group_get_type($type); - - $where_in = array( - 'condition' => $prefix.$key.$not.' IN('.implode(', ', $where_in).')', - 'escape' => $escape - ); - - $this->qb_where[] = $where_in; - if ($this->qb_caching === TRUE) - { - $this->qb_cache_where[] = $where_in; - $this->qb_cache_exists[] = 'where'; - } - - return $this; - } - - // -------------------------------------------------------------------- - - /** - * LIKE - * - * Generates a %LIKE% portion of the query. - * Separates multiple calls with 'AND'. - * - * @param mixed $field - * @param string $match - * @param string $side - * @param bool $escape - * @return FW_DB_query_builder - */ - public function like($field, $match = '', $side = 'both', $escape = NULL) - { - return $this->_like($field, $match, 'AND ', $side, '', $escape); - } - - // -------------------------------------------------------------------- - - /** - * NOT LIKE - * - * Generates a NOT LIKE portion of the query. - * Separates multiple calls with 'AND'. - * - * @param mixed $field - * @param string $match - * @param string $side - * @param bool $escape - * @return FW_DB_query_builder - */ - public function not_like($field, $match = '', $side = 'both', $escape = NULL) - { - return $this->_like($field, $match, 'AND ', $side, 'NOT', $escape); - } - - // -------------------------------------------------------------------- - - /** - * OR LIKE - * - * Generates a %LIKE% portion of the query. - * Separates multiple calls with 'OR'. - * - * @param mixed $field - * @param string $match - * @param string $side - * @param bool $escape - * @return FW_DB_query_builder - */ - public function or_like($field, $match = '', $side = 'both', $escape = NULL) - { - return $this->_like($field, $match, 'OR ', $side, '', $escape); - } - - // -------------------------------------------------------------------- - - /** - * OR NOT LIKE - * - * Generates a NOT LIKE portion of the query. - * Separates multiple calls with 'OR'. - * - * @param mixed $field - * @param string $match - * @param string $side - * @param bool $escape - * @return FW_DB_query_builder - */ - public function or_not_like($field, $match = '', $side = 'both', $escape = NULL) - { - return $this->_like($field, $match, 'OR ', $side, 'NOT', $escape); - } - - // -------------------------------------------------------------------- - - /** - * Internal LIKE - * - * @used-by like() - * @used-by or_like() - * @used-by not_like() - * @used-by or_not_like() - * - * @param mixed $field - * @param string $match - * @param string $type - * @param string $side - * @param string $not - * @param bool $escape - * @return FW_DB_query_builder - */ - protected function _like($field, $match = '', $type = 'AND ', $side = 'both', $not = '', $escape = NULL) - { - if ( ! is_array($field)) - { - $field = array($field => $match); - } - - is_bool($escape) OR $escape = $this->_protect_identifiers; - // lowercase $side in case somebody writes e.g. 'BEFORE' instead of 'before' (doh) - $side = strtolower($side); - - foreach ($field as $k => $v) - { - $prefix = (count($this->qb_where) === 0 && count($this->qb_cache_where) === 0) - ? $this->_group_get_type('') : $this->_group_get_type($type); - - if ($escape === TRUE) - { - $v = $this->escape_like_str($v); - } - - if ($side === 'none') - { - $like_statement = "{$prefix} {$k} {$not} LIKE '{$v}'"; - } - elseif ($side === 'before') - { - $like_statement = "{$prefix} {$k} {$not} LIKE '%{$v}'"; - } - elseif ($side === 'after') - { - $like_statement = "{$prefix} {$k} {$not} LIKE '{$v}%'"; - } - else - { - $like_statement = "{$prefix} {$k} {$not} LIKE '%{$v}%'"; - } - - // some platforms require an escape sequence definition for LIKE wildcards - if ($escape === TRUE && $this->_like_escape_str !== '') - { - $like_statement .= sprintf($this->_like_escape_str, $this->_like_escape_chr); - } - - $this->qb_where[] = array('condition' => $like_statement, 'escape' => $escape); - if ($this->qb_caching === TRUE) - { - $this->qb_cache_where[] = array('condition' => $like_statement, 'escape' => $escape); - $this->qb_cache_exists[] = 'where'; - } - } - - return $this; - } - - // -------------------------------------------------------------------- - - /** - * Starts a query group. - * - * @param string $not (Internal use only) - * @param string $type (Internal use only) - * @return FW_DB_query_builder - */ - public function group_start($not = '', $type = 'AND ') - { - $type = $this->_group_get_type($type); - - $this->qb_where_group_started = TRUE; - $prefix = (count($this->qb_where) === 0 && count($this->qb_cache_where) === 0) ? '' : $type; - $where = array( - 'condition' => $prefix.$not.str_repeat(' ', ++$this->qb_where_group_count).' (', - 'escape' => FALSE - ); - - $this->qb_where[] = $where; - if ($this->qb_caching) - { - $this->qb_cache_where[] = $where; - } - - return $this; - } - - // -------------------------------------------------------------------- - - /** - * Starts a query group, but ORs the group - * - * @return FW_DB_query_builder - */ - public function or_group_start() - { - return $this->group_start('', 'OR '); - } - - // -------------------------------------------------------------------- - - /** - * Starts a query group, but NOTs the group - * - * @return FW_DB_query_builder - */ - public function not_group_start() - { - return $this->group_start('NOT ', 'AND '); - } - - // -------------------------------------------------------------------- - - /** - * Starts a query group, but OR NOTs the group - * - * @return FW_DB_query_builder - */ - public function or_not_group_start() - { - return $this->group_start('NOT ', 'OR '); - } - - // -------------------------------------------------------------------- - - /** - * Ends a query group - * - * @return FW_DB_query_builder - */ - public function group_end() - { - $this->qb_where_group_started = FALSE; - $where = array( - 'condition' => str_repeat(' ', $this->qb_where_group_count--).')', - 'escape' => FALSE - ); - - $this->qb_where[] = $where; - if ($this->qb_caching) - { - $this->qb_cache_where[] = $where; - } - - return $this; - } - - // -------------------------------------------------------------------- - - /** - * Group_get_type - * - * @used-by group_start() - * @used-by _like() - * @used-by _wh() - * @used-by _where_in() - * - * @param string $type - * @return string - */ - protected function _group_get_type($type) - { - if ($this->qb_where_group_started) - { - $type = ''; - $this->qb_where_group_started = FALSE; - } - - return $type; - } - - // -------------------------------------------------------------------- - - /** - * GROUP BY - * - * @param string $by - * @param bool $escape - * @return FW_DB_query_builder - */ - public function group_by($by, $escape = NULL) - { - is_bool($escape) OR $escape = $this->_protect_identifiers; - - if (is_string($by)) - { - $by = ($escape === TRUE) - ? explode(',', $by) - : array($by); - } - - foreach ($by as $val) - { - $val = trim($val); - - if ($val !== '') - { - $val = array('field' => $val, 'escape' => $escape); - - $this->qb_groupby[] = $val; - if ($this->qb_caching === TRUE) - { - $this->qb_cache_groupby[] = $val; - $this->qb_cache_exists[] = 'groupby'; - } - } - } - - return $this; - } - - // -------------------------------------------------------------------- - - /** - * HAVING - * - * Separates multiple calls with 'AND'. - * - * @param string $key - * @param string $value - * @param bool $escape - * @return FW_DB_query_builder - */ - public function having($key, $value = NULL, $escape = NULL) - { - return $this->_wh('qb_having', $key, $value, 'AND ', $escape); - } - - // -------------------------------------------------------------------- - - /** - * OR HAVING - * - * Separates multiple calls with 'OR'. - * - * @param string $key - * @param string $value - * @param bool $escape - * @return FW_DB_query_builder - */ - public function or_having($key, $value = NULL, $escape = NULL) - { - return $this->_wh('qb_having', $key, $value, 'OR ', $escape); - } - - // -------------------------------------------------------------------- - - /** - * ORDER BY - * - * @param string $orderby - * @param string $direction ASC, DESC or RANDOM - * @param bool $escape - * @return FW_DB_query_builder - */ - public function order_by($orderby, $direction = '', $escape = NULL) - { - $direction = strtoupper(trim($direction)); - - if ($direction === 'RANDOM') - { - $direction = ''; - - // Do we have a seed value? - $orderby = ctype_digit((string) $orderby) - ? sprintf($this->_random_keyword[1], $orderby) - : $this->_random_keyword[0]; - } - elseif (empty($orderby)) - { - return $this; - } - elseif ($direction !== '') - { - $direction = in_array($direction, array('ASC', 'DESC'), TRUE) ? ' '.$direction : ''; - } - - is_bool($escape) OR $escape = $this->_protect_identifiers; - - if ($escape === FALSE) - { - $qb_orderby[] = array('field' => $orderby, 'direction' => $direction, 'escape' => FALSE); - } - else - { - $qb_orderby = array(); - foreach (explode(',', $orderby) as $field) - { - $qb_orderby[] = ($direction === '' && preg_match('/\s+(ASC|DESC)$/i', rtrim($field), $match, PREG_OFFSET_CAPTURE)) - ? array('field' => ltrim(substr($field, 0, $match[0][1])), 'direction' => ' '.$match[1][0], 'escape' => TRUE) - : array('field' => trim($field), 'direction' => $direction, 'escape' => TRUE); - } - } - - $this->qb_orderby = array_merge($this->qb_orderby, $qb_orderby); - if ($this->qb_caching === TRUE) - { - $this->qb_cache_orderby = array_merge($this->qb_cache_orderby, $qb_orderby); - $this->qb_cache_exists[] = 'orderby'; - } - - return $this; - } - - // -------------------------------------------------------------------- - - /** - * LIMIT - * - * @param int $value LIMIT value - * @param int $offset OFFSET value - * @return FW_DB_query_builder - */ - public function limit($value, $offset = 0) - { - is_null($value) OR $this->qb_limit = (int) $value; - empty($offset) OR $this->qb_offset = (int) $offset; - - return $this; - } - - // -------------------------------------------------------------------- - - /** - * Sets the OFFSET value - * - * @param int $offset OFFSET value - * @return FW_DB_query_builder - */ - public function offset($offset) - { - empty($offset) OR $this->qb_offset = (int) $offset; - return $this; - } - - // -------------------------------------------------------------------- - - /** - * LIMIT string - * - * Generates a platform-specific LIMIT clause. - * - * @param string $sql SQL Query - * @return string - */ - protected function _limit($sql) - { - return $sql.' LIMIT '.($this->qb_offset ? $this->qb_offset.', ' : '').$this->qb_limit; - } - - // -------------------------------------------------------------------- - - /** - * The "set" function. - * - * Allows key/value pairs to be set for inserting or updating - * - * @param mixed - * @param string - * @param bool - * @return FW_DB_query_builder - */ - public function set($key, $value = '', $escape = NULL) - { - $key = $this->_object_to_array($key); - - if ( ! is_array($key)) - { - $key = array($key => $value); - } - - is_bool($escape) OR $escape = $this->_protect_identifiers; - - foreach ($key as $k => $v) - { - $this->qb_set[$this->protect_identifiers($k, FALSE, $escape)] = ($escape) - ? $this->escape($v) : $v; - } - - return $this; - } - - // -------------------------------------------------------------------- - - /** - * Get SELECT query string - * - * Compiles a SELECT query string and returns the sql. - * - * @param string the table name to select from (optional) - * @param bool TRUE: resets QB values; FALSE: leave QB values alone - * @return string - */ - public function get_compiled_select($table = '', $reset = TRUE) - { - if ($table !== '') - { - $this->_track_aliases($table); - $this->from($table); - } - - $select = $this->_compile_select(); - - if ($reset === TRUE) - { - $this->_reset_select(); - } - - return $select; - } - - // -------------------------------------------------------------------- - - /** - * Get - * - * Compiles the select statement based on the other functions called - * and runs the query - * - * @param string the table - * @param string the limit clause - * @param string the offset clause - * @return FW_DB_result - */ - public function get($table = '', $limit = NULL, $offset = NULL) - { - if ($table !== '') - { - $this->_track_aliases($table); - $this->from($table); - } - - if ( ! empty($limit)) - { - $this->limit($limit, $offset); - } - - $result = $this->query($this->_compile_select()); - $this->_reset_select(); - return $result; - } - - // -------------------------------------------------------------------- - - /** - * "Count All Results" query - * - * Generates a platform-specific query string that counts all records - * returned by an Query Builder query. - * - * @param string - * @param bool the reset clause - * @return int - */ - public function count_all_results($table = '', $reset = TRUE) - { - if ($table !== '') - { - $this->_track_aliases($table); - $this->from($table); - } - - // ORDER BY usage is often problematic here (most notably - // on Microsoft SQL Server) and ultimately unnecessary - // for selecting COUNT(*) ... - if ( ! empty($this->qb_orderby)) - { - $orderby = $this->qb_orderby; - $this->qb_orderby = NULL; - } - - $result = ($this->qb_distinct === TRUE) - ? $this->query($this->_count_string.$this->protect_identifiers('numrows')."\nFROM (\n".$this->_compile_select()."\n) FW_count_all_results") - : $this->query($this->_compile_select($this->_count_string.$this->protect_identifiers('numrows'))); - - if ($reset === TRUE) - { - $this->_reset_select(); - } - // If we've previously reset the qb_orderby values, get them back - elseif ( ! isset($this->qb_orderby)) - { - $this->qb_orderby = $orderby; - } - - if ($result->num_rows() === 0) - { - return 0; - } - - $row = $result->row(); - return (int) $row->numrows; - } - - // -------------------------------------------------------------------- - - /** - * Get_Where - * - * Allows the where clause, limit and offset to be added directly - * - * @param string $table - * @param string $where - * @param int $limit - * @param int $offset - * @return FW_DB_result - */ - public function get_where($table = '', $where = NULL, $limit = NULL, $offset = NULL) - { - if ($table !== '') - { - $this->from($table); - } - - if ($where !== NULL) - { - $this->where($where); - } - - if ( ! empty($limit)) - { - $this->limit($limit, $offset); - } - - $result = $this->query($this->_compile_select()); - $this->_reset_select(); - return $result; - } - - // -------------------------------------------------------------------- - - /** - * Insert_Batch - * - * Compiles batch insert strings and runs the queries - * - * @param string $table Table to insert into - * @param array $set An associative array of insert values - * @param bool $escape Whether to escape values and identifiers - * @return int Number of rows inserted or FALSE on failure - */ - public function insert_batch($table, $set = NULL, $escape = NULL, $batch_size = 100) - { - if ($set === NULL) - { - if (empty($this->qb_set)) - { - return ($this->db_debug) ? $this->display_error('db_must_use_set') : FALSE; - } - } - else - { - if (empty($set)) - { - return ($this->db_debug) ? $this->display_error('insert_batch() called with no data') : FALSE; - } - - $this->set_insert_batch($set, '', $escape); - } - - if (strlen($table) === 0) - { - if ( ! isset($this->qb_from[0])) - { - return ($this->db_debug) ? $this->display_error('db_must_set_table') : FALSE; - } - - $table = $this->qb_from[0]; - } - - // Batch this baby - $affected_rows = 0; - for ($i = 0, $total = count($this->qb_set); $i < $total; $i += $batch_size) - { - $this->query($this->_insert_batch($this->protect_identifiers($table, TRUE, $escape, FALSE), $this->qb_keys, array_slice($this->qb_set, $i, $batch_size))); - $affected_rows += $this->affected_rows(); - } - - $this->_reset_write(); - return $affected_rows; - } - - // -------------------------------------------------------------------- - - /** - * Insert batch statement - * - * Generates a platform-specific insert string from the supplied data. - * - * @param string $table Table name - * @param array $keys INSERT keys - * @param array $values INSERT values - * @return string - */ - protected function _insert_batch($table, $keys, $values) - { - return 'INSERT INTO '.$table.' ('.implode(', ', $keys).') VALUES '.implode(', ', $values); - } - - // -------------------------------------------------------------------- - - /** - * The "set_insert_batch" function. Allows key/value pairs to be set for batch inserts - * - * @param mixed - * @param string - * @param bool - * @return FW_DB_query_builder - */ - public function set_insert_batch($key, $value = '', $escape = NULL) - { - $key = $this->_object_to_array_batch($key); - - if ( ! is_array($key)) - { - $key = array($key => $value); - } - - is_bool($escape) OR $escape = $this->_protect_identifiers; - - $keys = array_keys($this->_object_to_array(current($key))); - sort($keys); - - foreach ($key as $row) - { - $row = $this->_object_to_array($row); - if (count(array_diff($keys, array_keys($row))) > 0 OR count(array_diff(array_keys($row), $keys)) > 0) - { - // batch function above returns an error on an empty array - $this->qb_set[] = array(); - return; - } - - ksort($row); // puts $row in the same order as our keys - - if ($escape !== FALSE) - { - $clean = array(); - foreach ($row as $value) - { - $clean[] = $this->escape($value); - } - - $row = $clean; - } - - $this->qb_set[] = '('.implode(',', $row).')'; - } - - foreach ($keys as $k) - { - $this->qb_keys[] = $this->protect_identifiers($k, FALSE, $escape); - } - - return $this; - } - - // -------------------------------------------------------------------- - - /** - * Get INSERT query string - * - * Compiles an insert query and returns the sql - * - * @param string the table to insert into - * @param bool TRUE: reset QB values; FALSE: leave QB values alone - * @return string - */ - public function get_compiled_insert($table = '', $reset = TRUE) - { - if ($this->_validate_insert($table) === FALSE) - { - return FALSE; - } - - $sql = $this->_insert( - $this->protect_identifiers( - $this->qb_from[0], TRUE, NULL, FALSE - ), - array_keys($this->qb_set), - array_values($this->qb_set) - ); - - if ($reset === TRUE) - { - $this->_reset_write(); - } - - return $sql; - } - - // -------------------------------------------------------------------- - - /** - * Insert - * - * Compiles an insert string and runs the query - * - * @param string the table to insert data into - * @param array an associative array of insert values - * @param bool $escape Whether to escape values and identifiers - * @return bool TRUE on success, FALSE on failure - */ - public function insert($table = '', $set = NULL, $escape = NULL) - { - if ($set !== NULL) - { - $this->set($set, '', $escape); - } - - if ($this->_validate_insert($table) === FALSE) - { - return FALSE; - } - - $sql = $this->_insert( - $this->protect_identifiers( - $this->qb_from[0], TRUE, $escape, FALSE - ), - array_keys($this->qb_set), - array_values($this->qb_set) - ); - - $this->_reset_write(); - return $this->query($sql); - } - - // -------------------------------------------------------------------- - - /** - * Validate Insert - * - * This method is used by both insert() and get_compiled_insert() to - * validate that the there data is actually being set and that table - * has been chosen to be inserted into. - * - * @param string the table to insert data into - * @return string - */ - protected function _validate_insert($table = '') - { - if (count($this->qb_set) === 0) - { - return ($this->db_debug) ? $this->display_error('db_must_use_set') : FALSE; - } - - if ($table !== '') - { - $this->qb_from[0] = $table; - } - elseif ( ! isset($this->qb_from[0])) - { - return ($this->db_debug) ? $this->display_error('db_must_set_table') : FALSE; - } - - return TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Replace - * - * Compiles an replace into string and runs the query - * - * @param string the table to replace data into - * @param array an associative array of insert values - * @return bool TRUE on success, FALSE on failure - */ - public function replace($table = '', $set = NULL) - { - if ($set !== NULL) - { - $this->set($set); - } - - if (count($this->qb_set) === 0) - { - return ($this->db_debug) ? $this->display_error('db_must_use_set') : FALSE; - } - - if ($table === '') - { - if ( ! isset($this->qb_from[0])) - { - return ($this->db_debug) ? $this->display_error('db_must_set_table') : FALSE; - } - - $table = $this->qb_from[0]; - } - - $sql = $this->_replace($this->protect_identifiers($table, TRUE, NULL, FALSE), array_keys($this->qb_set), array_values($this->qb_set)); - - $this->_reset_write(); - return $this->query($sql); - } - - // -------------------------------------------------------------------- - - /** - * Replace statement - * - * Generates a platform-specific replace string from the supplied data - * - * @param string the table name - * @param array the insert keys - * @param array the insert values - * @return string - */ - protected function _replace($table, $keys, $values) - { - return 'REPLACE INTO '.$table.' ('.implode(', ', $keys).') VALUES ('.implode(', ', $values).')'; - } - - // -------------------------------------------------------------------- - - /** - * FROM tables - * - * Groups tables in FROM clauses if needed, so there is no confusion - * about operator precedence. - * - * Note: This is only used (and overridden) by MySQL and CUBRID. - * - * @return string - */ - protected function _from_tables() - { - return implode(', ', $this->qb_from); - } - - // -------------------------------------------------------------------- - - /** - * Get UPDATE query string - * - * Compiles an update query and returns the sql - * - * @param string the table to update - * @param bool TRUE: reset QB values; FALSE: leave QB values alone - * @return string - */ - public function get_compiled_update($table = '', $reset = TRUE) - { - // Combine any cached components with the current statements - $this->_merge_cache(); - - if ($this->_validate_update($table) === FALSE) - { - return FALSE; - } - - $sql = $this->_update($this->qb_from[0], $this->qb_set); - - if ($reset === TRUE) - { - $this->_reset_write(); - } - - return $sql; - } - - // -------------------------------------------------------------------- - - /** - * UPDATE - * - * Compiles an update string and runs the query. - * - * @param string $table - * @param array $set An associative array of update values - * @param mixed $where - * @param int $limit - * @return bool TRUE on success, FALSE on failure - */ - public function update($table = '', $set = NULL, $where = NULL, $limit = NULL) - { - // Combine any cached components with the current statements - $this->_merge_cache(); - - if ($set !== NULL) - { - $this->set($set); - } - - if ($this->_validate_update($table) === FALSE) - { - return FALSE; - } - - if ($where !== NULL) - { - $this->where($where); - } - - if ( ! empty($limit)) - { - $this->limit($limit); - } - - $sql = $this->_update($this->qb_from[0], $this->qb_set); - $this->_reset_write(); - return $this->query($sql); - } - - // -------------------------------------------------------------------- - - /** - * Validate Update - * - * This method is used by both update() and get_compiled_update() to - * validate that data is actually being set and that a table has been - * chosen to be update. - * - * @param string the table to update data on - * @return bool - */ - protected function _validate_update($table) - { - if (count($this->qb_set) === 0) - { - return ($this->db_debug) ? $this->display_error('db_must_use_set') : FALSE; - } - - if ($table !== '') - { - $this->qb_from = array($this->protect_identifiers($table, TRUE, NULL, FALSE)); - } - elseif ( ! isset($this->qb_from[0])) - { - return ($this->db_debug) ? $this->display_error('db_must_set_table') : FALSE; - } - - return TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Update_Batch - * - * Compiles an update string and runs the query - * - * @param string the table to retrieve the results from - * @param array an associative array of update values - * @param string the where key - * @return int number of rows affected or FALSE on failure - */ - public function update_batch($table, $set = NULL, $index = NULL, $batch_size = 100) - { - // Combine any cached components with the current statements - $this->_merge_cache(); - - if ($index === NULL) - { - return ($this->db_debug) ? $this->display_error('db_must_use_index') : FALSE; - } - - if ($set === NULL) - { - if (empty($this->qb_set)) - { - return ($this->db_debug) ? $this->display_error('db_must_use_set') : FALSE; - } - } - else - { - if (empty($set)) - { - return ($this->db_debug) ? $this->display_error('update_batch() called with no data') : FALSE; - } - - $this->set_update_batch($set, $index); - } - - if (strlen($table) === 0) - { - if ( ! isset($this->qb_from[0])) - { - return ($this->db_debug) ? $this->display_error('db_must_set_table') : FALSE; - } - - $table = $this->qb_from[0]; - } - - // Batch this baby - $affected_rows = 0; - for ($i = 0, $total = count($this->qb_set); $i < $total; $i += $batch_size) - { - $this->query($this->_update_batch($this->protect_identifiers($table, TRUE, NULL, FALSE), array_slice($this->qb_set, $i, $batch_size), $this->protect_identifiers($index))); - $affected_rows += $this->affected_rows(); - $this->qb_where = array(); - } - - $this->_reset_write(); - return $affected_rows; - } - - // -------------------------------------------------------------------- - - /** - * Update_Batch statement - * - * Generates a platform-specific batch update string from the supplied data - * - * @param string $table Table name - * @param array $values Update data - * @param string $index WHERE key - * @return string - */ - protected function _update_batch($table, $values, $index) - { - $ids = array(); - foreach ($values as $key => $val) - { - $ids[] = $val[$index]; - - foreach (array_keys($val) as $field) - { - if ($field !== $index) - { - $final[$field][] = 'WHEN '.$index.' = '.$val[$index].' THEN '.$val[$field]; - } - } - } - - $cases = ''; - foreach ($final as $k => $v) - { - $cases .= $k." = CASE \n" - .implode("\n", $v)."\n" - .'ELSE '.$k.' END, '; - } - - $this->where($index.' IN('.implode(',', $ids).')', NULL, FALSE); - - return 'UPDATE '.$table.' SET '.substr($cases, 0, -2).$this->_compile_wh('qb_where'); - } - - // -------------------------------------------------------------------- - - /** - * The "set_update_batch" function. Allows key/value pairs to be set for batch updating - * - * @param array - * @param string - * @param bool - * @return FW_DB_query_builder - */ - public function set_update_batch($key, $index = '', $escape = NULL) - { - $key = $this->_object_to_array_batch($key); - - if ( ! is_array($key)) - { - // @todo error - } - - is_bool($escape) OR $escape = $this->_protect_identifiers; - - foreach ($key as $k => $v) - { - $index_set = FALSE; - $clean = array(); - foreach ($v as $k2 => $v2) - { - if ($k2 === $index) - { - $index_set = TRUE; - } - - $clean[$this->protect_identifiers($k2, FALSE, $escape)] = ($escape === FALSE) ? $v2 : $this->escape($v2); - } - - if ($index_set === FALSE) - { - return $this->display_error('db_batch_missing_index'); - } - - $this->qb_set[] = $clean; - } - - return $this; - } - - // -------------------------------------------------------------------- - - /** - * Empty Table - * - * Compiles a delete string and runs "DELETE FROM table" - * - * @param string the table to empty - * @return bool TRUE on success, FALSE on failure - */ - public function empty_table($table = '') - { - if ($table === '') - { - if ( ! isset($this->qb_from[0])) - { - return ($this->db_debug) ? $this->display_error('db_must_set_table') : FALSE; - } - - $table = $this->qb_from[0]; - } - else - { - $table = $this->protect_identifiers($table, TRUE, NULL, FALSE); - } - - $sql = $this->_delete($table); - $this->_reset_write(); - return $this->query($sql); - } - - // -------------------------------------------------------------------- - - /** - * Truncate - * - * Compiles a truncate string and runs the query - * If the database does not support the truncate() command - * This function maps to "DELETE FROM table" - * - * @param string the table to truncate - * @return bool TRUE on success, FALSE on failure - */ - public function truncate($table = '') - { - if ($table === '') - { - if ( ! isset($this->qb_from[0])) - { - return ($this->db_debug) ? $this->display_error('db_must_set_table') : FALSE; - } - - $table = $this->qb_from[0]; - } - else - { - $table = $this->protect_identifiers($table, TRUE, NULL, FALSE); - } - - $sql = $this->_truncate($table); - $this->_reset_write(); - return $this->query($sql); - } - - // -------------------------------------------------------------------- - - /** - * Truncate statement - * - * Generates a platform-specific truncate string from the supplied data - * - * If the database does not support the truncate() command, - * then this method maps to 'DELETE FROM table' - * - * @param string the table name - * @return string - */ - protected function _truncate($table) - { - return 'TRUNCATE '.$table; - } - - // -------------------------------------------------------------------- - - /** - * Get DELETE query string - * - * Compiles a delete query string and returns the sql - * - * @param string the table to delete from - * @param bool TRUE: reset QB values; FALSE: leave QB values alone - * @return string - */ - public function get_compiled_delete($table = '', $reset = TRUE) - { - $this->return_delete_sql = TRUE; - $sql = $this->delete($table, '', NULL, $reset); - $this->return_delete_sql = FALSE; - return $sql; - } - - // -------------------------------------------------------------------- - - /** - * Delete - * - * Compiles a delete string and runs the query - * - * @param mixed the table(s) to delete from. String or array - * @param mixed the where clause - * @param mixed the limit clause - * @param bool - * @return mixed - */ - public function delete($table = '', $where = '', $limit = NULL, $reset_data = TRUE) - { - // Combine any cached components with the current statements - $this->_merge_cache(); - - if ($table === '') - { - if ( ! isset($this->qb_from[0])) - { - return ($this->db_debug) ? $this->display_error('db_must_set_table') : FALSE; - } - - $table = $this->qb_from[0]; - } - elseif (is_array($table)) - { - empty($where) && $reset_data = FALSE; - - foreach ($table as $single_table) - { - $this->delete($single_table, $where, $limit, $reset_data); - } - - return; - } - else - { - $table = $this->protect_identifiers($table, TRUE, NULL, FALSE); - } - - if ($where !== '') - { - $this->where($where); - } - - if ( ! empty($limit)) - { - $this->limit($limit); - } - - if (count($this->qb_where) === 0) - { - return ($this->db_debug) ? $this->display_error('db_del_must_use_where') : FALSE; - } - - $sql = $this->_delete($table); - if ($reset_data) - { - $this->_reset_write(); - } - - return ($this->return_delete_sql === TRUE) ? $sql : $this->query($sql); - } - - // -------------------------------------------------------------------- - - /** - * Delete statement - * - * Generates a platform-specific delete string from the supplied data - * - * @param string the table name - * @return string - */ - protected function _delete($table) - { - return 'DELETE FROM '.$table.$this->_compile_wh('qb_where') - .($this->qb_limit ? ' LIMIT '.$this->qb_limit : ''); - } - - // -------------------------------------------------------------------- - - /** - * DB Prefix - * - * Prepends a database prefix if one exists in configuration - * - * @param string the table - * @return string - */ - public function dbprefix($table = '') - { - if ($table === '') - { - $this->display_error('db_table_name_required'); - } - - return $this->dbprefix.$table; - } - - // -------------------------------------------------------------------- - - /** - * Set DB Prefix - * - * Set's the DB Prefix to something new without needing to reconnect - * - * @param string the prefix - * @return string - */ - public function set_dbprefix($prefix = '') - { - return $this->dbprefix = $prefix; - } - - // -------------------------------------------------------------------- - - /** - * Track Aliases - * - * Used to track SQL statements written with aliased tables. - * - * @param string The table to inspect - * @return string - */ - protected function _track_aliases($table) - { - if (is_array($table)) - { - foreach ($table as $t) - { - $this->_track_aliases($t); - } - return; - } - - // Does the string contain a comma? If so, we need to separate - // the string into discreet statements - if (strpos($table, ',') !== FALSE) - { - return $this->_track_aliases(explode(',', $table)); - } - - // if a table alias is used we can recognize it by a space - if (strpos($table, ' ') !== FALSE) - { - // if the alias is written with the AS keyword, remove it - $table = preg_replace('/\s+AS\s+/i', ' ', $table); - - // Grab the alias - $table = trim(strrchr($table, ' ')); - - // Store the alias, if it doesn't already exist - if ( ! in_array($table, $this->qb_aliased_tables)) - { - $this->qb_aliased_tables[] = $table; - } - } - } - - // -------------------------------------------------------------------- - - /** - * Compile the SELECT statement - * - * Generates a query string based on which functions were used. - * Should not be called directly. - * - * @param bool $select_override - * @return string - */ - protected function _compile_select($select_override = FALSE) - { - // Combine any cached components with the current statements - $this->_merge_cache(); - - // Write the "select" portion of the query - if ($select_override !== FALSE) - { - $sql = $select_override; - } - else - { - $sql = ( ! $this->qb_distinct) ? 'SELECT ' : 'SELECT DISTINCT '; - - if (count($this->qb_select) === 0) - { - $sql .= '*'; - } - else - { - // Cycle through the "select" portion of the query and prep each column name. - // The reason we protect identifiers here rather than in the select() function - // is because until the user calls the from() function we don't know if there are aliases - foreach ($this->qb_select as $key => $val) - { - $no_escape = isset($this->qb_no_escape[$key]) ? $this->qb_no_escape[$key] : NULL; - $this->qb_select[$key] = $this->protect_identifiers($val, FALSE, $no_escape); - } - - $sql .= implode(', ', $this->qb_select); - } - } - - // Write the "FROM" portion of the query - if (count($this->qb_from) > 0) - { - $sql .= "\nFROM ".$this->_from_tables(); - } - - // Write the "JOIN" portion of the query - if (count($this->qb_join) > 0) - { - $sql .= "\n".implode("\n", $this->qb_join); - } - - $sql .= $this->_compile_wh('qb_where') - .$this->_compile_group_by() - .$this->_compile_wh('qb_having') - .$this->_compile_order_by(); // ORDER BY - - // LIMIT - if ($this->qb_limit) - { - return $this->_limit($sql."\n"); - } - - return $sql; - } - - // -------------------------------------------------------------------- - - /** - * Compile WHERE, HAVING statements - * - * Escapes identifiers in WHERE and HAVING statements at execution time. - * - * Required so that aliases are tracked properly, regardless of whether - * where(), or_where(), having(), or_having are called prior to from(), - * join() and dbprefix is added only if needed. - * - * @param string $qb_key 'qb_where' or 'qb_having' - * @return string SQL statement - */ - protected function _compile_wh($qb_key) - { - if (count($this->$qb_key) > 0) - { - for ($i = 0, $c = count($this->$qb_key); $i < $c; $i++) - { - // Is this condition already compiled? - if (is_string($this->{$qb_key}[$i])) - { - continue; - } - elseif ($this->{$qb_key}[$i]['escape'] === FALSE) - { - $this->{$qb_key}[$i] = $this->{$qb_key}[$i]['condition']; - continue; - } - - // Split multiple conditions - $conditions = preg_split( - '/((?:^|\s+)AND\s+|(?:^|\s+)OR\s+)/i', - $this->{$qb_key}[$i]['condition'], - -1, - PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY - ); - - for ($ci = 0, $cc = count($conditions); $ci < $cc; $ci++) - { - if (($op = $this->_get_operator($conditions[$ci])) === FALSE - OR ! preg_match('/^(\(?)(.*)('.preg_quote($op, '/').')\s*(.*(? '(test <= foo)', /* the whole thing */ - // 1 => '(', /* optional */ - // 2 => 'test', /* the field name */ - // 3 => ' <= ', /* $op */ - // 4 => 'foo', /* optional, if $op is e.g. 'IS NULL' */ - // 5 => ')' /* optional */ - // ); - - if ( ! empty($matches[4])) - { - $this->_is_literal($matches[4]) OR $matches[4] = $this->protect_identifiers(trim($matches[4])); - $matches[4] = ' '.$matches[4]; - } - - $conditions[$ci] = $matches[1].$this->protect_identifiers(trim($matches[2])) - .' '.trim($matches[3]).$matches[4].$matches[5]; - } - - $this->{$qb_key}[$i] = implode('', $conditions); - } - - return ($qb_key === 'qb_having' ? "\nHAVING " : "\nWHERE ") - .implode("\n", $this->$qb_key); - } - - return ''; - } - - // -------------------------------------------------------------------- - - /** - * Compile GROUP BY - * - * Escapes identifiers in GROUP BY statements at execution time. - * - * Required so that aliases are tracked properly, regardless of wether - * group_by() is called prior to from(), join() and dbprefix is added - * only if needed. - * - * @return string SQL statement - */ - protected function _compile_group_by() - { - if (count($this->qb_groupby) > 0) - { - for ($i = 0, $c = count($this->qb_groupby); $i < $c; $i++) - { - // Is it already compiled? - if (is_string($this->qb_groupby[$i])) - { - continue; - } - - $this->qb_groupby[$i] = ($this->qb_groupby[$i]['escape'] === FALSE OR $this->_is_literal($this->qb_groupby[$i]['field'])) - ? $this->qb_groupby[$i]['field'] - : $this->protect_identifiers($this->qb_groupby[$i]['field']); - } - - return "\nGROUP BY ".implode(', ', $this->qb_groupby); - } - - return ''; - } - - // -------------------------------------------------------------------- - - /** - * Compile ORDER BY - * - * Escapes identifiers in ORDER BY statements at execution time. - * - * Required so that aliases are tracked properly, regardless of wether - * order_by() is called prior to from(), join() and dbprefix is added - * only if needed. - * - * @return string SQL statement - */ - protected function _compile_order_by() - { - if (is_array($this->qb_orderby) && count($this->qb_orderby) > 0) - { - for ($i = 0, $c = count($this->qb_orderby); $i < $c; $i++) - { - if ($this->qb_orderby[$i]['escape'] !== FALSE && ! $this->_is_literal($this->qb_orderby[$i]['field'])) - { - $this->qb_orderby[$i]['field'] = $this->protect_identifiers($this->qb_orderby[$i]['field']); - } - - $this->qb_orderby[$i] = $this->qb_orderby[$i]['field'].$this->qb_orderby[$i]['direction']; - } - - return $this->qb_orderby = "\nORDER BY ".implode(', ', $this->qb_orderby); - } - elseif (is_string($this->qb_orderby)) - { - return $this->qb_orderby; - } - - return ''; - } - - // -------------------------------------------------------------------- - - /** - * Object to Array - * - * Takes an object as input and converts the class variables to array key/vals - * - * @param object - * @return array - */ - protected function _object_to_array($object) - { - if ( ! is_object($object)) - { - return $object; - } - - $array = array(); - foreach (get_object_vars($object) as $key => $val) - { - // There are some built in keys we need to ignore for this conversion - if ( ! is_object($val) && ! is_array($val) && $key !== '_parent_name') - { - $array[$key] = $val; - } - } - - return $array; - } - - // -------------------------------------------------------------------- - - /** - * Object to Array - * - * Takes an object as input and converts the class variables to array key/vals - * - * @param object - * @return array - */ - protected function _object_to_array_batch($object) - { - if ( ! is_object($object)) - { - return $object; - } - - $array = array(); - $out = get_object_vars($object); - $fields = array_keys($out); - - foreach ($fields as $val) - { - // There are some built in keys we need to ignore for this conversion - if ($val !== '_parent_name') - { - $i = 0; - foreach ($out[$val] as $data) - { - $array[$i++][$val] = $data; - } - } - } - - return $array; - } - - // -------------------------------------------------------------------- - - /** - * Start Cache - * - * Starts QB caching - * - * @return FW_DB_query_builder - */ - public function start_cache() - { - $this->qb_caching = TRUE; - return $this; - } - - // -------------------------------------------------------------------- - - /** - * Stop Cache - * - * Stops QB caching - * - * @return FW_DB_query_builder - */ - public function stop_cache() - { - $this->qb_caching = FALSE; - return $this; - } - - // -------------------------------------------------------------------- - - /** - * Flush Cache - * - * Empties the QB cache - * - * @return FW_DB_query_builder - */ - public function flush_cache() - { - $this->_reset_run(array( - 'qb_cache_select' => array(), - 'qb_cache_from' => array(), - 'qb_cache_join' => array(), - 'qb_cache_where' => array(), - 'qb_cache_groupby' => array(), - 'qb_cache_having' => array(), - 'qb_cache_orderby' => array(), - 'qb_cache_set' => array(), - 'qb_cache_exists' => array(), - 'qb_cache_no_escape' => array() - )); - - return $this; - } - - // -------------------------------------------------------------------- - - /** - * Merge Cache - * - * When called, this function merges any cached QB arrays with - * locally called ones. - * - * @return void - */ - protected function _merge_cache() - { - if (count($this->qb_cache_exists) === 0) - { - return; - } - elseif (in_array('select', $this->qb_cache_exists, TRUE)) - { - $qb_no_escape = $this->qb_cache_no_escape; - } - - foreach (array_unique($this->qb_cache_exists) as $val) // select, from, etc. - { - $qb_variable = 'qb_'.$val; - $qb_cache_var = 'qb_cache_'.$val; - $qb_new = $this->$qb_cache_var; - - for ($i = 0, $c = count($this->$qb_variable); $i < $c; $i++) - { - if ( ! in_array($this->{$qb_variable}[$i], $qb_new, TRUE)) - { - $qb_new[] = $this->{$qb_variable}[$i]; - if ($val === 'select') - { - $qb_no_escape[] = $this->qb_no_escape[$i]; - } - } - } - - $this->$qb_variable = $qb_new; - if ($val === 'select') - { - $this->qb_no_escape = $qb_no_escape; - } - } - - // If we are "protecting identifiers" we need to examine the "from" - // portion of the query to determine if there are any aliases - if ($this->_protect_identifiers === TRUE && count($this->qb_cache_from) > 0) - { - $this->_track_aliases($this->qb_from); - } - } - - // -------------------------------------------------------------------- - - /** - * Is literal - * - * Determines if a string represents a literal value or a field name - * - * @param string $str - * @return bool - */ - protected function _is_literal($str) - { - $str = trim($str); - - if (empty($str) OR ctype_digit($str) OR (string) (float) $str === $str OR in_array(strtoupper($str), array('TRUE', 'FALSE'), TRUE)) - { - return TRUE; - } - - static $_str; - - if (empty($_str)) - { - $_str = ($this->_escape_char !== '"') - ? array('"', "'") : array("'"); - } - - return in_array($str[0], $_str, TRUE); - } - - // -------------------------------------------------------------------- - - /** - * Reset Query Builder values. - * - * Publicly-visible method to reset the QB values. - * - * @return FW_DB_query_builder - */ - public function reset_query() - { - $this->_reset_select(); - $this->_reset_write(); - return $this; - } - - // -------------------------------------------------------------------- - - /** - * Resets the query builder values. Called by the get() function - * - * @param array An array of fields to reset - * @return void - */ - protected function _reset_run($qb_reset_items) - { - foreach ($qb_reset_items as $item => $default_value) - { - $this->$item = $default_value; - } - } - - // -------------------------------------------------------------------- - - /** - * Resets the query builder values. Called by the get() function - * - * @return void - */ - protected function _reset_select() - { - $this->_reset_run(array( - 'qb_select' => array(), - 'qb_from' => array(), - 'qb_join' => array(), - 'qb_where' => array(), - 'qb_groupby' => array(), - 'qb_having' => array(), - 'qb_orderby' => array(), - 'qb_aliased_tables' => array(), - 'qb_no_escape' => array(), - 'qb_distinct' => FALSE, - 'qb_limit' => FALSE, - 'qb_offset' => FALSE - )); - } - - // -------------------------------------------------------------------- - - /** - * Resets the query builder "write" values. - * - * Called by the insert() update() insert_batch() update_batch() and delete() functions - * - * @return void - */ - protected function _reset_write() - { - $this->_reset_run(array( - 'qb_set' => array(), - 'qb_from' => array(), - 'qb_join' => array(), - 'qb_where' => array(), - 'qb_orderby' => array(), - 'qb_keys' => array(), - 'qb_limit' => FALSE - )); - } - -} diff --git a/src/Database/DB_result.php b/src/Database/DB_result.php deleted file mode 100644 index e7c3c6b..0000000 --- a/src/Database/DB_result.php +++ /dev/null @@ -1,670 +0,0 @@ -conn_id = $driver_object->conn_id; - $this->result_id = $driver_object->result_id; - } - - // -------------------------------------------------------------------- - - /** - * Number of rows in the result set - * - * @return int - */ - public function num_rows() - { - if (is_int($this->num_rows)) - { - return $this->num_rows; - } - elseif (count($this->result_array) > 0) - { - return $this->num_rows = count($this->result_array); - } - elseif (count($this->result_object) > 0) - { - return $this->num_rows = count($this->result_object); - } - - return $this->num_rows = count($this->result_array()); - } - - // -------------------------------------------------------------------- - - /** - * Query result. Acts as a wrapper function for the following functions. - * - * @param string $type 'object', 'array' or a custom class name - * @return array - */ - public function result($type = 'object') - { - if ($type === 'array') - { - return $this->result_array(); - } - elseif ($type === 'object') - { - return $this->result_object(); - } - else - { - return $this->custom_result_object($type); - } - } - - // -------------------------------------------------------------------- - - /** - * Custom query result. - * - * @param string $class_name - * @return array - */ - public function custom_result_object($class_name) - { - if (isset($this->custom_result_object[$class_name])) - { - return $this->custom_result_object[$class_name]; - } - elseif ( ! $this->result_id OR $this->num_rows === 0) - { - return array(); - } - - // Don't fetch the result set again if we already have it - $_data = NULL; - if (($c = count($this->result_array)) > 0) - { - $_data = 'result_array'; - } - elseif (($c = count($this->result_object)) > 0) - { - $_data = 'result_object'; - } - - if ($_data !== NULL) - { - for ($i = 0; $i < $c; $i++) - { - $this->custom_result_object[$class_name][$i] = new $class_name(); - - foreach ($this->{$_data}[$i] as $key => $value) - { - $this->custom_result_object[$class_name][$i]->$key = $value; - } - } - - return $this->custom_result_object[$class_name]; - } - - is_null($this->row_data) OR $this->data_seek(0); - $this->custom_result_object[$class_name] = array(); - - while ($row = $this->_fetch_object($class_name)) - { - $this->custom_result_object[$class_name][] = $row; - } - - return $this->custom_result_object[$class_name]; - } - - // -------------------------------------------------------------------- - - /** - * Query result. "object" version. - * - * @return array - */ - public function result_object() - { - if (count($this->result_object) > 0) - { - return $this->result_object; - } - - // In the event that query caching is on, the result_id variable - // will not be a valid resource so we'll simply return an empty - // array. - if ( ! $this->result_id OR $this->num_rows === 0) - { - return array(); - } - - if (($c = count($this->result_array)) > 0) - { - for ($i = 0; $i < $c; $i++) - { - $this->result_object[$i] = (object) $this->result_array[$i]; - } - - return $this->result_object; - } - - is_null($this->row_data) OR $this->data_seek(0); - while ($row = $this->_fetch_object()) - { - $this->result_object[] = $row; - } - - return $this->result_object; - } - - // -------------------------------------------------------------------- - - /** - * Query result. "array" version. - * - * @return array - */ - public function result_array() - { - if (count($this->result_array) > 0) - { - return $this->result_array; - } - - // In the event that query caching is on, the result_id variable - // will not be a valid resource so we'll simply return an empty - // array. - if ( ! $this->result_id OR $this->num_rows === 0) - { - return array(); - } - - if (($c = count($this->result_object)) > 0) - { - for ($i = 0; $i < $c; $i++) - { - $this->result_array[$i] = (array) $this->result_object[$i]; - } - - return $this->result_array; - } - - is_null($this->row_data) OR $this->data_seek(0); - while ($row = $this->_fetch_assoc()) - { - $this->result_array[] = $row; - } - - return $this->result_array; - } - - // -------------------------------------------------------------------- - - /** - * Row - * - * A wrapper method. - * - * @param mixed $n - * @param string $type 'object' or 'array' - * @return mixed - */ - public function row($n = 0, $type = 'object') - { - if ( ! is_numeric($n)) - { - // We cache the row data for subsequent uses - is_array($this->row_data) OR $this->row_data = $this->row_array(0); - - // array_key_exists() instead of isset() to allow for NULL values - if (empty($this->row_data) OR ! array_key_exists($n, $this->row_data)) - { - return NULL; - } - - return $this->row_data[$n]; - } - - if ($type === 'object') return $this->row_object($n); - elseif ($type === 'array') return $this->row_array($n); - else return $this->custom_row_object($n, $type); - } - - // -------------------------------------------------------------------- - - /** - * Assigns an item into a particular column slot - * - * @param mixed $key - * @param mixed $value - * @return void - */ - public function set_row($key, $value = NULL) - { - // We cache the row data for subsequent uses - if ( ! is_array($this->row_data)) - { - $this->row_data = $this->row_array(0); - } - - if (is_array($key)) - { - foreach ($key as $k => $v) - { - $this->row_data[$k] = $v; - } - return; - } - - if ($key !== '' && $value !== NULL) - { - $this->row_data[$key] = $value; - } - } - - // -------------------------------------------------------------------- - - /** - * Returns a single result row - custom object version - * - * @param int $n - * @param string $type - * @return object - */ - public function custom_row_object($n, $type) - { - isset($this->custom_result_object[$type]) OR $this->custom_result_object($type); - - if (count($this->custom_result_object[$type]) === 0) - { - return NULL; - } - - if ($n !== $this->current_row && isset($this->custom_result_object[$type][$n])) - { - $this->current_row = $n; - } - - return $this->custom_result_object[$type][$this->current_row]; - } - - // -------------------------------------------------------------------- - - /** - * Returns a single result row - object version - * - * @param int $n - * @return object - */ - public function row_object($n = 0) - { - $result = $this->result_object(); - if (count($result) === 0) - { - return NULL; - } - - if ($n !== $this->current_row && isset($result[$n])) - { - $this->current_row = $n; - } - - return $result[$this->current_row]; - } - - // -------------------------------------------------------------------- - - /** - * Returns a single result row - array version - * - * @param int $n - * @return array - */ - public function row_array($n = 0) - { - $result = $this->result_array(); - if (count($result) === 0) - { - return NULL; - } - - if ($n !== $this->current_row && isset($result[$n])) - { - $this->current_row = $n; - } - - return $result[$this->current_row]; - } - - // -------------------------------------------------------------------- - - /** - * Returns the "first" row - * - * @param string $type - * @return mixed - */ - public function first_row($type = 'object') - { - $result = $this->result($type); - return (count($result) === 0) ? NULL : $result[0]; - } - - // -------------------------------------------------------------------- - - /** - * Returns the "last" row - * - * @param string $type - * @return mixed - */ - public function last_row($type = 'object') - { - $result = $this->result($type); - return (count($result) === 0) ? NULL : $result[count($result) - 1]; - } - - // -------------------------------------------------------------------- - - /** - * Returns the "next" row - * - * @param string $type - * @return mixed - */ - public function next_row($type = 'object') - { - $result = $this->result($type); - if (count($result) === 0) - { - return NULL; - } - - return isset($result[$this->current_row + 1]) - ? $result[++$this->current_row] - : NULL; - } - - // -------------------------------------------------------------------- - - /** - * Returns the "previous" row - * - * @param string $type - * @return mixed - */ - public function previous_row($type = 'object') - { - $result = $this->result($type); - if (count($result) === 0) - { - return NULL; - } - - if (isset($result[$this->current_row - 1])) - { - --$this->current_row; - } - return $result[$this->current_row]; - } - - // -------------------------------------------------------------------- - - /** - * Returns an unbuffered row and move pointer to next row - * - * @param string $type 'array', 'object' or a custom class name - * @return mixed - */ - public function unbuffered_row($type = 'object') - { - if ($type === 'array') - { - return $this->_fetch_assoc(); - } - elseif ($type === 'object') - { - return $this->_fetch_object(); - } - - return $this->_fetch_object($type); - } - - // -------------------------------------------------------------------- - - /** - * The following methods are normally overloaded by the identically named - * methods in the platform-specific driver -- except when query caching - * is used. When caching is enabled we do not load the other driver. - * These functions are primarily here to prevent undefined function errors - * when a cached result object is in use. They are not otherwise fully - * operational due to the unavailability of the database resource IDs with - * cached results. - */ - - // -------------------------------------------------------------------- - - /** - * Number of fields in the result set - * - * Overridden by driver result classes. - * - * @return int - */ - public function num_fields() - { - return 0; - } - - // -------------------------------------------------------------------- - - /** - * Fetch Field Names - * - * Generates an array of column names. - * - * Overridden by driver result classes. - * - * @return array - */ - public function list_fields() - { - return array(); - } - - // -------------------------------------------------------------------- - - /** - * Field data - * - * Generates an array of objects containing field meta-data. - * - * Overridden by driver result classes. - * - * @return array - */ - public function field_data() - { - return array(); - } - - // -------------------------------------------------------------------- - - /** - * Free the result - * - * Overridden by driver result classes. - * - * @return void - */ - public function free_result() - { - $this->result_id = FALSE; - } - - // -------------------------------------------------------------------- - - /** - * Data Seek - * - * Moves the internal pointer to the desired offset. We call - * this internally before fetching results to make sure the - * result set starts at zero. - * - * Overridden by driver result classes. - * - * @param int $n - * @return bool - */ - public function data_seek($n = 0) - { - return FALSE; - } - - // -------------------------------------------------------------------- - - /** - * Result - associative array - * - * Returns the result set as an array. - * - * Overridden by driver result classes. - * - * @return array - */ - protected function _fetch_assoc() - { - return array(); - } - - // -------------------------------------------------------------------- - - /** - * Result - object - * - * Returns the result set as an object. - * - * Overridden by driver result classes. - * - * @param string $class_name - * @return object - */ - protected function _fetch_object($class_name = 'stdClass') - { - return array(); - } - -} diff --git a/src/Database/DB_utility.php b/src/Database/DB_utility.php deleted file mode 100644 index f229231..0000000 --- a/src/Database/DB_utility.php +++ /dev/null @@ -1,438 +0,0 @@ -db =& $db; - $this->factory = Factory::getInstance(); - Logger::log('Database Utility Class Initialized'); - } - - // -------------------------------------------------------------------- - - /** - * List databases - * - * @return array - */ - public function list_databases() - { - // Is there a cached result? - if (isset($this->db->data_cache['db_names'])) - { - return $this->db->data_cache['db_names']; - } - elseif ($this->_list_databases === FALSE) - { - return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE; - } - - $this->db->data_cache['db_names'] = array(); - - $query = $this->db->query($this->_list_databases); - if ($query === FALSE) - { - return $this->db->data_cache['db_names']; - } - - for ($i = 0, $query = $query->result_array(), $c = count($query); $i < $c; $i++) - { - $this->db->data_cache['db_names'][] = current($query[$i]); - } - - return $this->db->data_cache['db_names']; - } - - // -------------------------------------------------------------------- - - /** - * Determine if a particular database exists - * - * @param string $database_name - * @return bool - */ - public function database_exists($database_name) - { - return in_array($database_name, $this->list_databases()); - } - - // -------------------------------------------------------------------- - - /** - * Optimize Table - * - * @param string $table_name - * @return mixed - */ - public function optimize_table($table_name) - { - if ($this->_optimize_table === FALSE) - { - return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE; - } - - $query = $this->db->query(sprintf($this->_optimize_table, $this->db->escape_identifiers($table_name))); - if ($query !== FALSE) - { - $query = $query->result_array(); - return current($query); - } - - return FALSE; - } - - // -------------------------------------------------------------------- - - /** - * Optimize Database - * - * @return mixed - */ - public function optimize_database() - { - if ($this->_optimize_table === FALSE) - { - return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE; - } - - $result = array(); - foreach ($this->db->list_tables() as $table_name) - { - $res = $this->db->query(sprintf($this->_optimize_table, $this->db->escape_identifiers($table_name))); - if (is_bool($res)) - { - return $res; - } - - // Build the result array... - $res = $res->result_array(); - $res = current($res); - $key = str_replace($this->db->database.'.', '', current($res)); - $keys = array_keys($res); - unset($res[$keys[0]]); - - $result[$key] = $res; - } - - return $result; - } - - // -------------------------------------------------------------------- - - /** - * Repair Table - * - * @param string $table_name - * @return mixed - */ - public function repair_table($table_name) - { - if ($this->_repair_table === FALSE) - { - return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE; - } - - $query = $this->db->query(sprintf($this->_repair_table, $this->db->escape_identifiers($table_name))); - if (is_bool($query)) - { - return $query; - } - - $query = $query->result_array(); - return current($query); - } - - // -------------------------------------------------------------------- - - /** - * Generate CSV from a query result object - * - * @param object $query Query result object - * @param string $delim Delimiter (default: ,) - * @param string $newline Newline character (default: \n) - * @param string $enclosure Enclosure (default: ") - * @return string - */ - public function csv_from_result($query, $delim = ',', $newline = "\n", $enclosure = '"') - { - if ( ! is_object($query) OR ! method_exists($query, 'list_fields')) - { - throw new DatabaseException('You must submit a valid result object', 1); - } - - $out = ''; - // First generate the headings from the table column names - foreach ($query->list_fields() as $name) - { - $out .= $enclosure.str_replace($enclosure, $enclosure.$enclosure, $name).$enclosure.$delim; - } - - $out = substr($out, 0, -strlen($delim)).$newline; - - // Next blast through the result array and build out the rows - while ($row = $query->unbuffered_row('array')) - { - $line = array(); - foreach ($row as $item) - { - $line[] = $enclosure.str_replace($enclosure, $enclosure.$enclosure, $item).$enclosure; - } - $out .= implode($delim, $line).$newline; - } - - return $out; - } - - // -------------------------------------------------------------------- - - /** - * Generate XML data from a query result object - * - * @param object $query Query result object - * @param array $params Any preferences - * @return string - */ - public function xml_from_result($query, $params = array()) - { - if ( ! is_object($query) OR ! method_exists($query, 'list_fields')) - { - throw new DatabaseException('You must submit a valid result object', 1); - } - - // Set our default values - foreach (array('root' => 'root', 'element' => 'element', 'newline' => "\n", 'tab' => "\t") as $key => $val) - { - if ( ! isset($params[$key])) - { - $params[$key] = $val; - } - } - - // Create variables for convenience - extract($params); - - // Load the xml helper - $this->factory->helpers->load('xml'); - - // Generate the result - $xml = '<'.$root.'>'.$newline; - while ($row = $query->unbuffered_row()) - { - $xml .= $tab.'<'.$element.'>'.$newline; - foreach ($row as $key => $val) - { - $xml .= $tab.$tab.'<'.$key.'>'.xml_convert($val).''.$newline; - } - $xml .= $tab.''.$newline; - } - - return $xml.''.$newline; - } - - // -------------------------------------------------------------------- - - /** - * Database Backup - * - * @param array $params - * @return string - */ - public function backup($params = array()) - { - // If the parameters have not been submitted as an - // array then we know that it is simply the table - // name, which is a valid short cut. - if (is_string($params)) - { - $params = array('tables' => $params); - } - - // Set up our default preferences - $prefs = array( - 'tables' => array(), - 'ignore' => array(), - 'filename' => '', - 'format' => 'gzip', // gzip, zip, txt - 'add_drop' => TRUE, - 'add_insert' => TRUE, - 'newline' => "\n", - 'foreign_key_checks' => TRUE - ); - - // Did the user submit any preferences? If so set them.... - if (count($params) > 0) - { - foreach ($prefs as $key => $val) - { - if (isset($params[$key])) - { - $prefs[$key] = $params[$key]; - } - } - } - - // Are we backing up a complete database or individual tables? - // If no table names were submitted we'll fetch the entire table list - if (count($prefs['tables']) === 0) - { - $prefs['tables'] = $this->db->list_tables(); - } - - // Validate the format - if ( ! in_array($prefs['format'], array('gzip', 'zip', 'txt'), TRUE)) - { - $prefs['format'] = 'txt'; - } - - // Is the encoder supported? If not, we'll either issue an - // error or use plain text depending on the debug settings - if (($prefs['format'] === 'gzip' && ! function_exists('gzencode')) - OR ($prefs['format'] === 'zip' && ! function_exists('gzcompress'))) - { - if ($this->db->db_debug) - { - return $this->db->display_error('db_unsupported_compression'); - } - - $prefs['format'] = 'txt'; - } - - // Was a Zip file requested? - if ($prefs['format'] === 'zip') - { - // Set the filename if not provided (only needed with Zip files) - if ($prefs['filename'] === '') - { - $prefs['filename'] = (count($prefs['tables']) === 1 ? $prefs['tables'] : $this->db->database) - .date('Y-m-d_H-i', time()).'.sql'; - } - else - { - // If they included the .zip file extension we'll remove it - if (preg_match('|.+?\.zip$|', $prefs['filename'])) - { - $prefs['filename'] = str_replace('.zip', '', $prefs['filename']); - } - - // Tack on the ".sql" file extension if needed - if ( ! preg_match('|.+?\.sql$|', $prefs['filename'])) - { - $prefs['filename'] .= '.sql'; - } - } - - // Load the Zip class and output it - $zip = Libraries::get('zip'); - $zip->add_data($prefs['filename'], $this->_backup($prefs)); - return $zip->get_zip(); - } - elseif ($prefs['format'] === 'txt') // Was a text file requested? - { - return $this->_backup($prefs); - } - elseif ($prefs['format'] === 'gzip') // Was a Gzip file requested? - { - return gzencode($this->_backup($prefs)); - } - - return; - } - -} diff --git a/src/Database/drivers/cubrid/cubrid_driver.php b/src/Database/drivers/cubrid/cubrid_driver.php deleted file mode 100644 index 039971d..0000000 --- a/src/Database/drivers/cubrid/cubrid_driver.php +++ /dev/null @@ -1,405 +0,0 @@ -dsn, $matches)) - { - if (stripos($matches[2], 'autocommit=off') !== FALSE) - { - $this->auto_commit = FALSE; - } - } - else - { - // If no port is defined by the user, use the default value - empty($this->port) OR $this->port = 33000; - } - } - - // -------------------------------------------------------------------- - - /** - * Non-persistent database connection - * - * @param bool $persistent - * @return resource - */ - public function db_connect($persistent = FALSE) - { - if (preg_match('/^CUBRID:[^:]+(:[0-9][1-9]{0,4})?:[^:]+:([^:]*):([^:]*):(\?.+)?$/', $this->dsn, $matches)) - { - $func = ($persistent !== TRUE) ? 'cubrid_connect_with_url' : 'cubrid_pconnect_with_url'; - return ($matches[2] === '' && $matches[3] === '' && $this->username !== '' && $this->password !== '') - ? $func($this->dsn, $this->username, $this->password) - : $func($this->dsn); - } - - $func = ($persistent !== TRUE) ? 'cubrid_connect' : 'cubrid_pconnect'; - return ($this->username !== '') - ? $func($this->hostname, $this->port, $this->database, $this->username, $this->password) - : $func($this->hostname, $this->port, $this->database); - } - - // -------------------------------------------------------------------- - - /** - * Reconnect - * - * Keep / reestablish the db connection if no queries have been - * sent for a length of time exceeding the server's idle timeout - * - * @return void - */ - public function reconnect() - { - if (cubrid_ping($this->conn_id) === FALSE) - { - $this->conn_id = FALSE; - } - } - - // -------------------------------------------------------------------- - - /** - * Database version number - * - * @return string - */ - public function version() - { - if (isset($this->data_cache['version'])) - { - return $this->data_cache['version']; - } - - return ( ! $this->conn_id OR ($version = cubrid_get_server_info($this->conn_id)) === FALSE) - ? FALSE - : $this->data_cache['version'] = $version; - } - - // -------------------------------------------------------------------- - - /** - * Execute the query - * - * @param string $sql an SQL query - * @return resource - */ - protected function _execute($sql) - { - return cubrid_query($sql, $this->conn_id); - } - - // -------------------------------------------------------------------- - - /** - * Begin Transaction - * - * @return bool - */ - protected function _trans_begin() - { - if (($autocommit = cubrid_get_autocommit($this->conn_id)) === NULL) - { - return FALSE; - } - elseif ($autocommit === TRUE) - { - return cubrid_set_autocommit($this->conn_id, CUBRID_AUTOCOMMIT_FALSE); - } - - return TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Commit Transaction - * - * @return bool - */ - protected function _trans_commit() - { - if ( ! cubrid_commit($this->conn_id)) - { - return FALSE; - } - - if ($this->auto_commit && ! cubrid_get_autocommit($this->conn_id)) - { - return cubrid_set_autocommit($this->conn_id, CUBRID_AUTOCOMMIT_TRUE); - } - - return TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Rollback Transaction - * - * @return bool - */ - protected function _trans_rollback() - { - if ( ! cubrid_rollback($this->conn_id)) - { - return FALSE; - } - - if ($this->auto_commit && ! cubrid_get_autocommit($this->conn_id)) - { - cubrid_set_autocommit($this->conn_id, CUBRID_AUTOCOMMIT_TRUE); - } - - return TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Platform-dependant string escape - * - * @param string - * @return string - */ - protected function _escape_str($str) - { - return cubrid_real_escape_string($str, $this->conn_id); - } - - // -------------------------------------------------------------------- - - /** - * Affected Rows - * - * @return int - */ - public function affected_rows() - { - return cubrid_affected_rows(); - } - - // -------------------------------------------------------------------- - - /** - * Insert ID - * - * @return int - */ - public function insert_id() - { - return cubrid_insert_id($this->conn_id); - } - - // -------------------------------------------------------------------- - - /** - * List table query - * - * Generates a platform-specific query string so that the table names can be fetched - * - * @param bool $prefix_limit - * @return string - */ - protected function _list_tables($prefix_limit = FALSE) - { - $sql = 'SHOW TABLES'; - - if ($prefix_limit !== FALSE && $this->dbprefix !== '') - { - return $sql." LIKE '".$this->escape_like_str($this->dbprefix)."%'"; - } - - return $sql; - } - - // -------------------------------------------------------------------- - - /** - * Show column query - * - * Generates a platform-specific query string so that the column names can be fetched - * - * @param string $table - * @return string - */ - protected function _list_columns($table = '') - { - return 'SHOW COLUMNS FROM '.$this->protect_identifiers($table, TRUE, NULL, FALSE); - } - - // -------------------------------------------------------------------- - - /** - * Returns an object with field data - * - * @param string $table - * @return array - */ - public function field_data($table) - { - if (($query = $this->query('SHOW COLUMNS FROM '.$this->protect_identifiers($table, TRUE, NULL, FALSE))) === FALSE) - { - return FALSE; - } - $query = $query->result_object(); - - $retval = array(); - for ($i = 0, $c = count($query); $i < $c; $i++) - { - $retval[$i] = new stdClass(); - $retval[$i]->name = $query[$i]->Field; - - sscanf($query[$i]->Type, '%[a-z](%d)', - $retval[$i]->type, - $retval[$i]->max_length - ); - - $retval[$i]->default = $query[$i]->Default; - $retval[$i]->primary_key = (int) ($query[$i]->Key === 'PRI'); - } - - return $retval; - } - - // -------------------------------------------------------------------- - - /** - * Error - * - * Returns an array containing code and message of the last - * database error that has occured. - * - * @return array - */ - public function error() - { - return array('code' => cubrid_errno($this->conn_id), 'message' => cubrid_error($this->conn_id)); - } - - // -------------------------------------------------------------------- - - /** - * FROM tables - * - * Groups tables in FROM clauses if needed, so there is no confusion - * about operator precedence. - * - * @return string - */ - protected function _from_tables() - { - if ( ! empty($this->qb_join) && count($this->qb_from) > 1) - { - return '('.implode(', ', $this->qb_from).')'; - } - - return implode(', ', $this->qb_from); - } - - // -------------------------------------------------------------------- - - /** - * Close DB Connection - * - * @return void - */ - protected function _close() - { - cubrid_close($this->conn_id); - } - -} diff --git a/src/Database/drivers/cubrid/cubrid_forge.php b/src/Database/drivers/cubrid/cubrid_forge.php deleted file mode 100644 index 96cf3e6..0000000 --- a/src/Database/drivers/cubrid/cubrid_forge.php +++ /dev/null @@ -1,228 +0,0 @@ - 'INTEGER', - 'SMALLINT' => 'INTEGER', - 'INT' => 'BIGINT', - 'INTEGER' => 'BIGINT', - 'BIGINT' => 'NUMERIC', - 'FLOAT' => 'DOUBLE', - 'REAL' => 'DOUBLE' - ); - - // -------------------------------------------------------------------- - - /** - * ALTER TABLE - * - * @param string $alter_type ALTER type - * @param string $table Table name - * @param mixed $field Column definition - * @return string|string[] - */ - protected function _alter_table($alter_type, $table, $field) - { - if (in_array($alter_type, array('DROP', 'ADD'), TRUE)) - { - return parent::_alter_table($alter_type, $table, $field); - } - - $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table); - $sqls = array(); - for ($i = 0, $c = count($field); $i < $c; $i++) - { - if ($field[$i]['_literal'] !== FALSE) - { - $sqls[] = $sql.' CHANGE '.$field[$i]['_literal']; - } - else - { - $alter_type = empty($field[$i]['new_name']) ? ' MODIFY ' : ' CHANGE '; - $sqls[] = $sql.$alter_type.$this->_process_column($field[$i]); - } - } - - return $sqls; - } - - // -------------------------------------------------------------------- - - /** - * Process column - * - * @param array $field - * @return string - */ - protected function _process_column($field) - { - $extra_clause = isset($field['after']) - ? ' AFTER '.$this->db->escape_identifiers($field['after']) : ''; - - if (empty($extra_clause) && isset($field['first']) && $field['first'] === TRUE) - { - $extra_clause = ' FIRST'; - } - - return $this->db->escape_identifiers($field['name']) - .(empty($field['new_name']) ? '' : ' '.$this->db->escape_identifiers($field['new_name'])) - .' '.$field['type'].$field['length'] - .$field['unsigned'] - .$field['null'] - .$field['default'] - .$field['auto_increment'] - .$field['unique'] - .$extra_clause; - } - - // -------------------------------------------------------------------- - - /** - * Field attribute TYPE - * - * Performs a data type mapping between different databases. - * - * @param array &$attributes - * @return void - */ - protected function _attr_type(&$attributes) - { - switch (strtoupper($attributes['TYPE'])) - { - case 'TINYINT': - $attributes['TYPE'] = 'SMALLINT'; - $attributes['UNSIGNED'] = FALSE; - return; - case 'MEDIUMINT': - $attributes['TYPE'] = 'INTEGER'; - $attributes['UNSIGNED'] = FALSE; - return; - default: return; - } - } - - // -------------------------------------------------------------------- - - /** - * Process indexes - * - * @param string $table (ignored) - * @return string - */ - protected function _process_indexes($table) - { - $sql = ''; - - for ($i = 0, $c = count($this->keys); $i < $c; $i++) - { - if (is_array($this->keys[$i])) - { - for ($i2 = 0, $c2 = count($this->keys[$i]); $i2 < $c2; $i2++) - { - if ( ! isset($this->fields[$this->keys[$i][$i2]])) - { - unset($this->keys[$i][$i2]); - continue; - } - } - } - elseif ( ! isset($this->fields[$this->keys[$i]])) - { - unset($this->keys[$i]); - continue; - } - - is_array($this->keys[$i]) OR $this->keys[$i] = array($this->keys[$i]); - - $sql .= ",\n\tKEY ".$this->db->escape_identifiers(implode('_', $this->keys[$i])) - .' ('.implode(', ', $this->db->escape_identifiers($this->keys[$i])).')'; - } - - $this->keys = array(); - - return $sql; - } - -} diff --git a/src/Database/drivers/cubrid/cubrid_result.php b/src/Database/drivers/cubrid/cubrid_result.php deleted file mode 100644 index 9ec1b2b..0000000 --- a/src/Database/drivers/cubrid/cubrid_result.php +++ /dev/null @@ -1,178 +0,0 @@ -num_rows) - ? $this->num_rows - : $this->num_rows = cubrid_num_rows($this->result_id); - } - - // -------------------------------------------------------------------- - - /** - * Number of fields in the result set - * - * @return int - */ - public function num_fields() - { - return cubrid_num_fields($this->result_id); - } - - // -------------------------------------------------------------------- - - /** - * Fetch Field Names - * - * Generates an array of column names - * - * @return array - */ - public function list_fields() - { - return cubrid_column_names($this->result_id); - } - - // -------------------------------------------------------------------- - - /** - * Field data - * - * Generates an array of objects containing field meta-data - * - * @return array - */ - public function field_data() - { - $retval = array(); - - for ($i = 0, $c = $this->num_fields(); $i < $c; $i++) - { - $retval[$i] = new stdClass(); - $retval[$i]->name = cubrid_field_name($this->result_id, $i); - $retval[$i]->type = cubrid_field_type($this->result_id, $i); - $retval[$i]->max_length = cubrid_field_len($this->result_id, $i); - $retval[$i]->primary_key = (int) (strpos(cubrid_field_flags($this->result_id, $i), 'primary_key') !== FALSE); - } - - return $retval; - } - - // -------------------------------------------------------------------- - - /** - * Free the result - * - * @return void - */ - public function free_result() - { - if (is_resource($this->result_id) OR - (get_resource_type($this->result_id) === 'Unknown' && preg_match('/Resource id #/', strval($this->result_id)))) - { - cubrid_close_request($this->result_id); - $this->result_id = FALSE; - } - } - - // -------------------------------------------------------------------- - - /** - * Data Seek - * - * Moves the internal pointer to the desired offset. We call - * this internally before fetching results to make sure the - * result set starts at zero. - * - * @param int $n - * @return bool - */ - public function data_seek($n = 0) - { - return cubrid_data_seek($this->result_id, $n); - } - - // -------------------------------------------------------------------- - - /** - * Result - associative array - * - * Returns the result set as an array - * - * @return array - */ - protected function _fetch_assoc() - { - return cubrid_fetch_assoc($this->result_id); - } - - // -------------------------------------------------------------------- - - /** - * Result - object - * - * Returns the result set as an object - * - * @param string $class_name - * @return object - */ - protected function _fetch_object($class_name = 'stdClass') - { - return cubrid_fetch_object($this->result_id, $class_name); - } - -} diff --git a/src/Database/drivers/cubrid/cubrid_utility.php b/src/Database/drivers/cubrid/cubrid_utility.php deleted file mode 100644 index 7d4a879..0000000 --- a/src/Database/drivers/cubrid/cubrid_utility.php +++ /dev/null @@ -1,80 +0,0 @@ -db->data_cache['db_names'])) - { - return $this->db->data_cache['db_names']; - } - - return $this->db->data_cache['db_names'] = cubrid_list_dbs($this->db->conn_id); - } - - // -------------------------------------------------------------------- - - /** - * CUBRID Export - * - * @param array Preferences - * @return mixed - */ - protected function _backup($params = array()) - { - // No SQL based support in CUBRID as of version 8.4.0. Database or - // table backup can be performed using CUBRID Manager - // database administration tool. - return $this->db->display_error('db_unsupported_feature'); - } -} diff --git a/src/Database/drivers/ibase/ibase_driver.php b/src/Database/drivers/ibase/ibase_driver.php deleted file mode 100644 index 6438fdd..0000000 --- a/src/Database/drivers/ibase/ibase_driver.php +++ /dev/null @@ -1,396 +0,0 @@ -hostname.':'.$this->database, $this->username, $this->password, $this->char_set) - : ibase_connect($this->hostname.':'.$this->database, $this->username, $this->password, $this->char_set); - } - - // -------------------------------------------------------------------- - - /** - * Database version number - * - * @return string - */ - public function version() - { - if (isset($this->data_cache['version'])) - { - return $this->data_cache['version']; - } - - if (($service = ibase_service_attach($this->hostname, $this->username, $this->password))) - { - $this->data_cache['version'] = ibase_server_info($service, IBASE_SVC_SERVER_VERSION); - - // Don't keep the service open - ibase_service_detach($service); - return $this->data_cache['version']; - } - - return FALSE; - } - - // -------------------------------------------------------------------- - - /** - * Execute the query - * - * @param string $sql an SQL query - * @return resource - */ - protected function _execute($sql) - { - return ibase_query(isset($this->_ibase_trans) ? $this->_ibase_trans : $this->conn_id, $sql); - } - - // -------------------------------------------------------------------- - - /** - * Begin Transaction - * - * @return bool - */ - protected function _trans_begin() - { - if (($trans_handle = ibase_trans($this->conn_id)) === FALSE) - { - return FALSE; - } - - $this->_ibase_trans = $trans_handle; - return TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Commit Transaction - * - * @return bool - */ - protected function _trans_commit() - { - if (ibase_commit($this->_ibase_trans)) - { - $this->_ibase_trans = NULL; - return TRUE; - } - - return FALSE; - } - - // -------------------------------------------------------------------- - - /** - * Rollback Transaction - * - * @return bool - */ - protected function _trans_rollback() - { - if (ibase_rollback($this->_ibase_trans)) - { - $this->_ibase_trans = NULL; - return TRUE; - } - - return FALSE; - } - - // -------------------------------------------------------------------- - - /** - * Affected Rows - * - * @return int - */ - public function affected_rows() - { - return ibase_affected_rows($this->conn_id); - } - - // -------------------------------------------------------------------- - - /** - * Insert ID - * - * @param string $generator_name - * @param int $inc_by - * @return int - */ - public function insert_id($generator_name, $inc_by = 0) - { - //If a generator hasn't been used before it will return 0 - return ibase_gen_id('"'.$generator_name.'"', $inc_by); - } - - // -------------------------------------------------------------------- - - /** - * List table query - * - * Generates a platform-specific query string so that the table names can be fetched - * - * @param bool $prefix_limit - * @return string - */ - protected function _list_tables($prefix_limit = FALSE) - { - $sql = 'SELECT TRIM("RDB$RELATION_NAME") AS TABLE_NAME FROM "RDB$RELATIONS" WHERE "RDB$RELATION_NAME" NOT LIKE \'RDB$%\' AND "RDB$RELATION_NAME" NOT LIKE \'MON$%\''; - - if ($prefix_limit !== FALSE && $this->dbprefix !== '') - { - return $sql.' AND TRIM("RDB$RELATION_NAME") AS TABLE_NAME LIKE \''.$this->escape_like_str($this->dbprefix)."%' " - .sprintf($this->_like_escape_str, $this->_like_escape_chr); - } - - return $sql; - } - - // -------------------------------------------------------------------- - - /** - * Show column query - * - * Generates a platform-specific query string so that the column names can be fetched - * - * @param string $table - * @return string - */ - protected function _list_columns($table = '') - { - return 'SELECT TRIM("RDB$FIELD_NAME") AS COLUMN_NAME FROM "RDB$RELATION_FIELDS" WHERE "RDB$RELATION_NAME" = '.$this->escape($table); - } - - // -------------------------------------------------------------------- - - /** - * Returns an object with field data - * - * @param string $table - * @return array - */ - public function field_data($table) - { - $sql = 'SELECT "rfields"."RDB$FIELD_NAME" AS "name", - CASE "fields"."RDB$FIELD_TYPE" - WHEN 7 THEN \'SMALLINT\' - WHEN 8 THEN \'INTEGER\' - WHEN 9 THEN \'QUAD\' - WHEN 10 THEN \'FLOAT\' - WHEN 11 THEN \'DFLOAT\' - WHEN 12 THEN \'DATE\' - WHEN 13 THEN \'TIME\' - WHEN 14 THEN \'CHAR\' - WHEN 16 THEN \'INT64\' - WHEN 27 THEN \'DOUBLE\' - WHEN 35 THEN \'TIMESTAMP\' - WHEN 37 THEN \'VARCHAR\' - WHEN 40 THEN \'CSTRING\' - WHEN 261 THEN \'BLOB\' - ELSE NULL - END AS "type", - "fields"."RDB$FIELD_LENGTH" AS "max_length", - "rfields"."RDB$DEFAULT_VALUE" AS "default" - FROM "RDB$RELATION_FIELDS" "rfields" - JOIN "RDB$FIELDS" "fields" ON "rfields"."RDB$FIELD_SOURCE" = "fields"."RDB$FIELD_NAME" - WHERE "rfields"."RDB$RELATION_NAME" = '.$this->escape($table).' - ORDER BY "rfields"."RDB$FIELD_POSITION"'; - - return (($query = $this->query($sql)) !== FALSE) - ? $query->result_object() - : FALSE; - } - - // -------------------------------------------------------------------- - - /** - * Error - * - * Returns an array containing code and message of the last - * database error that has occured. - * - * @return array - */ - public function error() - { - return array('code' => ibase_errcode(), 'message' => ibase_errmsg()); - } - - // -------------------------------------------------------------------- - - /** - * Update statement - * - * Generates a platform-specific update string from the supplied data - * - * @param string $table - * @param array $values - * @return string - */ - protected function _update($table, $values) - { - $this->qb_limit = FALSE; - return parent::_update($table, $values); - } - - // -------------------------------------------------------------------- - - /** - * Truncate statement - * - * Generates a platform-specific truncate string from the supplied data - * - * If the database does not support the TRUNCATE statement, - * then this method maps to 'DELETE FROM table' - * - * @param string $table - * @return string - */ - protected function _truncate($table) - { - return 'DELETE FROM '.$table; - } - - // -------------------------------------------------------------------- - - /** - * Delete statement - * - * Generates a platform-specific delete string from the supplied data - * - * @param string $table - * @return string - */ - protected function _delete($table) - { - $this->qb_limit = FALSE; - return parent::_delete($table); - } - - // -------------------------------------------------------------------- - - /** - * LIMIT - * - * Generates a platform-specific LIMIT clause - * - * @param string $sql SQL Query - * @return string - */ - protected function _limit($sql) - { - // Limit clause depends on if Interbase or Firebird - if (stripos($this->version(), 'firebird') !== FALSE) - { - $select = 'FIRST '.$this->qb_limit - .($this->qb_offset ? ' SKIP '.$this->qb_offset : ''); - } - else - { - $select = 'ROWS ' - .($this->qb_offset ? $this->qb_offset.' TO '.($this->qb_limit + $this->qb_offset) : $this->qb_limit); - } - - return preg_replace('`SELECT`i', 'SELECT '.$select, $sql, 1); - } - - // -------------------------------------------------------------------- - - /** - * Close DB Connection - * - * @return void - */ - protected function _close() - { - ibase_close($this->conn_id); - } - -} diff --git a/src/Database/drivers/ibase/ibase_forge.php b/src/Database/drivers/ibase/ibase_forge.php deleted file mode 100644 index 93ab0c1..0000000 --- a/src/Database/drivers/ibase/ibase_forge.php +++ /dev/null @@ -1,252 +0,0 @@ - 'INTEGER', - 'INTEGER' => 'INT64', - 'FLOAT' => 'DOUBLE PRECISION' - ); - - /** - * NULL value representation in CREATE/ALTER TABLE statements - * - * @var string - */ - protected $_null = 'NULL'; - - // -------------------------------------------------------------------- - - /** - * Create database - * - * @param string $db_name - * @return string - */ - public function create_database($db_name) - { - // Firebird databases are flat files, so a path is required - - // Hostname is needed for remote access - empty($this->db->hostname) OR $db_name = $this->hostname.':'.$db_name; - - return parent::create_database('"'.$db_name.'"'); - } - - // -------------------------------------------------------------------- - - /** - * Drop database - * - * @param string $db_name (ignored) - * @return bool - */ - public function drop_database($db_name = '') - { - if ( ! ibase_drop_db($this->conn_id)) - { - return ($this->db->db_debug) ? $this->db->display_error('db_unable_to_drop') : FALSE; - } - elseif ( ! empty($this->db->data_cache['db_names'])) - { - $key = array_search(strtolower($this->db->database), array_map('strtolower', $this->db->data_cache['db_names']), TRUE); - if ($key !== FALSE) - { - unset($this->db->data_cache['db_names'][$key]); - } - } - - return TRUE; - } - - // -------------------------------------------------------------------- - - /** - * ALTER TABLE - * - * @param string $alter_type ALTER type - * @param string $table Table name - * @param mixed $field Column definition - * @return string|string[] - */ - protected function _alter_table($alter_type, $table, $field) - { - if (in_array($alter_type, array('DROP', 'ADD'), TRUE)) - { - return parent::_alter_table($alter_type, $table, $field); - } - - $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table); - $sqls = array(); - for ($i = 0, $c = count($field); $i < $c; $i++) - { - if ($field[$i]['_literal'] !== FALSE) - { - return FALSE; - } - - if (isset($field[$i]['type'])) - { - $sqls[] = $sql.' ALTER COLUMN '.$this->db->escape_identififers($field[$i]['name']) - .' TYPE '.$field[$i]['type'].$field[$i]['length']; - } - - if ( ! empty($field[$i]['default'])) - { - $sqls[] = $sql.' ALTER COLUMN '.$this->db->escape_identifiers($field[$i]['name']) - .' SET DEFAULT '.$field[$i]['default']; - } - - if (isset($field[$i]['null'])) - { - $sqls[] = 'UPDATE "RDB$RELATION_FIELDS" SET "RDB$NULL_FLAG" = ' - .($field[$i]['null'] === TRUE ? 'NULL' : '1') - .' WHERE "RDB$FIELD_NAME" = '.$this->db->escape($field[$i]['name']) - .' AND "RDB$RELATION_NAME" = '.$this->db->escape($table); - } - - if ( ! empty($field[$i]['new_name'])) - { - $sqls[] = $sql.' ALTER COLUMN '.$this->db->escape_identifiers($field[$i]['name']) - .' TO '.$this->db->escape_identifiers($field[$i]['new_name']); - } - } - - return $sqls; - } - - // -------------------------------------------------------------------- - - /** - * Process column - * - * @param array $field - * @return string - */ - protected function _process_column($field) - { - return $this->db->escape_identifiers($field['name']) - .' '.$field['type'].$field['length'] - .$field['null'] - .$field['unique'] - .$field['default']; - } - - // -------------------------------------------------------------------- - - /** - * Field attribute TYPE - * - * Performs a data type mapping between different databases. - * - * @param array &$attributes - * @return void - */ - protected function _attr_type(&$attributes) - { - switch (strtoupper($attributes['TYPE'])) - { - case 'TINYINT': - $attributes['TYPE'] = 'SMALLINT'; - $attributes['UNSIGNED'] = FALSE; - return; - case 'MEDIUMINT': - $attributes['TYPE'] = 'INTEGER'; - $attributes['UNSIGNED'] = FALSE; - return; - case 'INT': - $attributes['TYPE'] = 'INTEGER'; - return; - case 'BIGINT': - $attributes['TYPE'] = 'INT64'; - return; - default: return; - } - } - - // -------------------------------------------------------------------- - - /** - * Field attribute AUTO_INCREMENT - * - * @param array &$attributes - * @param array &$field - * @return void - */ - protected function _attr_auto_increment(&$attributes, &$field) - { - // Not supported - } - -} diff --git a/src/Database/drivers/ibase/ibase_result.php b/src/Database/drivers/ibase/ibase_result.php deleted file mode 100644 index 4038912..0000000 --- a/src/Database/drivers/ibase/ibase_result.php +++ /dev/null @@ -1,162 +0,0 @@ -result_id); - } - - // -------------------------------------------------------------------- - - /** - * Fetch Field Names - * - * Generates an array of column names - * - * @return array - */ - public function list_fields() - { - $field_names = array(); - for ($i = 0, $num_fields = $this->num_fields(); $i < $num_fields; $i++) - { - $info = ibase_field_info($this->result_id, $i); - $field_names[] = $info['name']; - } - - return $field_names; - } - - // -------------------------------------------------------------------- - - /** - * Field data - * - * Generates an array of objects containing field meta-data - * - * @return array - */ - public function field_data() - { - $retval = array(); - for ($i = 0, $c = $this->num_fields(); $i < $c; $i++) - { - $info = ibase_field_info($this->result_id, $i); - - $retval[$i] = new stdClass(); - $retval[$i]->name = $info['name']; - $retval[$i]->type = $info['type']; - $retval[$i]->max_length = $info['length']; - } - - return $retval; - } - - // -------------------------------------------------------------------- - - /** - * Free the result - * - * @return void - */ - public function free_result() - { - ibase_free_result($this->result_id); - } - - // -------------------------------------------------------------------- - - /** - * Result - associative array - * - * Returns the result set as an array - * - * @return array - */ - protected function _fetch_assoc() - { - return ibase_fetch_assoc($this->result_id, IBASE_FETCH_BLOBS); - } - - // -------------------------------------------------------------------- - - /** - * Result - object - * - * Returns the result set as an object - * - * @param string $class_name - * @return object - */ - protected function _fetch_object($class_name = 'stdClass') - { - $row = ibase_fetch_object($this->result_id, IBASE_FETCH_BLOBS); - - if ($class_name === 'stdClass' OR ! $row) - { - return $row; - } - - $class_name = new $class_name(); - foreach ($row as $key => $value) - { - $class_name->$key = $value; - } - - return $class_name; - } - -} diff --git a/src/Database/drivers/ibase/ibase_utility.php b/src/Database/drivers/ibase/ibase_utility.php deleted file mode 100644 index 3789e7e..0000000 --- a/src/Database/drivers/ibase/ibase_utility.php +++ /dev/null @@ -1,70 +0,0 @@ -db->hostname, $this->db->username, $this->db->password)) - { - $res = ibase_backup($service, $this->db->database, $filename.'.fbk'); - - // Close the service connection - ibase_service_detach($service); - return $res; - } - - return FALSE; - } - -} diff --git a/src/Database/drivers/mysqli/mysqli_driver.php b/src/Database/drivers/mysqli/mysqli_driver.php deleted file mode 100644 index 737361c..0000000 --- a/src/Database/drivers/mysqli/mysqli_driver.php +++ /dev/null @@ -1,547 +0,0 @@ -hostname[0] === '/') - { - $hostname = NULL; - $port = NULL; - $socket = $this->hostname; - } - else - { - // Persistent connection support was added in PHP 5.3.0 - $hostname = ($persistent === TRUE && Core::isPHP('5.3')) - ? 'p:'.$this->hostname : $this->hostname; - $port = empty($this->port) ? NULL : $this->port; - $socket = NULL; - } - - $client_flags = ($this->compress === TRUE) ? MYSQLI_CLIENT_COMPRESS : 0; - $this->_mysqli = mysqli_init(); - - $this->_mysqli->options(MYSQLI_OPT_CONNECT_TIMEOUT, 10); - - if (isset($this->stricton)) - { - if ($this->stricton) - { - $this->_mysqli->options(MYSQLI_INIT_COMMAND, 'SET SESSION sql_mode = CONCAT(@@sql_mode, ",", "STRICT_ALL_TABLES")'); - } - else - { - $this->_mysqli->options(MYSQLI_INIT_COMMAND, - 'SET SESSION sql_mode = - REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( - @@sql_mode, - "STRICT_ALL_TABLES,", ""), - ",STRICT_ALL_TABLES", ""), - "STRICT_ALL_TABLES", ""), - "STRICT_TRANS_TABLES,", ""), - ",STRICT_TRANS_TABLES", ""), - "STRICT_TRANS_TABLES", "")' - ); - } - } - - if (is_array($this->encrypt)) - { - $ssl = array(); - empty($this->encrypt['ssl_key']) OR $ssl['key'] = $this->encrypt['ssl_key']; - empty($this->encrypt['ssl_cert']) OR $ssl['cert'] = $this->encrypt['ssl_cert']; - empty($this->encrypt['ssl_ca']) OR $ssl['ca'] = $this->encrypt['ssl_ca']; - empty($this->encrypt['ssl_capath']) OR $ssl['capath'] = $this->encrypt['ssl_capath']; - empty($this->encrypt['ssl_cipher']) OR $ssl['cipher'] = $this->encrypt['ssl_cipher']; - - if ( ! empty($ssl)) - { - if (isset($this->encrypt['ssl_verify'])) - { - if ($this->encrypt['ssl_verify']) - { - defined('MYSQLI_OPT_SSL_VERIFY_SERVER_CERT') && $this->_mysqli->options(MYSQLI_OPT_SSL_VERIFY_SERVER_CERT, TRUE); - } - // Apparently (when it exists), setting MYSQLI_OPT_SSL_VERIFY_SERVER_CERT - // to FALSE didn't do anything, so PHP 5.6.16 introduced yet another - // constant ... - // - // https://secure.php.net/ChangeLog-5.php#5.6.16 - // https://bugs.php.net/bug.php?id=68344 - elseif (defined('MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT')) - { - $this->_mysqli->options(MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT, TRUE); - } - } - - $client_flags |= MYSQLI_CLIENT_SSL; - $this->_mysqli->ssl_set( - isset($ssl['key']) ? $ssl['key'] : NULL, - isset($ssl['cert']) ? $ssl['cert'] : NULL, - isset($ssl['ca']) ? $ssl['ca'] : NULL, - isset($ssl['capath']) ? $ssl['capath'] : NULL, - isset($ssl['cipher']) ? $ssl['cipher'] : NULL - ); - } - } - - if ($this->_mysqli->real_connect($hostname, $this->username, $this->password, $this->database, $port, $socket, $client_flags)) - { - // Prior to version 5.7.3, MySQL silently downgrades to an unencrypted connection if SSL setup fails - if ( - ($client_flags & MYSQLI_CLIENT_SSL) - && version_compare($this->_mysqli->client_info, '5.7.3', '<=') - && empty($this->_mysqli->query("SHOW STATUS LIKE 'ssl_cipher'")->fetch_object()->Value) - ) - { - $this->_mysqli->close(); - $message = 'MySQLi was configured for an SSL connection, but got an unencrypted connection instead!'; - Logger::logError($message); - return ($this->db->db_debug) ? $this->db->display_error($message, '', TRUE) : FALSE; - } - - return $this->_mysqli; - } - - return FALSE; - } - - // -------------------------------------------------------------------- - - /** - * Reconnect - * - * Keep / reestablish the db connection if no queries have been - * sent for a length of time exceeding the server's idle timeout - * - * @return void - */ - public function reconnect() - { - if ($this->conn_id !== FALSE && $this->conn_id->ping() === FALSE) - { - $this->conn_id = FALSE; - } - } - - // -------------------------------------------------------------------- - - /** - * Select the database - * - * @param string $database - * @return bool - */ - public function db_select($database = '') - { - if ($database === '') - { - $database = $this->database; - } - - if ($this->conn_id->select_db($database)) - { - $this->database = $database; - return TRUE; - } - - return FALSE; - } - - // -------------------------------------------------------------------- - - /** - * Set client character set - * - * @param string $charset - * @return bool - */ - protected function _db_set_charset($charset) - { - return $this->conn_id->set_charset($charset); - } - - // -------------------------------------------------------------------- - - /** - * Database version number - * - * @return string - */ - public function version() - { - if (isset($this->data_cache['version'])) - { - return $this->data_cache['version']; - } - - return $this->data_cache['version'] = $this->conn_id->server_info; - } - - // -------------------------------------------------------------------- - - /** - * Execute the query - * - * @param string $sql an SQL query - * @return mixed - */ - protected function _execute($sql) - { - return $this->conn_id->query($this->_prep_query($sql)); - } - - // -------------------------------------------------------------------- - - /** - * Prep the query - * - * If needed, each database adapter can prep the query string - * - * @param string $sql an SQL query - * @return string - */ - protected function _prep_query($sql) - { - // mysqli_affected_rows() returns 0 for "DELETE FROM TABLE" queries. This hack - // modifies the query so that it a proper number of affected rows is returned. - if ($this->delete_hack === TRUE && preg_match('/^\s*DELETE\s+FROM\s+(\S+)\s*$/i', $sql)) - { - return trim($sql).' WHERE 1=1'; - } - - return $sql; - } - - // -------------------------------------------------------------------- - - /** - * Begin Transaction - * - * @return bool - */ - protected function _trans_begin() - { - $this->conn_id->autocommit(FALSE); - return Core::isPHP('5.5') - ? $this->conn_id->begin_transaction() - : $this->simple_query('START TRANSACTION'); // can also be BEGIN or BEGIN WORK - } - - // -------------------------------------------------------------------- - - /** - * Commit Transaction - * - * @return bool - */ - protected function _trans_commit() - { - if ($this->conn_id->commit()) - { - $this->conn_id->autocommit(TRUE); - return TRUE; - } - - return FALSE; - } - - // -------------------------------------------------------------------- - - /** - * Rollback Transaction - * - * @return bool - */ - protected function _trans_rollback() - { - if ($this->conn_id->rollback()) - { - $this->conn_id->autocommit(TRUE); - return TRUE; - } - - return FALSE; - } - - // -------------------------------------------------------------------- - - /** - * Platform-dependant string escape - * - * @param string - * @return string - */ - protected function _escape_str($str) - { - return $this->conn_id->real_escape_string($str); - } - - // -------------------------------------------------------------------- - - /** - * Affected Rows - * - * @return int - */ - public function affected_rows() - { - return $this->conn_id->affected_rows; - } - - // -------------------------------------------------------------------- - - /** - * Insert ID - * - * @return int - */ - public function insert_id() - { - return $this->conn_id->insert_id; - } - - // -------------------------------------------------------------------- - - /** - * List table query - * - * Generates a platform-specific query string so that the table names can be fetched - * - * @param bool $prefix_limit - * @return string - */ - protected function _list_tables($prefix_limit = FALSE) - { - $sql = 'SHOW TABLES FROM '.$this->escape_identifiers($this->database); - - if ($prefix_limit !== FALSE && $this->dbprefix !== '') - { - return $sql." LIKE '".$this->escape_like_str($this->dbprefix)."%'"; - } - - return $sql; - } - - // -------------------------------------------------------------------- - - /** - * Show column query - * - * Generates a platform-specific query string so that the column names can be fetched - * - * @param string $table - * @return string - */ - protected function _list_columns($table = '') - { - return 'SHOW COLUMNS FROM '.$this->protect_identifiers($table, TRUE, NULL, FALSE); - } - - // -------------------------------------------------------------------- - - /** - * Returns an object with field data - * - * @param string $table - * @return array - */ - public function field_data($table) - { - if (($query = $this->query('SHOW COLUMNS FROM '.$this->protect_identifiers($table, TRUE, NULL, FALSE))) === FALSE) - { - return FALSE; - } - $query = $query->result_object(); - - $retval = array(); - for ($i = 0, $c = count($query); $i < $c; $i++) - { - $retval[$i] = new stdClass(); - $retval[$i]->name = $query[$i]->Field; - - sscanf($query[$i]->Type, '%[a-z](%d)', - $retval[$i]->type, - $retval[$i]->max_length - ); - - $retval[$i]->default = $query[$i]->Default; - $retval[$i]->primary_key = (int) ($query[$i]->Key === 'PRI'); - } - - return $retval; - } - - // -------------------------------------------------------------------- - - /** - * Error - * - * Returns an array containing code and message of the last - * database error that has occurred. - * - * @return array - */ - public function error() - { - if ( ! empty($this->_mysqli->connect_errno)) - { - return array( - 'code' => $this->_mysqli->connect_errno, - 'message' => Core::isPHP('5.2.9') ? $this->_mysqli->connect_error : mysqli_connect_error() - ); - } - - return array('code' => $this->conn_id->errno, 'message' => $this->conn_id->error); - } - - // -------------------------------------------------------------------- - - /** - * FROM tables - * - * Groups tables in FROM clauses if needed, so there is no confusion - * about operator precedence. - * - * @return string - */ - protected function _from_tables() - { - if ( ! empty($this->qb_join) && count($this->qb_from) > 1) - { - return '('.implode(', ', $this->qb_from).')'; - } - - return implode(', ', $this->qb_from); - } - - // -------------------------------------------------------------------- - - /** - * Close DB Connection - * - * @return void - */ - protected function _close() - { - $this->conn_id->close(); - } - -} diff --git a/src/Database/drivers/mysqli/mysqli_forge.php b/src/Database/drivers/mysqli/mysqli_forge.php deleted file mode 100644 index 5e6f055..0000000 --- a/src/Database/drivers/mysqli/mysqli_forge.php +++ /dev/null @@ -1,244 +0,0 @@ -db->char_set) && ! strpos($sql, 'CHARACTER SET') && ! strpos($sql, 'CHARSET')) - { - $sql .= ' DEFAULT CHARACTER SET = '.$this->db->char_set; - } - - if ( ! empty($this->db->dbcollat) && ! strpos($sql, 'COLLATE')) - { - $sql .= ' COLLATE = '.$this->db->dbcollat; - } - - return $sql; - } - - // -------------------------------------------------------------------- - - /** - * ALTER TABLE - * - * @param string $alter_type ALTER type - * @param string $table Table name - * @param mixed $field Column definition - * @return string|string[] - */ - protected function _alter_table($alter_type, $table, $field) - { - if ($alter_type === 'DROP') - { - return parent::_alter_table($alter_type, $table, $field); - } - - $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table); - for ($i = 0, $c = count($field); $i < $c; $i++) - { - if ($field[$i]['_literal'] !== FALSE) - { - $field[$i] = ($alter_type === 'ADD') - ? "\n\tADD ".$field[$i]['_literal'] - : "\n\tMODIFY ".$field[$i]['_literal']; - } - else - { - if ($alter_type === 'ADD') - { - $field[$i]['_literal'] = "\n\tADD "; - } - else - { - $field[$i]['_literal'] = empty($field[$i]['new_name']) ? "\n\tMODIFY " : "\n\tCHANGE "; - } - - $field[$i] = $field[$i]['_literal'].$this->_process_column($field[$i]); - } - } - - return array($sql.implode(',', $field)); - } - - // -------------------------------------------------------------------- - - /** - * Process column - * - * @param array $field - * @return string - */ - protected function _process_column($field) - { - $extra_clause = isset($field['after']) - ? ' AFTER '.$this->db->escape_identifiers($field['after']) : ''; - - if (empty($extra_clause) && isset($field['first']) && $field['first'] === TRUE) - { - $extra_clause = ' FIRST'; - } - - return $this->db->escape_identifiers($field['name']) - .(empty($field['new_name']) ? '' : ' '.$this->db->escape_identifiers($field['new_name'])) - .' '.$field['type'].$field['length'] - .$field['unsigned'] - .$field['null'] - .$field['default'] - .$field['auto_increment'] - .$field['unique'] - .(empty($field['comment']) ? '' : ' COMMENT '.$field['comment']) - .$extra_clause; - } - - // -------------------------------------------------------------------- - - /** - * Process indexes - * - * @param string $table (ignored) - * @return string - */ - protected function _process_indexes($table) - { - $sql = ''; - - for ($i = 0, $c = count($this->keys); $i < $c; $i++) - { - if (is_array($this->keys[$i])) - { - for ($i2 = 0, $c2 = count($this->keys[$i]); $i2 < $c2; $i2++) - { - if ( ! isset($this->fields[$this->keys[$i][$i2]])) - { - unset($this->keys[$i][$i2]); - continue; - } - } - } - elseif ( ! isset($this->fields[$this->keys[$i]])) - { - unset($this->keys[$i]); - continue; - } - - is_array($this->keys[$i]) OR $this->keys[$i] = array($this->keys[$i]); - - $sql .= ",\n\tKEY ".$this->db->escape_identifiers(implode('_', $this->keys[$i])) - .' ('.implode(', ', $this->db->escape_identifiers($this->keys[$i])).')'; - } - - $this->keys = array(); - - return $sql; - } - -} diff --git a/src/Database/drivers/mysqli/mysqli_result.php b/src/Database/drivers/mysqli/mysqli_result.php deleted file mode 100644 index 721720d..0000000 --- a/src/Database/drivers/mysqli/mysqli_result.php +++ /dev/null @@ -1,186 +0,0 @@ -num_rows) - ? $this->num_rows - : $this->num_rows = $this->result_id->num_rows; - } - - // -------------------------------------------------------------------- - - /** - * Number of fields in the result set - * - * @return int - */ - public function num_fields() - { - return $this->result_id->field_count; - } - - // -------------------------------------------------------------------- - - /** - * Fetch Field Names - * - * Generates an array of column names - * - * @return array - */ - public function list_fields() - { - $field_names = array(); - $this->result_id->field_seek(0); - while ($field = $this->result_id->fetch_field()) - { - $field_names[] = $field->name; - } - - return $field_names; - } - - // -------------------------------------------------------------------- - - /** - * Field data - * - * Generates an array of objects containing field meta-data - * - * @return array - */ - public function field_data() - { - $retval = array(); - $field_data = $this->result_id->fetch_fields(); - for ($i = 0, $c = count($field_data); $i < $c; $i++) - { - $retval[$i] = new stdClass(); - $retval[$i]->name = $field_data[$i]->name; - $retval[$i]->type = $field_data[$i]->type; - $retval[$i]->max_length = $field_data[$i]->max_length; - $retval[$i]->primary_key = (int) ($field_data[$i]->flags & 2); - $retval[$i]->default = $field_data[$i]->def; - } - - return $retval; - } - - // -------------------------------------------------------------------- - - /** - * Free the result - * - * @return void - */ - public function free_result() - { - if (is_object($this->result_id)) - { - $this->result_id->free(); - $this->result_id = FALSE; - } - } - - // -------------------------------------------------------------------- - - /** - * Data Seek - * - * Moves the internal pointer to the desired offset. We call - * this internally before fetching results to make sure the - * result set starts at zero. - * - * @param int $n - * @return bool - */ - public function data_seek($n = 0) - { - return $this->result_id->data_seek($n); - } - - // -------------------------------------------------------------------- - - /** - * Result - associative array - * - * Returns the result set as an array - * - * @return array - */ - protected function _fetch_assoc() - { - return $this->result_id->fetch_assoc(); - } - - // -------------------------------------------------------------------- - - /** - * Result - object - * - * Returns the result set as an object - * - * @param string $class_name - * @return object - */ - protected function _fetch_object($class_name = 'stdClass') - { - return $this->result_id->fetch_object($class_name); - } - -} diff --git a/src/Database/drivers/mysqli/mysqli_utility.php b/src/Database/drivers/mysqli/mysqli_utility.php deleted file mode 100644 index 38c0b37..0000000 --- a/src/Database/drivers/mysqli/mysqli_utility.php +++ /dev/null @@ -1,213 +0,0 @@ -db->query('SHOW CREATE TABLE '.$this->db->escape_identifiers($this->db->database.'.'.$table)); - - // No result means the table name was invalid - if ($query === FALSE) - { - continue; - } - - // Write out the table schema - $output .= '#'.$newline.'# TABLE STRUCTURE FOR: '.$table.$newline.'#'.$newline.$newline; - - if ($add_drop === TRUE) - { - $output .= 'DROP TABLE IF EXISTS '.$this->db->protect_identifiers($table).';'.$newline.$newline; - } - - $i = 0; - $result = $query->result_array(); - foreach ($result[0] as $val) - { - if ($i++ % 2) - { - $output .= $val.';'.$newline.$newline; - } - } - - // If inserts are not needed we're done... - if ($add_insert === FALSE) - { - continue; - } - - // Grab all the data from the current table - $query = $this->db->query('SELECT * FROM '.$this->db->protect_identifiers($table)); - - if ($query->num_rows() === 0) - { - continue; - } - - // Fetch the field names and determine if the field is an - // integer type. We use this info to decide whether to - // surround the data with quotes or not - - $i = 0; - $field_str = ''; - $is_int = array(); - while ($field = $query->result_id->fetch_field()) - { - // Most versions of MySQL store timestamp as a string - $is_int[$i] = in_array(strtolower($field->type), - array('tinyint', 'smallint', 'mediumint', 'int', 'bigint'), //, 'timestamp'), - TRUE); - - // Create a string of field names - $field_str .= $this->db->escape_identifiers($field->name).', '; - $i++; - } - - // Trim off the end comma - $field_str = preg_replace('/, $/' , '', $field_str); - - // Build the insert string - foreach ($query->result_array() as $row) - { - $val_str = ''; - - $i = 0; - foreach ($row as $v) - { - // Is the value NULL? - if ($v === NULL) - { - $val_str .= 'NULL'; - } - else - { - // Escape the data if it's not an integer - $val_str .= ($is_int[$i] === FALSE) ? $this->db->escape($v) : $v; - } - - // Append a comma - $val_str .= ', '; - $i++; - } - - // Remove the comma at the end of the string - $val_str = preg_replace('/, $/' , '', $val_str); - - // Build the INSERT string - $output .= 'INSERT INTO '.$this->db->protect_identifiers($table).' ('.$field_str.') VALUES ('.$val_str.');'.$newline; - } - - $output .= $newline.$newline; - } - - // Do we need to include a statement to re-enable foreign key checks? - if ($foreign_key_checks === FALSE) - { - $output .= 'SET foreign_key_checks = 1;'.$newline; - } - - return $output; - } - -} diff --git a/src/Database/drivers/oci8/oci8_driver.php b/src/Database/drivers/oci8/oci8_driver.php deleted file mode 100644 index 7faeeac..0000000 --- a/src/Database/drivers/oci8/oci8_driver.php +++ /dev/null @@ -1,684 +0,0 @@ - '/^\(DESCRIPTION=(\(.+\)){2,}\)$/', // TNS - // Easy Connect string (Oracle 10g+) - 'ec' => '/^(\/\/)?[a-z0-9.:_-]+(:[1-9][0-9]{0,4})?(\/[a-z0-9$_]+)?(:[^\/])?(\/[a-z0-9$_]+)?$/i', - 'in' => '/^[a-z0-9$_]+$/i' // Instance name (defined in tnsnames.ora) - ); - - /* Space characters don't have any effect when actually - * connecting, but can be a hassle while validating the DSN. - */ - $this->dsn = str_replace(array("\n", "\r", "\t", ' '), '', $this->dsn); - - if ($this->dsn !== '') - { - foreach ($valid_dsns as $regexp) - { - if (preg_match($regexp, $this->dsn)) - { - return; - } - } - } - - // Legacy support for TNS in the hostname configuration field - $this->hostname = str_replace(array("\n", "\r", "\t", ' '), '', $this->hostname); - if (preg_match($valid_dsns['tns'], $this->hostname)) - { - $this->dsn = $this->hostname; - return; - } - elseif ($this->hostname !== '' && strpos($this->hostname, '/') === FALSE && strpos($this->hostname, ':') === FALSE - && (( ! empty($this->port) && ctype_digit($this->port)) OR $this->database !== '')) - { - /* If the hostname field isn't empty, doesn't contain - * ':' and/or '/' and if port and/or database aren't - * empty, then the hostname field is most likely indeed - * just a hostname. Therefore we'll try and build an - * Easy Connect string from these 3 settings, assuming - * that the database field is a service name. - */ - $this->dsn = $this->hostname - .(( ! empty($this->port) && ctype_digit($this->port)) ? ':'.$this->port : '') - .($this->database !== '' ? '/'.ltrim($this->database, '/') : ''); - - if (preg_match($valid_dsns['ec'], $this->dsn)) - { - return; - } - } - - /* At this point, we can only try and validate the hostname and - * database fields separately as DSNs. - */ - if (preg_match($valid_dsns['ec'], $this->hostname) OR preg_match($valid_dsns['in'], $this->hostname)) - { - $this->dsn = $this->hostname; - return; - } - - $this->database = str_replace(array("\n", "\r", "\t", ' '), '', $this->database); - foreach ($valid_dsns as $regexp) - { - if (preg_match($regexp, $this->database)) - { - return; - } - } - - /* Well - OK, an empty string should work as well. - * PHP will try to use environment variables to - * determine which Oracle instance to connect to. - */ - $this->dsn = ''; - } - - // -------------------------------------------------------------------- - - /** - * Non-persistent database connection - * - * @param bool $persistent - * @return resource - */ - public function db_connect($persistent = FALSE) - { - $func = ($persistent === TRUE) ? 'oci_pconnect' : 'oci_connect'; - return empty($this->char_set) - ? $func($this->username, $this->password, $this->dsn) - : $func($this->username, $this->password, $this->dsn, $this->char_set); - } - - // -------------------------------------------------------------------- - - /** - * Database version number - * - * @return string - */ - public function version() - { - if (isset($this->data_cache['version'])) - { - return $this->data_cache['version']; - } - - if ( ! $this->conn_id OR ($version_string = oci_server_version($this->conn_id)) === FALSE) - { - return FALSE; - } - elseif (preg_match('#Release\s(\d+(?:\.\d+)+)#', $version_string, $match)) - { - return $this->data_cache['version'] = $match[1]; - } - - return FALSE; - } - - // -------------------------------------------------------------------- - - /** - * Execute the query - * - * @param string $sql an SQL query - * @return resource - */ - protected function _execute($sql) - { - /* Oracle must parse the query before it is run. All of the actions with - * the query are based on the statement id returned by oci_parse(). - */ - if ($this->_reset_stmt_id === TRUE) - { - $this->stmt_id = oci_parse($this->conn_id, $sql); - } - - oci_set_prefetch($this->stmt_id, 1000); - return oci_execute($this->stmt_id, $this->commit_mode); - } - - // -------------------------------------------------------------------- - - /** - * Get cursor. Returns a cursor from the database - * - * @return resource - */ - public function get_cursor() - { - return $this->curs_id = oci_new_cursor($this->conn_id); - } - - // -------------------------------------------------------------------- - - /** - * Stored Procedure. Executes a stored procedure - * - * @param string package name in which the stored procedure is in - * @param string stored procedure name to execute - * @param array parameters - * @return mixed - * - * params array keys - * - * KEY OPTIONAL NOTES - * name no the name of the parameter should be in : format - * value no the value of the parameter. If this is an OUT or IN OUT parameter, - * this should be a reference to a variable - * type yes the type of the parameter - * length yes the max size of the parameter - */ - public function stored_procedure($package, $procedure, array $params) - { - if ($package === '' OR $procedure === '') - { - Logger::logError('Invalid query: '.$package.'.'.$procedure); - return ($this->db_debug) ? $this->display_error('db_invalid_query') : FALSE; - } - - // Build the query string - $sql = 'BEGIN '.$package.'.'.$procedure.'('; - - $have_cursor = FALSE; - foreach ($params as $param) - { - $sql .= $param['name'].','; - - if (isset($param['type']) && $param['type'] === OCI_B_CURSOR) - { - $have_cursor = TRUE; - } - } - $sql = trim($sql, ',').'); END;'; - - $this->_reset_stmt_id = FALSE; - $this->stmt_id = oci_parse($this->conn_id, $sql); - $this->_bind_params($params); - $result = $this->query($sql, FALSE, $have_cursor); - $this->_reset_stmt_id = TRUE; - return $result; - } - - // -------------------------------------------------------------------- - - /** - * Bind parameters - * - * @param array $params - * @return void - */ - protected function _bind_params($params) - { - if ( ! is_array($params) OR ! is_resource($this->stmt_id)) - { - return; - } - - foreach ($params as $param) - { - foreach (array('name', 'value', 'type', 'length') as $val) - { - if ( ! isset($param[$val])) - { - $param[$val] = ''; - } - } - - oci_bind_by_name($this->stmt_id, $param['name'], $param['value'], $param['length'], $param['type']); - } - } - - // -------------------------------------------------------------------- - - /** - * Begin Transaction - * - * @return bool - */ - protected function _trans_begin() - { - $this->commit_mode = Core::isPHP('5.3.2') ? OCI_NO_AUTO_COMMIT : OCI_DEFAULT; - return TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Commit Transaction - * - * @return bool - */ - protected function _trans_commit() - { - $this->commit_mode = OCI_COMMIT_ON_SUCCESS; - - return oci_commit($this->conn_id); - } - - // -------------------------------------------------------------------- - - /** - * Rollback Transaction - * - * @return bool - */ - protected function _trans_rollback() - { - $this->commit_mode = OCI_COMMIT_ON_SUCCESS; - return oci_rollback($this->conn_id); - } - - // -------------------------------------------------------------------- - - /** - * Affected Rows - * - * @return int - */ - public function affected_rows() - { - return oci_num_rows($this->stmt_id); - } - - // -------------------------------------------------------------------- - - /** - * Insert ID - * - * @return int - */ - public function insert_id() - { - // not supported in oracle - return $this->display_error('db_unsupported_function'); - } - - // -------------------------------------------------------------------- - - /** - * Show table query - * - * Generates a platform-specific query string so that the table names can be fetched - * - * @param bool $prefix_limit - * @return string - */ - protected function _list_tables($prefix_limit = FALSE) - { - $sql = 'SELECT "TABLE_NAME" FROM "ALL_TABLES"'; - - if ($prefix_limit !== FALSE && $this->dbprefix !== '') - { - return $sql.' WHERE "TABLE_NAME" LIKE \''.$this->escape_like_str($this->dbprefix)."%' " - .sprintf($this->_like_escape_str, $this->_like_escape_chr); - } - - return $sql; - } - - // -------------------------------------------------------------------- - - /** - * Show column query - * - * Generates a platform-specific query string so that the column names can be fetched - * - * @param string $table - * @return string - */ - protected function _list_columns($table = '') - { - if (strpos($table, '.') !== FALSE) - { - sscanf($table, '%[^.].%s', $owner, $table); - } - else - { - $owner = $this->username; - } - - return 'SELECT COLUMN_NAME FROM ALL_TAB_COLUMNS - WHERE UPPER(OWNER) = '.$this->escape(strtoupper($owner)).' - AND UPPER(TABLE_NAME) = '.$this->escape(strtoupper($table)); - } - - // -------------------------------------------------------------------- - - /** - * Returns an object with field data - * - * @param string $table - * @return array - */ - public function field_data($table) - { - if (strpos($table, '.') !== FALSE) - { - sscanf($table, '%[^.].%s', $owner, $table); - } - else - { - $owner = $this->username; - } - - $sql = 'SELECT COLUMN_NAME, DATA_TYPE, CHAR_LENGTH, DATA_PRECISION, DATA_LENGTH, DATA_DEFAULT, NULLABLE - FROM ALL_TAB_COLUMNS - WHERE UPPER(OWNER) = '.$this->escape(strtoupper($owner)).' - AND UPPER(TABLE_NAME) = '.$this->escape(strtoupper($table)); - - if (($query = $this->query($sql)) === FALSE) - { - return FALSE; - } - $query = $query->result_object(); - - $retval = array(); - for ($i = 0, $c = count($query); $i < $c; $i++) - { - $retval[$i] = new stdClass(); - $retval[$i]->name = $query[$i]->COLUMN_NAME; - $retval[$i]->type = $query[$i]->DATA_TYPE; - - $length = ($query[$i]->CHAR_LENGTH > 0) - ? $query[$i]->CHAR_LENGTH : $query[$i]->DATA_PRECISION; - if ($length === NULL) - { - $length = $query[$i]->DATA_LENGTH; - } - $retval[$i]->max_length = $length; - - $default = $query[$i]->DATA_DEFAULT; - if ($default === NULL && $query[$i]->NULLABLE === 'N') - { - $default = ''; - } - $retval[$i]->default = $default; - } - - return $retval; - } - - // -------------------------------------------------------------------- - - /** - * Error - * - * Returns an array containing code and message of the last - * database error that has occured. - * - * @return array - */ - public function error() - { - /* oci_error() returns an array that already contains the - * 'code' and 'message' keys, so we can just return it. - */ - if (is_resource($this->curs_id)) - { - return oci_error($this->curs_id); - } - elseif (is_resource($this->stmt_id)) - { - return oci_error($this->stmt_id); - } - elseif (is_resource($this->conn_id)) - { - return oci_error($this->conn_id); - } - - return oci_error(); - } - - // -------------------------------------------------------------------- - - /** - * Insert batch statement - * - * Generates a platform-specific insert string from the supplied data - * - * @param string $table Table name - * @param array $keys INSERT keys - * @param array $values INSERT values - * @return string - */ - protected function _insert_batch($table, $keys, $values) - { - $keys = implode(', ', $keys); - $sql = "INSERT ALL\n"; - - for ($i = 0, $c = count($values); $i < $c; $i++) - { - $sql .= ' INTO '.$table.' ('.$keys.') VALUES '.$values[$i]."\n"; - } - - return $sql.'SELECT * FROM dual'; - } - - // -------------------------------------------------------------------- - - /** - * Truncate statement - * - * Generates a platform-specific truncate string from the supplied data - * - * If the database does not support the TRUNCATE statement, - * then this method maps to 'DELETE FROM table' - * - * @param string $table - * @return string - */ - protected function _truncate($table) - { - return 'TRUNCATE TABLE '.$table; - } - - // -------------------------------------------------------------------- - - /** - * Delete statement - * - * Generates a platform-specific delete string from the supplied data - * - * @param string $table - * @return string - */ - protected function _delete($table) - { - if ($this->qb_limit) - { - $this->where('rownum <= ',$this->qb_limit, FALSE); - $this->qb_limit = FALSE; - } - - return parent::_delete($table); - } - - // -------------------------------------------------------------------- - - /** - * LIMIT - * - * Generates a platform-specific LIMIT clause - * - * @param string $sql SQL Query - * @return string - */ - protected function _limit($sql) - { - if (version_compare($this->version(), '12.1', '>=')) - { - // OFFSET-FETCH can be used only with the ORDER BY clause - empty($this->qb_orderby) && $sql .= ' ORDER BY 1'; - - return $sql.' OFFSET '.(int) $this->qb_offset.' ROWS FETCH NEXT '.$this->qb_limit.' ROWS ONLY'; - } - - $this->limit_used = TRUE; - return 'SELECT * FROM (SELECT inner_query.*, rownum rnum FROM ('.$sql.') inner_query WHERE rownum < '.($this->qb_offset + $this->qb_limit + 1).')' - .($this->qb_offset ? ' WHERE rnum >= '.($this->qb_offset + 1) : ''); - } - - // -------------------------------------------------------------------- - - /** - * Close DB Connection - * - * @return void - */ - protected function _close() - { - oci_close($this->conn_id); - } - -} diff --git a/src/Database/drivers/oci8/oci8_forge.php b/src/Database/drivers/oci8/oci8_forge.php deleted file mode 100644 index a150d05..0000000 --- a/src/Database/drivers/oci8/oci8_forge.php +++ /dev/null @@ -1,150 +0,0 @@ -db->escape_identifiers($table); - $sqls = array(); - for ($i = 0, $c = count($field); $i < $c; $i++) - { - if ($field[$i]['_literal'] !== FALSE) - { - $field[$i] = "\n\t".$field[$i]['_literal']; - } - else - { - $field[$i]['_literal'] = "\n\t".$this->_process_column($field[$i]); - - if ( ! empty($field[$i]['comment'])) - { - $sqls[] = 'COMMENT ON COLUMN ' - .$this->db->escape_identifiers($table).'.'.$this->db->escape_identifiers($field[$i]['name']) - .' IS '.$field[$i]['comment']; - } - - if ($alter_type === 'MODIFY' && ! empty($field[$i]['new_name'])) - { - $sqls[] = $sql.' RENAME COLUMN '.$this->db->escape_identifiers($field[$i]['name']) - .' '.$this->db->escape_identifiers($field[$i]['new_name']); - } - } - } - - $sql .= ' '.$alter_type.' '; - $sql .= (count($field) === 1) - ? $field[0] - : '('.implode(',', $field).')'; - - // RENAME COLUMN must be executed after MODIFY - array_unshift($sqls, $sql); - return $sql; - } - - // -------------------------------------------------------------------- - - /** - * Field attribute AUTO_INCREMENT - * - * @param array &$attributes - * @param array &$field - * @return void - */ - protected function _attr_auto_increment(&$attributes, &$field) - { - // Not supported - sequences and triggers must be used instead - } - -} diff --git a/src/Database/drivers/oci8/oci8_result.php b/src/Database/drivers/oci8/oci8_result.php deleted file mode 100644 index 7fbe1b2..0000000 --- a/src/Database/drivers/oci8/oci8_result.php +++ /dev/null @@ -1,230 +0,0 @@ -stmt_id = $driver_object->stmt_id; - $this->curs_id = $driver_object->curs_id; - $this->limit_used = $driver_object->limit_used; - $this->commit_mode =& $driver_object->commit_mode; - $driver_object->stmt_id = FALSE; - } - - // -------------------------------------------------------------------- - - /** - * Number of fields in the result set - * - * @return int - */ - public function num_fields() - { - $count = oci_num_fields($this->stmt_id); - - // if we used a limit we subtract it - return ($this->limit_used) ? $count - 1 : $count; - } - - // -------------------------------------------------------------------- - - /** - * Fetch Field Names - * - * Generates an array of column names - * - * @return array - */ - public function list_fields() - { - $field_names = array(); - for ($c = 1, $fieldCount = $this->num_fields(); $c <= $fieldCount; $c++) - { - $field_names[] = oci_field_name($this->stmt_id, $c); - } - return $field_names; - } - - // -------------------------------------------------------------------- - - /** - * Field data - * - * Generates an array of objects containing field meta-data - * - * @return array - */ - public function field_data() - { - $retval = array(); - for ($c = 1, $fieldCount = $this->num_fields(); $c <= $fieldCount; $c++) - { - $F = new stdClass(); - $F->name = oci_field_name($this->stmt_id, $c); - $F->type = oci_field_type($this->stmt_id, $c); - $F->max_length = oci_field_size($this->stmt_id, $c); - - $retval[] = $F; - } - - return $retval; - } - - // -------------------------------------------------------------------- - - /** - * Free the result - * - * @return void - */ - public function free_result() - { - if (is_resource($this->result_id)) - { - oci_free_statement($this->result_id); - $this->result_id = FALSE; - } - - if (is_resource($this->stmt_id)) - { - oci_free_statement($this->stmt_id); - } - - if (is_resource($this->curs_id)) - { - oci_cancel($this->curs_id); - $this->curs_id = NULL; - } - } - - // -------------------------------------------------------------------- - - /** - * Result - associative array - * - * Returns the result set as an array - * - * @return array - */ - protected function _fetch_assoc() - { - $id = ($this->curs_id) ? $this->curs_id : $this->stmt_id; - return oci_fetch_assoc($id); - } - - // -------------------------------------------------------------------- - - /** - * Result - object - * - * Returns the result set as an object - * - * @param string $class_name - * @return object - */ - protected function _fetch_object($class_name = 'stdClass') - { - $row = ($this->curs_id) - ? oci_fetch_object($this->curs_id) - : oci_fetch_object($this->stmt_id); - - if ($class_name === 'stdClass' OR ! $row) - { - return $row; - } - - $class_name = new $class_name(); - foreach ($row as $key => $value) - { - $class_name->$key = $value; - } - - return $class_name; - } - -} diff --git a/src/Database/drivers/oci8/oci8_utility.php b/src/Database/drivers/oci8/oci8_utility.php deleted file mode 100644 index 6a871dd..0000000 --- a/src/Database/drivers/oci8/oci8_utility.php +++ /dev/null @@ -1,69 +0,0 @@ -db->display_error('db_unsupported_feature'); - } - -} diff --git a/src/Database/drivers/odbc/odbc_driver.php b/src/Database/drivers/odbc/odbc_driver.php deleted file mode 100644 index 17810f2..0000000 --- a/src/Database/drivers/odbc/odbc_driver.php +++ /dev/null @@ -1,378 +0,0 @@ -dsn)) - { - $this->dsn = $this->hostname; - } - } - - // -------------------------------------------------------------------- - - /** - * Non-persistent database connection - * - * @param bool $persistent - * @return resource - */ - public function db_connect($persistent = FALSE) - { - return ($persistent === TRUE) - ? odbc_pconnect($this->dsn, $this->username, $this->password) - : odbc_connect($this->dsn, $this->username, $this->password); - } - - // -------------------------------------------------------------------- - - /** - * Execute the query - * - * @param string $sql an SQL query - * @return resource - */ - protected function _execute($sql) - { - return odbc_exec($this->conn_id, $sql); - } - - // -------------------------------------------------------------------- - - /** - * Begin Transaction - * - * @return bool - */ - protected function _trans_begin() - { - return odbc_autocommit($this->conn_id, FALSE); - } - - // -------------------------------------------------------------------- - - /** - * Commit Transaction - * - * @return bool - */ - protected function _trans_commit() - { - if (odbc_commit($this->conn_id)) - { - odbc_autocommit($this->conn_id, TRUE); - return TRUE; - } - - return FALSE; - } - - // -------------------------------------------------------------------- - - /** - * Rollback Transaction - * - * @return bool - */ - protected function _trans_rollback() - { - if (odbc_rollback($this->conn_id)) - { - odbc_autocommit($this->conn_id, TRUE); - return TRUE; - } - - return FALSE; - } - - // -------------------------------------------------------------------- - - /** - * Determines if a query is a "write" type. - * - * @param string An SQL query string - * @return bool - */ - public function is_write_type($sql) - { - if (preg_match('#^(INSERT|UPDATE).*RETURNING\s.+(\,\s?.+)*$#i', $sql)) - { - return FALSE; - } - - return parent::is_write_type($sql); - } - - // -------------------------------------------------------------------- - - /** - * Platform-dependant string escape - * - * @param string - * @return string - */ - protected function _escape_str($str) - { - return Utf8::remove_invisible_characters($str); - } - - // -------------------------------------------------------------------- - - /** - * Affected Rows - * - * @return int - */ - public function affected_rows() - { - return odbc_num_rows($this->result_id); - } - - // -------------------------------------------------------------------- - - /** - * Insert ID - * - * @return bool - */ - public function insert_id() - { - return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE; - } - - // -------------------------------------------------------------------- - - /** - * Show table query - * - * Generates a platform-specific query string so that the table names can be fetched - * - * @param bool $prefix_limit - * @return string - */ - protected function _list_tables($prefix_limit = FALSE) - { - $sql = "SELECT table_name FROM information_schema.tables WHERE table_schema = '".$this->schema."'"; - - if ($prefix_limit !== FALSE && $this->dbprefix !== '') - { - return $sql." AND table_name LIKE '".$this->escape_like_str($this->dbprefix)."%' " - .sprintf($this->_like_escape_str, $this->_like_escape_chr); - } - - return $sql; - } - - // -------------------------------------------------------------------- - - /** - * Show column query - * - * Generates a platform-specific query string so that the column names can be fetched - * - * @param string $table - * @return string - */ - protected function _list_columns($table = '') - { - return 'SHOW COLUMNS FROM '.$table; - } - - // -------------------------------------------------------------------- - - /** - * Field data query - * - * Generates a platform-specific query so that the column data can be retrieved - * - * @param string $table - * @return string - */ - protected function _field_data($table) - { - return 'SELECT TOP 1 FROM '.$table; - } - - // -------------------------------------------------------------------- - - /** - * Error - * - * Returns an array containing code and message of the last - * database error that has occured. - * - * @return array - */ - public function error() - { - return array('code' => odbc_error($this->conn_id), 'message' => odbc_errormsg($this->conn_id)); - } - - // -------------------------------------------------------------------- - - /** - * Update statement - * - * Generates a platform-specific update string from the supplied data - * - * @param string $table - * @param array $values - * @return string - */ - protected function _update($table, $values) - { - $this->qb_limit = FALSE; - $this->qb_orderby = array(); - return parent::_update($table, $values); - } - - // -------------------------------------------------------------------- - - /** - * Truncate statement - * - * Generates a platform-specific truncate string from the supplied data - * - * If the database does not support the TRUNCATE statement, - * then this method maps to 'DELETE FROM table' - * - * @param string $table - * @return string - */ - protected function _truncate($table) - { - return 'DELETE FROM '.$table; - } - - // -------------------------------------------------------------------- - - /** - * Delete statement - * - * Generates a platform-specific delete string from the supplied data - * - * @param string $table - * @return string - */ - protected function _delete($table) - { - $this->qb_limit = FALSE; - return parent::_delete($table); - } - - // -------------------------------------------------------------------- - - /** - * Close DB Connection - * - * @return void - */ - protected function _close() - { - odbc_close($this->conn_id); - } - -} diff --git a/src/Database/drivers/odbc/odbc_result.php b/src/Database/drivers/odbc/odbc_result.php deleted file mode 100644 index 96d250d..0000000 --- a/src/Database/drivers/odbc/odbc_result.php +++ /dev/null @@ -1,268 +0,0 @@ -num_rows)) - { - return $this->num_rows; - } - elseif (($this->num_rows = odbc_num_rows($this->result_id)) !== -1) - { - return $this->num_rows; - } - - // Work-around for ODBC subdrivers that don't support num_rows() - if (count($this->result_array) > 0) - { - return $this->num_rows = count($this->result_array); - } - elseif (count($this->result_object) > 0) - { - return $this->num_rows = count($this->result_object); - } - - return $this->num_rows = count($this->result_array()); - } - - // -------------------------------------------------------------------- - - /** - * Number of fields in the result set - * - * @return int - */ - public function num_fields() - { - return odbc_num_fields($this->result_id); - } - - // -------------------------------------------------------------------- - - /** - * Fetch Field Names - * - * Generates an array of column names - * - * @return array - */ - public function list_fields() - { - $field_names = array(); - $num_fields = $this->num_fields(); - - if ($num_fields > 0) - { - for ($i = 1; $i <= $num_fields; $i++) - { - $field_names[] = odbc_field_name($this->result_id, $i); - } - } - - return $field_names; - } - - // -------------------------------------------------------------------- - - /** - * Field data - * - * Generates an array of objects containing field meta-data - * - * @return array - */ - public function field_data() - { - $retval = array(); - for ($i = 0, $odbc_index = 1, $c = $this->num_fields(); $i < $c; $i++, $odbc_index++) - { - $retval[$i] = new stdClass(); - $retval[$i]->name = odbc_field_name($this->result_id, $odbc_index); - $retval[$i]->type = odbc_field_type($this->result_id, $odbc_index); - $retval[$i]->max_length = odbc_field_len($this->result_id, $odbc_index); - $retval[$i]->primary_key = 0; - $retval[$i]->default = ''; - } - - return $retval; - } - - // -------------------------------------------------------------------- - - /** - * Free the result - * - * @return void - */ - public function free_result() - { - if (is_resource($this->result_id)) - { - odbc_free_result($this->result_id); - $this->result_id = FALSE; - } - } - - // -------------------------------------------------------------------- - - /** - * Result - associative array - * - * Returns the result set as an array - * - * @return array - */ - protected function _fetch_assoc() - { - return odbc_fetch_array($this->result_id); - } - - // -------------------------------------------------------------------- - - /** - * Result - object - * - * Returns the result set as an object - * - * @param string $class_name - * @return object - */ - protected function _fetch_object($class_name = 'stdClass') - { - $row = odbc_fetch_object($this->result_id); - - if ($class_name === 'stdClass' OR ! $row) - { - return $row; - } - - $class_name = new $class_name(); - foreach ($row as $key => $value) - { - $class_name->$key = $value; - } - - return $class_name; - } - -} - -// -------------------------------------------------------------------- - -if ( ! function_exists('odbc_fetch_array')) -{ - /** - * ODBC Fetch array - * - * Emulates the native odbc_fetch_array() function when - * it is not available (odbc_fetch_array() requires unixODBC) - * - * @param resource &$result - * @param int $rownumber - * @return array - */ - function odbc_fetch_array(&$result, $rownumber = 1) - { - $rs = array(); - if ( ! odbc_fetch_into($result, $rs, $rownumber)) - { - return FALSE; - } - - $rs_assoc = array(); - foreach ($rs as $k => $v) - { - $field_name = odbc_field_name($result, $k+1); - $rs_assoc[$field_name] = $v; - } - - return $rs_assoc; - } -} - -// -------------------------------------------------------------------- - -if ( ! function_exists('odbc_fetch_object')) -{ - /** - * ODBC Fetch object - * - * Emulates the native odbc_fetch_object() function when - * it is not available. - * - * @param resource &$result - * @param int $rownumber - * @return object - */ - function odbc_fetch_object(&$result, $rownumber = 1) - { - $rs = array(); - if ( ! odbc_fetch_into($result, $rs, $rownumber)) - { - return FALSE; - } - - $rs_object = new stdClass(); - foreach ($rs as $k => $v) - { - $field_name = odbc_field_name($result, $k+1); - $rs_object->$field_name = $v; - } - - return $rs_object; - } -} diff --git a/src/Database/drivers/odbc/odbc_utility.php b/src/Database/drivers/odbc/odbc_utility.php deleted file mode 100644 index fdc3e13..0000000 --- a/src/Database/drivers/odbc/odbc_utility.php +++ /dev/null @@ -1,63 +0,0 @@ -db->display_error('db_unsupported_feature'); - } - -} diff --git a/src/Database/drivers/pdo/pdo_driver.php b/src/Database/drivers/pdo/pdo_driver.php deleted file mode 100644 index badb9b4..0000000 --- a/src/Database/drivers/pdo/pdo_driver.php +++ /dev/null @@ -1,375 +0,0 @@ -dsn, $match) && count($match) === 2) - { - // If there is a minimum valid dsn string pattern found, we're done - // This is for general PDO users, who tend to have a full DSN string. - $this->subdriver = $match[1]; - return; - } - // Legacy support for DSN specified in the hostname field - elseif (preg_match('/([^:]+):/', $this->hostname, $match) && count($match) === 2) - { - $this->dsn = $this->hostname; - $this->hostname = NULL; - $this->subdriver = $match[1]; - return; - } - elseif (in_array($this->subdriver, array('mssql', 'sybase'), TRUE)) - { - $this->subdriver = 'dblib'; - } - elseif ($this->subdriver === '4D') - { - $this->subdriver = '4d'; - } - elseif ( ! in_array($this->subdriver, array('4d', 'cubrid', 'dblib', 'firebird', 'ibm', 'informix', 'mysql', 'oci', 'odbc', 'pgsql', 'sqlite', 'sqlsrv'), TRUE)) - { - Logger::logError('PDO: Invalid or non-existent subdriver'); - - if ($this->db_debug) - { - throw new DatabaseException('Invalid or non-existent PDO subdriver', 1); - } - } - - $this->dsn = NULL; - } - - // -------------------------------------------------------------------- - - /** - * Database connection - * - * @param bool $persistent - * @return object - */ - public function db_connect($persistent = FALSE) - { - $this->options[PDO::ATTR_PERSISTENT] = $persistent; - - try - { - return new PDO($this->dsn, $this->username, $this->password, $this->options); - } - catch (PDOException $e) - { - if ($this->db_debug && empty($this->failover)) - { - $this->display_error($e->getMessage(), '', TRUE); - } - - return FALSE; - } - } - - // -------------------------------------------------------------------- - - /** - * Database version number - * - * @return string - */ - public function version() - { - if (isset($this->data_cache['version'])) - { - return $this->data_cache['version']; - } - - // Not all subdrivers support the getAttribute() method - try - { - return $this->data_cache['version'] = $this->conn_id->getAttribute(PDO::ATTR_SERVER_VERSION); - } - catch (PDOException $e) - { - return parent::version(); - } - } - - // -------------------------------------------------------------------- - - /** - * Execute the query - * - * @param string $sql SQL query - * @return mixed - */ - protected function _execute($sql) - { - return $this->conn_id->query($sql); - } - - // -------------------------------------------------------------------- - - /** - * Begin Transaction - * - * @return bool - */ - protected function _trans_begin() - { - return $this->conn_id->beginTransaction(); - } - - // -------------------------------------------------------------------- - - /** - * Commit Transaction - * - * @return bool - */ - protected function _trans_commit() - { - return $this->conn_id->commit(); - } - - // -------------------------------------------------------------------- - - /** - * Rollback Transaction - * - * @return bool - */ - protected function _trans_rollback() - { - return $this->conn_id->rollBack(); - } - - // -------------------------------------------------------------------- - - /** - * Platform-dependant string escape - * - * @param string - * @return string - */ - protected function _escape_str($str) - { - // Escape the string - $str = $this->conn_id->quote($str); - - // If there are duplicated quotes, trim them away - return ($str[0] === "'") - ? substr($str, 1, -1) - : $str; - } - - // -------------------------------------------------------------------- - - /** - * Affected Rows - * - * @return int - */ - public function affected_rows() - { - return is_object($this->result_id) ? $this->result_id->rowCount() : 0; - } - - // -------------------------------------------------------------------- - - /** - * Insert ID - * - * @param string $name - * @return int - */ - public function insert_id($name = NULL) - { - return $this->conn_id->lastInsertId($name); - } - - // -------------------------------------------------------------------- - - /** - * Field data query - * - * Generates a platform-specific query so that the column data can be retrieved - * - * @param string $table - * @return string - */ - protected function _field_data($table) - { - return 'SELECT TOP 1 * FROM '.$this->protect_identifiers($table); - } - - // -------------------------------------------------------------------- - - /** - * Error - * - * Returns an array containing code and message of the last - * database error that has occured. - * - * @return array - */ - public function error() - { - $error = array('code' => '00000', 'message' => ''); - $pdo_error = $this->conn_id->errorInfo(); - - if (empty($pdo_error[0])) - { - return $error; - } - - $error['code'] = isset($pdo_error[1]) ? $pdo_error[0].'/'.$pdo_error[1] : $pdo_error[0]; - if (isset($pdo_error[2])) - { - $error['message'] = $pdo_error[2]; - } - - return $error; - } - - // -------------------------------------------------------------------- - - /** - * Update_Batch statement - * - * Generates a platform-specific batch update string from the supplied data - * - * @param string $table Table name - * @param array $values Update data - * @param string $index WHERE key - * @return string - */ - protected function _update_batch($table, $values, $index) - { - $ids = array(); - foreach ($values as $key => $val) - { - $ids[] = $val[$index]; - - foreach (array_keys($val) as $field) - { - if ($field !== $index) - { - $final[$field][] = 'WHEN '.$index.' = '.$val[$index].' THEN '.$val[$field]; - } - } - } - - $cases = ''; - foreach ($final as $k => $v) - { - $cases .= $k.' = CASE '."\n"; - - foreach ($v as $row) - { - $cases .= $row."\n"; - } - - $cases .= 'ELSE '.$k.' END, '; - } - - $this->where($index.' IN('.implode(',', $ids).')', NULL, FALSE); - - return 'UPDATE '.$table.' SET '.substr($cases, 0, -2).$this->_compile_wh('qb_where'); - } - - // -------------------------------------------------------------------- - - /** - * Truncate statement - * - * Generates a platform-specific truncate string from the supplied data - * - * If the database does not support the TRUNCATE statement, - * then this method maps to 'DELETE FROM table' - * - * @param string $table - * @return string - */ - protected function _truncate($table) - { - return 'TRUNCATE TABLE '.$table; - } - -} diff --git a/src/Database/drivers/pdo/pdo_result.php b/src/Database/drivers/pdo/pdo_result.php deleted file mode 100644 index 3db8a4b..0000000 --- a/src/Database/drivers/pdo/pdo_result.php +++ /dev/null @@ -1,198 +0,0 @@ -num_rows)) - { - return $this->num_rows; - } - elseif (count($this->result_array) > 0) - { - return $this->num_rows = count($this->result_array); - } - elseif (count($this->result_object) > 0) - { - return $this->num_rows = count($this->result_object); - } - elseif (($num_rows = $this->result_id->rowCount()) > 0) - { - return $this->num_rows = $num_rows; - } - - return $this->num_rows = count($this->result_array()); - } - - // -------------------------------------------------------------------- - - /** - * Number of fields in the result set - * - * @return int - */ - public function num_fields() - { - return $this->result_id->columnCount(); - } - - // -------------------------------------------------------------------- - - /** - * Fetch Field Names - * - * Generates an array of column names - * - * @return bool - */ - public function list_fields() - { - $field_names = array(); - for ($i = 0, $c = $this->num_fields(); $i < $c; $i++) - { - // Might trigger an E_WARNING due to not all subdrivers - // supporting getColumnMeta() - $field_names[$i] = @$this->result_id->getColumnMeta($i); - $field_names[$i] = $field_names[$i]['name']; - } - - return $field_names; - } - - // -------------------------------------------------------------------- - - /** - * Field data - * - * Generates an array of objects containing field meta-data - * - * @return array - */ - public function field_data() - { - try - { - $retval = array(); - - for ($i = 0, $c = $this->num_fields(); $i < $c; $i++) - { - $field = $this->result_id->getColumnMeta($i); - - $retval[$i] = new stdClass(); - $retval[$i]->name = $field['name']; - $retval[$i]->type = $field['native_type']; - $retval[$i]->max_length = ($field['len'] > 0) ? $field['len'] : NULL; - $retval[$i]->primary_key = (int) ( ! empty($field['flags']) && in_array('primary_key', $field['flags'], TRUE)); - } - - return $retval; - } - catch (Exception $e) - { - if ($this->db->db_debug) - { - return $this->db->display_error('db_unsupported_feature'); - } - - return FALSE; - } - } - - // -------------------------------------------------------------------- - - /** - * Free the result - * - * @return void - */ - public function free_result() - { - if (is_object($this->result_id)) - { - $this->result_id = FALSE; - } - } - - // -------------------------------------------------------------------- - - /** - * Result - associative array - * - * Returns the result set as an array - * - * @return array - */ - protected function _fetch_assoc() - { - return $this->result_id->fetch(PDO::FETCH_ASSOC); - } - - // -------------------------------------------------------------------- - - /** - * Result - object - * - * Returns the result set as an object - * - * @param string $class_name - * @return object - */ - protected function _fetch_object($class_name = 'stdClass') - { - return $this->result_id->fetchObject($class_name); - } - -} diff --git a/src/Database/drivers/pdo/pdo_utility.php b/src/Database/drivers/pdo/pdo_utility.php deleted file mode 100644 index 49c59aa..0000000 --- a/src/Database/drivers/pdo/pdo_utility.php +++ /dev/null @@ -1,63 +0,0 @@ -db->display_error('db_unsupported_feature'); - } - -} diff --git a/src/Database/drivers/pdo/subdrivers/pdo_4d_driver.php b/src/Database/drivers/pdo/subdrivers/pdo_4d_driver.php deleted file mode 100644 index 4abf822..0000000 --- a/src/Database/drivers/pdo/subdrivers/pdo_4d_driver.php +++ /dev/null @@ -1,200 +0,0 @@ -dsn)) - { - $this->dsn = '4D:host='.(empty($this->hostname) ? '127.0.0.1' : $this->hostname); - - empty($this->port) OR $this->dsn .= ';port='.$this->port; - empty($this->database) OR $this->dsn .= ';dbname='.$this->database; - empty($this->char_set) OR $this->dsn .= ';charset='.$this->char_set; - } - elseif ( ! empty($this->char_set) && strpos($this->dsn, 'charset=', 3) === FALSE) - { - $this->dsn .= ';charset='.$this->char_set; - } - } - - // -------------------------------------------------------------------- - - /** - * Show table query - * - * Generates a platform-specific query string so that the table names can be fetched - * - * @param bool $prefix_limit - * @return string - */ - protected function _list_tables($prefix_limit = FALSE) - { - $sql = 'SELECT '.$this->escape_identifiers('TABLE_NAME').' FROM '.$this->escape_identifiers('_USER_TABLES'); - - if ($prefix_limit === TRUE && $this->dbprefix !== '') - { - $sql .= ' WHERE '.$this->escape_identifiers('TABLE_NAME')." LIKE '".$this->escape_like_str($this->dbprefix)."%' " - .sprintf($this->_like_escape_str, $this->_like_escape_chr); - } - - return $sql; - } - - // -------------------------------------------------------------------- - - /** - * Show column query - * - * Generates a platform-specific query string so that the column names can be fetched - * - * @param string $table - * @return string - */ - protected function _list_columns($table = '') - { - return 'SELECT '.$this->escape_identifiers('COLUMN_NAME').' FROM '.$this->escape_identifiers('_USER_COLUMNS') - .' WHERE '.$this->escape_identifiers('TABLE_NAME').' = '.$this->escape($table); - } - - // -------------------------------------------------------------------- - - /** - * Field data query - * - * Generates a platform-specific query so that the column data can be retrieved - * - * @param string $table - * @return string - */ - protected function _field_data($table) - { - return 'SELECT * FROM '.$this->protect_identifiers($table, TRUE, NULL, FALSE).' LIMIT 1'; - } - - // -------------------------------------------------------------------- - - /** - * Update statement - * - * Generates a platform-specific update string from the supplied data - * - * @param string $table - * @param array $values - * @return string - */ - protected function _update($table, $values) - { - $this->qb_limit = FALSE; - $this->qb_orderby = array(); - return parent::_update($table, $values); - } - - // -------------------------------------------------------------------- - - /** - * Delete statement - * - * Generates a platform-specific delete string from the supplied data - * - * @param string $table - * @return string - */ - protected function _delete($table) - { - $this->qb_limit = FALSE; - return parent::_delete($table); - } - - // -------------------------------------------------------------------- - - /** - * LIMIT - * - * Generates a platform-specific LIMIT clause - * - * @param string $sql SQL Query - * @return string - */ - protected function _limit($sql) - { - return $sql.' LIMIT '.$this->qb_limit.($this->qb_offset ? ' OFFSET '.$this->qb_offset : ''); - } - -} diff --git a/src/Database/drivers/pdo/subdrivers/pdo_4d_forge.php b/src/Database/drivers/pdo/subdrivers/pdo_4d_forge.php deleted file mode 100644 index a83f4be..0000000 --- a/src/Database/drivers/pdo/subdrivers/pdo_4d_forge.php +++ /dev/null @@ -1,218 +0,0 @@ - 'INT', - 'SMALLINT' => 'INT', - 'INT' => 'INT64', - 'INT32' => 'INT64' - ); - - /** - * DEFAULT value representation in CREATE/ALTER TABLE statements - * - * @var string - */ - protected $_default = FALSE; - - // -------------------------------------------------------------------- - - /** - * ALTER TABLE - * - * @param string $alter_type ALTER type - * @param string $table Table name - * @param mixed $field Column definition - * @return string|string[] - */ - protected function _alter_table($alter_type, $table, $field) - { - if (in_array($alter_type, array('ADD', 'DROP'), TRUE)) - { - return parent::_alter_table($alter_type, $table, $field); - } - - // No method of modifying columns is supported - return FALSE; - } - - // -------------------------------------------------------------------- - - /** - * Process column - * - * @param array $field - * @return string - */ - protected function _process_column($field) - { - return $this->db->escape_identifiers($field['name']) - .' '.$field['type'].$field['length'] - .$field['null'] - .$field['unique'] - .$field['auto_increment']; - } - - // -------------------------------------------------------------------- - - /** - * Field attribute TYPE - * - * Performs a data type mapping between different databases. - * - * @param array &$attributes - * @return void - */ - protected function _attr_type(&$attributes) - { - switch (strtoupper($attributes['TYPE'])) - { - case 'TINYINT': - $attributes['TYPE'] = 'SMALLINT'; - $attributes['UNSIGNED'] = FALSE; - return; - case 'MEDIUMINT': - $attributes['TYPE'] = 'INTEGER'; - $attributes['UNSIGNED'] = FALSE; - return; - case 'INTEGER': - $attributes['TYPE'] = 'INT'; - return; - case 'BIGINT': - $attributes['TYPE'] = 'INT64'; - return; - default: return; - } - } - - // -------------------------------------------------------------------- - - /** - * Field attribute UNIQUE - * - * @param array &$attributes - * @param array &$field - * @return void - */ - protected function _attr_unique(&$attributes, &$field) - { - if ( ! empty($attributes['UNIQUE']) && $attributes['UNIQUE'] === TRUE) - { - $field['unique'] = ' UNIQUE'; - - // UNIQUE must be used with NOT NULL - $field['null'] = ' NOT NULL'; - } - } - - // -------------------------------------------------------------------- - - /** - * Field attribute AUTO_INCREMENT - * - * @param array &$attributes - * @param array &$field - * @return void - */ - protected function _attr_auto_increment(&$attributes, &$field) - { - if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE) - { - if (stripos($field['type'], 'int') !== FALSE) - { - $field['auto_increment'] = ' AUTO_INCREMENT'; - } - elseif (strcasecmp($field['type'], 'UUID') === 0) - { - $field['auto_increment'] = ' AUTO_GENERATE'; - } - } - } - -} diff --git a/src/Database/drivers/pdo/subdrivers/pdo_cubrid_driver.php b/src/Database/drivers/pdo/subdrivers/pdo_cubrid_driver.php deleted file mode 100644 index 2f692ce..0000000 --- a/src/Database/drivers/pdo/subdrivers/pdo_cubrid_driver.php +++ /dev/null @@ -1,250 +0,0 @@ -dsn)) - { - $this->dsn = 'cubrid:host='.(empty($this->hostname) ? '127.0.0.1' : $this->hostname); - - empty($this->port) OR $this->dsn .= ';port='.$this->port; - empty($this->database) OR $this->dsn .= ';dbname='.$this->database; - empty($this->char_set) OR $this->dsn .= ';charset='.$this->char_set; - } - } - - // -------------------------------------------------------------------- - - /** - * Show table query - * - * Generates a platform-specific query string so that the table names can be fetched - * - * @param bool $prefix_limit - * @return string - */ - protected function _list_tables($prefix_limit = FALSE) - { - $sql = 'SHOW TABLES'; - - if ($prefix_limit === TRUE && $this->dbprefix !== '') - { - return $sql." LIKE '".$this->escape_like_str($this->dbprefix)."%'"; - } - - return $sql; - } - - // -------------------------------------------------------------------- - - /** - * Show column query - * - * Generates a platform-specific query string so that the column names can be fetched - * - * @param string $table - * @return string - */ - protected function _list_columns($table = '') - { - return 'SHOW COLUMNS FROM '.$this->protect_identifiers($table, TRUE, NULL, FALSE); - } - - // -------------------------------------------------------------------- - - /** - * Returns an object with field data - * - * @param string $table - * @return array - */ - public function field_data($table) - { - if (($query = $this->query('SHOW COLUMNS FROM '.$this->protect_identifiers($table, TRUE, NULL, FALSE))) === FALSE) - { - return FALSE; - } - $query = $query->result_object(); - - $retval = array(); - for ($i = 0, $c = count($query); $i < $c; $i++) - { - $retval[$i] = new stdClass(); - $retval[$i]->name = $query[$i]->Field; - - sscanf($query[$i]->Type, '%[a-z](%d)', - $retval[$i]->type, - $retval[$i]->max_length - ); - - $retval[$i]->default = $query[$i]->Default; - $retval[$i]->primary_key = (int) ($query[$i]->Key === 'PRI'); - } - - return $retval; - } - - // -------------------------------------------------------------------- - - /** - * Update_Batch statement - * - * Generates a platform-specific batch update string from the supplied data - * - * @param string $table Table name - * @param array $values Update data - * @param string $index WHERE key - * @return string - */ - protected function _update_batch($table, $values, $index) - { - $ids = array(); - foreach ($values as $key => $val) - { - $ids[] = $val[$index]; - - foreach (array_keys($val) as $field) - { - if ($field !== $index) - { - $final[$field][] = 'WHEN '.$index.' = '.$val[$index].' THEN '.$val[$field]; - } - } - } - - $cases = ''; - foreach ($final as $k => $v) - { - $cases .= $k." = CASE \n" - .implode("\n", $v)."\n" - .'ELSE '.$k.' END), '; - } - - $this->where($index.' IN('.implode(',', $ids).')', NULL, FALSE); - - return 'UPDATE '.$table.' SET '.substr($cases, 0, -2).$this->_compile_wh('qb_where'); - } - - // -------------------------------------------------------------------- - - /** - * Truncate statement - * - * Generates a platform-specific truncate string from the supplied data - * - * If the database does not support the TRUNCATE statement, - * then this method maps to 'DELETE FROM table' - * - * @param string $table - * @return string - */ - protected function _truncate($table) - { - return 'TRUNCATE '.$table; - } - - // -------------------------------------------------------------------- - - /** - * FROM tables - * - * Groups tables in FROM clauses if needed, so there is no confusion - * about operator precedence. - * - * @return string - */ - protected function _from_tables() - { - if ( ! empty($this->qb_join) && count($this->qb_from) > 1) - { - return '('.implode(', ', $this->qb_from).')'; - } - - return implode(', ', $this->qb_from); - } - -} diff --git a/src/Database/drivers/pdo/subdrivers/pdo_cubrid_forge.php b/src/Database/drivers/pdo/subdrivers/pdo_cubrid_forge.php deleted file mode 100644 index 9bde68c..0000000 --- a/src/Database/drivers/pdo/subdrivers/pdo_cubrid_forge.php +++ /dev/null @@ -1,228 +0,0 @@ - 'INTEGER', - 'SMALLINT' => 'INTEGER', - 'INT' => 'BIGINT', - 'INTEGER' => 'BIGINT', - 'BIGINT' => 'NUMERIC', - 'FLOAT' => 'DOUBLE', - 'REAL' => 'DOUBLE' - ); - - // -------------------------------------------------------------------- - - /** - * ALTER TABLE - * - * @param string $alter_type ALTER type - * @param string $table Table name - * @param mixed $field Column definition - * @return string|string[] - */ - protected function _alter_table($alter_type, $table, $field) - { - if (in_array($alter_type, array('DROP', 'ADD'), TRUE)) - { - return parent::_alter_table($alter_type, $table, $field); - } - - $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table); - $sqls = array(); - for ($i = 0, $c = count($field); $i < $c; $i++) - { - if ($field[$i]['_literal'] !== FALSE) - { - $sqls[] = $sql.' CHANGE '.$field[$i]['_literal']; - } - else - { - $alter_type = empty($field[$i]['new_name']) ? ' MODIFY ' : ' CHANGE '; - $sqls[] = $sql.$alter_type.$this->_process_column($field[$i]); - } - } - - return $sqls; - } - - // -------------------------------------------------------------------- - - /** - * Process column - * - * @param array $field - * @return string - */ - protected function _process_column($field) - { - $extra_clause = isset($field['after']) - ? ' AFTER '.$this->db->escape_identifiers($field['after']) : ''; - - if (empty($extra_clause) && isset($field['first']) && $field['first'] === TRUE) - { - $extra_clause = ' FIRST'; - } - - return $this->db->escape_identifiers($field['name']) - .(empty($field['new_name']) ? '' : ' '.$this->db->escape_identifiers($field['new_name'])) - .' '.$field['type'].$field['length'] - .$field['unsigned'] - .$field['null'] - .$field['default'] - .$field['auto_increment'] - .$field['unique'] - .$extra_clause; - } - - // -------------------------------------------------------------------- - - /** - * Field attribute TYPE - * - * Performs a data type mapping between different databases. - * - * @param array &$attributes - * @return void - */ - protected function _attr_type(&$attributes) - { - switch (strtoupper($attributes['TYPE'])) - { - case 'TINYINT': - $attributes['TYPE'] = 'SMALLINT'; - $attributes['UNSIGNED'] = FALSE; - return; - case 'MEDIUMINT': - $attributes['TYPE'] = 'INTEGER'; - $attributes['UNSIGNED'] = FALSE; - return; - default: return; - } - } - - // -------------------------------------------------------------------- - - /** - * Process indexes - * - * @param string $table (ignored) - * @return string - */ - protected function _process_indexes($table) - { - $sql = ''; - - for ($i = 0, $c = count($this->keys); $i < $c; $i++) - { - if (is_array($this->keys[$i])) - { - for ($i2 = 0, $c2 = count($this->keys[$i]); $i2 < $c2; $i2++) - { - if ( ! isset($this->fields[$this->keys[$i][$i2]])) - { - unset($this->keys[$i][$i2]); - continue; - } - } - } - elseif ( ! isset($this->fields[$this->keys[$i]])) - { - unset($this->keys[$i]); - continue; - } - - is_array($this->keys[$i]) OR $this->keys[$i] = array($this->keys[$i]); - - $sql .= ",\n\tKEY ".$this->db->escape_identifiers(implode('_', $this->keys[$i])) - .' ('.implode(', ', $this->db->escape_identifiers($this->keys[$i])).')'; - } - - $this->keys = array(); - - return $sql; - } - -} diff --git a/src/Database/drivers/pdo/subdrivers/pdo_dblib_driver.php b/src/Database/drivers/pdo/subdrivers/pdo_dblib_driver.php deleted file mode 100644 index e5ef94a..0000000 --- a/src/Database/drivers/pdo/subdrivers/pdo_dblib_driver.php +++ /dev/null @@ -1,332 +0,0 @@ -dsn)) - { - $this->dsn = $params['subdriver'].':host='.(empty($this->hostname) ? '127.0.0.1' : $this->hostname); - - if ( ! empty($this->port)) - { - $this->dsn .= (DIRECTORY_SEPARATOR === '\\' ? ',' : ':').$this->port; - } - - empty($this->database) OR $this->dsn .= ';dbname='.$this->database; - empty($this->char_set) OR $this->dsn .= ';charset='.$this->char_set; - empty($this->appname) OR $this->dsn .= ';appname='.$this->appname; - } - else - { - if ( ! empty($this->char_set) && strpos($this->dsn, 'charset=', 6) === FALSE) - { - $this->dsn .= ';charset='.$this->char_set; - } - - $this->subdriver = 'dblib'; - } - } - - // -------------------------------------------------------------------- - - /** - * Database connection - * - * @param bool $persistent - * @return object - */ - public function db_connect($persistent = FALSE) - { - $this->conn_id = parent::db_connect($persistent); - - if ( ! is_object($this->conn_id)) - { - return $this->conn_id; - } - - // Determine how identifiers are escaped - $query = $this->query('SELECT CASE WHEN (@@OPTIONS | 256) = @@OPTIONS THEN 1 ELSE 0 END AS qi'); - $query = $query->row_array(); - $this->_quoted_identifier = empty($query) ? FALSE : (bool) $query['qi']; - $this->_escape_char = ($this->_quoted_identifier) ? '"' : array('[', ']'); - - return $this->conn_id; - } - - // -------------------------------------------------------------------- - - /** - * Show table query - * - * Generates a platform-specific query string so that the table names can be fetched - * - * @param bool $prefix_limit - * @return string - */ - protected function _list_tables($prefix_limit = FALSE) - { - $sql = 'SELECT '.$this->escape_identifiers('name') - .' FROM '.$this->escape_identifiers('sysobjects') - .' WHERE '.$this->escape_identifiers('type')." = 'U'"; - - if ($prefix_limit === TRUE && $this->dbprefix !== '') - { - $sql .= ' AND '.$this->escape_identifiers('name')." LIKE '".$this->escape_like_str($this->dbprefix)."%' " - .sprintf($this->_like_escape_str, $this->_like_escape_chr); - } - - return $sql.' ORDER BY '.$this->escape_identifiers('name'); - } - - // -------------------------------------------------------------------- - - /** - * Show column query - * - * Generates a platform-specific query string so that the column names can be fetched - * - * @param string $table - * @return string - */ - protected function _list_columns($table = '') - { - return 'SELECT COLUMN_NAME - FROM INFORMATION_SCHEMA.Columns - WHERE UPPER(TABLE_NAME) = '.$this->escape(strtoupper($table)); - } - - // -------------------------------------------------------------------- - - /** - * Returns an object with field data - * - * @param string $table - * @return array - */ - public function field_data($table) - { - $sql = 'SELECT COLUMN_NAME, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH, NUMERIC_PRECISION, COLUMN_DEFAULT - FROM INFORMATION_SCHEMA.Columns - WHERE UPPER(TABLE_NAME) = '.$this->escape(strtoupper($table)); - - if (($query = $this->query($sql)) === FALSE) - { - return FALSE; - } - $query = $query->result_object(); - - $retval = array(); - for ($i = 0, $c = count($query); $i < $c; $i++) - { - $retval[$i] = new stdClass(); - $retval[$i]->name = $query[$i]->COLUMN_NAME; - $retval[$i]->type = $query[$i]->DATA_TYPE; - $retval[$i]->max_length = ($query[$i]->CHARACTER_MAXIMUM_LENGTH > 0) ? $query[$i]->CHARACTER_MAXIMUM_LENGTH : $query[$i]->NUMERIC_PRECISION; - $retval[$i]->default = $query[$i]->COLUMN_DEFAULT; - } - - return $retval; - } - - // -------------------------------------------------------------------- - - /** - * Update statement - * - * Generates a platform-specific update string from the supplied data - * - * @param string $table - * @param array $values - * @return string - */ - protected function _update($table, $values) - { - $this->qb_limit = FALSE; - $this->qb_orderby = array(); - return parent::_update($table, $values); - } - - // -------------------------------------------------------------------- - - /** - * Delete statement - * - * Generates a platform-specific delete string from the supplied data - * - * @param string $table - * @return string - */ - protected function _delete($table) - { - if ($this->qb_limit) - { - return 'WITH fw_delete AS (SELECT TOP '.$this->qb_limit.' * FROM '.$table.$this->_compile_wh('qb_where').') DELETE FROM fw_delete'; - } - - return parent::_delete($table); - } - - // -------------------------------------------------------------------- - - /** - * LIMIT - * - * Generates a platform-specific LIMIT clause - * - * @param string $sql SQL Query - * @return string - */ - protected function _limit($sql) - { - $limit = $this->qb_offset + $this->qb_limit; - - // As of SQL Server 2005 (9.0.*) ROW_NUMBER() is supported, - // however an ORDER BY clause is required for it to work - if (version_compare($this->version(), '9', '>=') && $this->qb_offset && ! empty($this->qb_orderby)) - { - $orderby = $this->_compile_order_by(); - - // We have to strip the ORDER BY clause - $sql = trim(substr($sql, 0, strrpos($sql, $orderby))); - - // Get the fields to select from our subquery, so that we can avoid FW_rownum appearing in the actual results - if (count($this->qb_select) === 0) - { - $select = '*'; // Inevitable - } - else - { - // Use only field names and their aliases, everything else is out of our scope. - $select = array(); - $field_regexp = ($this->_quoted_identifier) - ? '("[^\"]+")' : '(\[[^\]]+\])'; - for ($i = 0, $c = count($this->qb_select); $i < $c; $i++) - { - $select[] = preg_match('/(?:\s|\.)'.$field_regexp.'$/i', $this->qb_select[$i], $m) - ? $m[1] : $this->qb_select[$i]; - } - $select = implode(', ', $select); - } - - return 'SELECT '.$select." FROM (\n\n" - .preg_replace('/^(SELECT( DISTINCT)?)/i', '\\1 ROW_NUMBER() OVER('.trim($orderby).') AS '.$this->escape_identifiers('FW_rownum').', ', $sql) - ."\n\n) ".$this->escape_identifiers('FW_subquery') - ."\nWHERE ".$this->escape_identifiers('FW_rownum').' BETWEEN '.($this->qb_offset + 1).' AND '.$limit; - } - - return preg_replace('/(^\SELECT (DISTINCT)?)/i','\\1 TOP '.$limit.' ', $sql); - } - - // -------------------------------------------------------------------- - - /** - * Insert batch statement - * - * Generates a platform-specific insert string from the supplied data. - * - * @param string $table Table name - * @param array $keys INSERT keys - * @param array $values INSERT values - * @return string|bool - */ - protected function _insert_batch($table, $keys, $values) - { - // Multiple-value inserts are only supported as of SQL Server 2008 - if (version_compare($this->version(), '10', '>=')) - { - return parent::_insert_batch($table, $keys, $values); - } - - return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE; - } - -} diff --git a/src/Database/drivers/pdo/subdrivers/pdo_dblib_forge.php b/src/Database/drivers/pdo/subdrivers/pdo_dblib_forge.php deleted file mode 100644 index bc73b0e..0000000 --- a/src/Database/drivers/pdo/subdrivers/pdo_dblib_forge.php +++ /dev/null @@ -1,145 +0,0 @@ - 'SMALLINT', - 'SMALLINT' => 'INT', - 'INT' => 'BIGINT', - 'REAL' => 'FLOAT' - ); - - // -------------------------------------------------------------------- - - /** - * ALTER TABLE - * - * @param string $alter_type ALTER type - * @param string $table Table name - * @param mixed $field Column definition - * @return string|string[] - */ - protected function _alter_table($alter_type, $table, $field) - { - if (in_array($alter_type, array('ADD', 'DROP'), TRUE)) - { - return parent::_alter_table($alter_type, $table, $field); - } - - $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table).' ALTER COLUMN '; - $sqls = array(); - for ($i = 0, $c = count($field); $i < $c; $i++) - { - $sqls[] = $sql.$this->_process_column($field[$i]); - } - - return $sqls; - } - - // -------------------------------------------------------------------- - - /** - * Field attribute TYPE - * - * Performs a data type mapping between different databases. - * - * @param array &$attributes - * @return void - */ - protected function _attr_type(&$attributes) - { - switch (strtoupper($attributes['TYPE'])) - { - case 'MEDIUMINT': - $attributes['TYPE'] = 'INTEGER'; - $attributes['UNSIGNED'] = FALSE; - return; - case 'INTEGER': - $attributes['TYPE'] = 'INT'; - return; - default: return; - } - } - - // -------------------------------------------------------------------- - - /** - * Field attribute AUTO_INCREMENT - * - * @param array &$attributes - * @param array &$field - * @return void - */ - protected function _attr_auto_increment(&$attributes, &$field) - { - if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE && stripos($field['type'], 'int') !== FALSE) - { - $field['auto_increment'] = ' IDENTITY(1,1)'; - } - } - -} diff --git a/src/Database/drivers/pdo/subdrivers/pdo_firebird_driver.php b/src/Database/drivers/pdo/subdrivers/pdo_firebird_driver.php deleted file mode 100644 index 0b5cbc7..0000000 --- a/src/Database/drivers/pdo/subdrivers/pdo_firebird_driver.php +++ /dev/null @@ -1,263 +0,0 @@ -dsn)) - { - $this->dsn = 'firebird:'; - - if ( ! empty($this->database)) - { - $this->dsn .= 'dbname='.$this->database; - } - elseif ( ! empty($this->hostname)) - { - $this->dsn .= 'dbname='.$this->hostname; - } - - empty($this->char_set) OR $this->dsn .= ';charset='.$this->char_set; - empty($this->role) OR $this->dsn .= ';role='.$this->role; - } - elseif ( ! empty($this->char_set) && strpos($this->dsn, 'charset=', 9) === FALSE) - { - $this->dsn .= ';charset='.$this->char_set; - } - } - - // -------------------------------------------------------------------- - - /** - * Show table query - * - * Generates a platform-specific query string so that the table names can be fetched - * - * @param bool $prefix_limit - * @return string - */ - protected function _list_tables($prefix_limit = FALSE) - { - $sql = 'SELECT "RDB$RELATION_NAME" FROM "RDB$RELATIONS" WHERE "RDB$RELATION_NAME" NOT LIKE \'RDB$%\' AND "RDB$RELATION_NAME" NOT LIKE \'MON$%\''; - - if ($prefix_limit === TRUE && $this->dbprefix !== '') - { - return $sql.' AND "RDB$RELATION_NAME" LIKE \''.$this->escape_like_str($this->dbprefix)."%' " - .sprintf($this->_like_escape_str, $this->_like_escape_chr); - } - - return $sql; - } - - // -------------------------------------------------------------------- - - /** - * Show column query - * - * Generates a platform-specific query string so that the column names can be fetched - * - * @param string $table - * @return string - */ - protected function _list_columns($table = '') - { - return 'SELECT "RDB$FIELD_NAME" FROM "RDB$RELATION_FIELDS" WHERE "RDB$RELATION_NAME" = '.$this->escape($table); - } - - // -------------------------------------------------------------------- - - /** - * Returns an object with field data - * - * @param string $table - * @return array - */ - public function field_data($table) - { - $sql = 'SELECT "rfields"."RDB$FIELD_NAME" AS "name", - CASE "fields"."RDB$FIELD_TYPE" - WHEN 7 THEN \'SMALLINT\' - WHEN 8 THEN \'INTEGER\' - WHEN 9 THEN \'QUAD\' - WHEN 10 THEN \'FLOAT\' - WHEN 11 THEN \'DFLOAT\' - WHEN 12 THEN \'DATE\' - WHEN 13 THEN \'TIME\' - WHEN 14 THEN \'CHAR\' - WHEN 16 THEN \'INT64\' - WHEN 27 THEN \'DOUBLE\' - WHEN 35 THEN \'TIMESTAMP\' - WHEN 37 THEN \'VARCHAR\' - WHEN 40 THEN \'CSTRING\' - WHEN 261 THEN \'BLOB\' - ELSE NULL - END AS "type", - "fields"."RDB$FIELD_LENGTH" AS "max_length", - "rfields"."RDB$DEFAULT_VALUE" AS "default" - FROM "RDB$RELATION_FIELDS" "rfields" - JOIN "RDB$FIELDS" "fields" ON "rfields"."RDB$FIELD_SOURCE" = "fields"."RDB$FIELD_NAME" - WHERE "rfields"."RDB$RELATION_NAME" = '.$this->escape($table).' - ORDER BY "rfields"."RDB$FIELD_POSITION"'; - - return (($query = $this->query($sql)) !== FALSE) - ? $query->result_object() - : FALSE; - } - - // -------------------------------------------------------------------- - - /** - * Update statement - * - * Generates a platform-specific update string from the supplied data - * - * @param string $table - * @param array $values - * @return string - */ - protected function _update($table, $values) - { - $this->qb_limit = FALSE; - return parent::_update($table, $values); - } - - // -------------------------------------------------------------------- - - /** - * Truncate statement - * - * Generates a platform-specific truncate string from the supplied data - * - * If the database does not support the TRUNCATE statement, - * then this method maps to 'DELETE FROM table' - * - * @param string $table - * @return string - */ - protected function _truncate($table) - { - return 'DELETE FROM '.$table; - } - - // -------------------------------------------------------------------- - - /** - * Delete statement - * - * Generates a platform-specific delete string from the supplied data - * - * @param string $table - * @return string - */ - protected function _delete($table) - { - $this->qb_limit = FALSE; - return parent::_delete($table); - } - - // -------------------------------------------------------------------- - - /** - * LIMIT - * - * Generates a platform-specific LIMIT clause - * - * @param string $sql SQL Query - * @return string - */ - protected function _limit($sql) - { - // Limit clause depends on if Interbase or Firebird - if (stripos($this->version(), 'firebird') !== FALSE) - { - $select = 'FIRST '.$this->qb_limit - .($this->qb_offset > 0 ? ' SKIP '.$this->qb_offset : ''); - } - else - { - $select = 'ROWS ' - .($this->qb_offset > 0 ? $this->qb_offset.' TO '.($this->qb_limit + $this->qb_offset) : $this->qb_limit); - } - - return preg_replace('`SELECT`i', 'SELECT '.$select, $sql); - } - -} diff --git a/src/Database/drivers/pdo/subdrivers/pdo_firebird_forge.php b/src/Database/drivers/pdo/subdrivers/pdo_firebird_forge.php deleted file mode 100644 index 1dc267a..0000000 --- a/src/Database/drivers/pdo/subdrivers/pdo_firebird_forge.php +++ /dev/null @@ -1,238 +0,0 @@ - 'INTEGER', - 'INTEGER' => 'INT64', - 'FLOAT' => 'DOUBLE PRECISION' - ); - - /** - * NULL value representation in CREATE/ALTER TABLE statements - * - * @var string - */ - protected $_null = 'NULL'; - - // -------------------------------------------------------------------- - - /** - * Create database - * - * @param string $db_name - * @return string - */ - public function create_database($db_name) - { - // Firebird databases are flat files, so a path is required - - // Hostname is needed for remote access - empty($this->db->hostname) OR $db_name = $this->hostname.':'.$db_name; - - return parent::create_database('"'.$db_name.'"'); - } - - // -------------------------------------------------------------------- - - /** - * Drop database - * - * @param string $db_name (ignored) - * @return bool - */ - public function drop_database($db_name = '') - { - if ( ! ibase_drop_db($this->conn_id)) - { - return ($this->db->db_debug) ? $this->db->display_error('db_unable_to_drop') : FALSE; - } - elseif ( ! empty($this->db->data_cache['db_names'])) - { - $key = array_search(strtolower($this->db->database), array_map('strtolower', $this->db->data_cache['db_names']), TRUE); - if ($key !== FALSE) - { - unset($this->db->data_cache['db_names'][$key]); - } - } - - return TRUE; - } - - // -------------------------------------------------------------------- - - /** - * ALTER TABLE - * - * @param string $alter_type ALTER type - * @param string $table Table name - * @param mixed $field Column definition - * @return string|string[] - */ - protected function _alter_table($alter_type, $table, $field) - { - if (in_array($alter_type, array('DROP', 'ADD'), TRUE)) - { - return parent::_alter_table($alter_type, $table, $field); - } - - $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table); - $sqls = array(); - for ($i = 0, $c = count($field); $i < $c; $i++) - { - if ($field[$i]['_literal'] !== FALSE) - { - return FALSE; - } - - if (isset($field[$i]['type'])) - { - $sqls[] = $sql.' ALTER COLUMN '.$this->db->escape_identifiers($field[$i]['name']) - .' TYPE '.$field[$i]['type'].$field[$i]['length']; - } - - if ( ! empty($field[$i]['default'])) - { - $sqls[] = $sql.' ALTER COLUMN '.$this->db->escape_identifiers($field[$i]['name']) - .' SET DEFAULT '.$field[$i]['default']; - } - - if (isset($field[$i]['null'])) - { - $sqls[] = 'UPDATE "RDB$RELATION_FIELDS" SET "RDB$NULL_FLAG" = ' - .($field[$i]['null'] === TRUE ? 'NULL' : '1') - .' WHERE "RDB$FIELD_NAME" = '.$this->db->escape($field[$i]['name']) - .' AND "RDB$RELATION_NAME" = '.$this->db->escape($table); - } - - if ( ! empty($field[$i]['new_name'])) - { - $sqls[] = $sql.' ALTER COLUMN '.$this->db->escape_identifiers($field[$i]['name']) - .' TO '.$this->db->escape_identifiers($field[$i]['new_name']); - } - } - - return $sqls; - } - - // -------------------------------------------------------------------- - - /** - * Process column - * - * @param array $field - * @return string - */ - protected function _process_column($field) - { - return $this->db->escape_identifiers($field['name']) - .' '.$field['type'].$field['length'] - .$field['null'] - .$field['unique'] - .$field['default']; - } - - // -------------------------------------------------------------------- - - /** - * Field attribute TYPE - * - * Performs a data type mapping between different databases. - * - * @param array &$attributes - * @return void - */ - protected function _attr_type(&$attributes) - { - switch (strtoupper($attributes['TYPE'])) - { - case 'TINYINT': - $attributes['TYPE'] = 'SMALLINT'; - $attributes['UNSIGNED'] = FALSE; - return; - case 'MEDIUMINT': - $attributes['TYPE'] = 'INTEGER'; - $attributes['UNSIGNED'] = FALSE; - return; - case 'INT': - $attributes['TYPE'] = 'INTEGER'; - return; - case 'BIGINT': - $attributes['TYPE'] = 'INT64'; - return; - default: return; - } - } - - // -------------------------------------------------------------------- - - /** - * Field attribute AUTO_INCREMENT - * - * @param array &$attributes - * @param array &$field - * @return void - */ - protected function _attr_auto_increment(&$attributes, &$field) - { - // Not supported - } - -} diff --git a/src/Database/drivers/pdo/subdrivers/pdo_ibm_driver.php b/src/Database/drivers/pdo/subdrivers/pdo_ibm_driver.php deleted file mode 100644 index e100dbb..0000000 --- a/src/Database/drivers/pdo/subdrivers/pdo_ibm_driver.php +++ /dev/null @@ -1,244 +0,0 @@ -dsn)) - { - $this->dsn = 'ibm:'; - - // Pre-defined DSN - if (empty($this->hostname) && empty($this->HOSTNAME) && empty($this->port) && empty($this->PORT)) - { - if (isset($this->DSN)) - { - $this->dsn .= 'DSN='.$this->DSN; - } - elseif ( ! empty($this->database)) - { - $this->dsn .= 'DSN='.$this->database; - } - - return; - } - - $this->dsn .= 'DRIVER='.(isset($this->DRIVER) ? '{'.$this->DRIVER.'}' : '{IBM DB2 ODBC DRIVER}').';'; - - if (isset($this->DATABASE)) - { - $this->dsn .= 'DATABASE='.$this->DATABASE.';'; - } - elseif ( ! empty($this->database)) - { - $this->dsn .= 'DATABASE='.$this->database.';'; - } - - if (isset($this->HOSTNAME)) - { - $this->dsn .= 'HOSTNAME='.$this->HOSTNAME.';'; - } - else - { - $this->dsn .= 'HOSTNAME='.(empty($this->hostname) ? '127.0.0.1;' : $this->hostname.';'); - } - - if (isset($this->PORT)) - { - $this->dsn .= 'PORT='.$this->port.';'; - } - elseif ( ! empty($this->port)) - { - $this->dsn .= ';PORT='.$this->port.';'; - } - - $this->dsn .= 'PROTOCOL='.(isset($this->PROTOCOL) ? $this->PROTOCOL.';' : 'TCPIP;'); - } - } - - // -------------------------------------------------------------------- - - /** - * Show table query - * - * Generates a platform-specific query string so that the table names can be fetched - * - * @param bool $prefix_limit - * @return string - */ - protected function _list_tables($prefix_limit = FALSE) - { - $sql = 'SELECT "tabname" FROM "syscat"."tables" - WHERE "type" = \'T\' AND LOWER("tabschema") = '.$this->escape(strtolower($this->database)); - - if ($prefix_limit === TRUE && $this->dbprefix !== '') - { - $sql .= ' AND "tabname" LIKE \''.$this->escape_like_str($this->dbprefix)."%' " - .sprintf($this->_like_escape_str, $this->_like_escape_chr); - } - - return $sql; - } - - // -------------------------------------------------------------------- - - /** - * Show column query - * - * Generates a platform-specific query string so that the column names can be fetched - * - * @param string $table - * @return array - */ - protected function _list_columns($table = '') - { - return 'SELECT "colname" FROM "syscat"."columns" - WHERE LOWER("tabschema") = '.$this->escape(strtolower($this->database)).' - AND LOWER("tabname") = '.$this->escape(strtolower($table)); - } - - // -------------------------------------------------------------------- - - /** - * Returns an object with field data - * - * @param string $table - * @return array - */ - public function field_data($table) - { - $sql = 'SELECT "colname" AS "name", "typename" AS "type", "default" AS "default", "length" AS "max_length", - CASE "keyseq" WHEN NULL THEN 0 ELSE 1 END AS "primary_key" - FROM "syscat"."columns" - WHERE LOWER("tabschema") = '.$this->escape(strtolower($this->database)).' - AND LOWER("tabname") = '.$this->escape(strtolower($table)).' - ORDER BY "colno"'; - - return (($query = $this->query($sql)) !== FALSE) - ? $query->result_object() - : FALSE; - } - - // -------------------------------------------------------------------- - - /** - * Update statement - * - * Generates a platform-specific update string from the supplied data - * - * @param string $table - * @param array $values - * @return string - */ - protected function _update($table, $values) - { - $this->qb_limit = FALSE; - $this->qb_orderby = array(); - return parent::_update($table, $values); - } - - // -------------------------------------------------------------------- - - /** - * Delete statement - * - * Generates a platform-specific delete string from the supplied data - * - * @param string $table - * @return string - */ - protected function _delete($table) - { - $this->qb_limit = FALSE; - return parent::_delete($table); - } - - // -------------------------------------------------------------------- - - /** - * LIMIT - * - * Generates a platform-specific LIMIT clause - * - * @param string $sql SQL Query - * @return string - */ - protected function _limit($sql) - { - $sql .= ' FETCH FIRST '.($this->qb_limit + $this->qb_offset).' ROWS ONLY'; - - return ($this->qb_offset) - ? 'SELECT * FROM ('.$sql.') WHERE rownum > '.$this->qb_offset - : $sql; - } - -} diff --git a/src/Database/drivers/pdo/subdrivers/pdo_ibm_forge.php b/src/Database/drivers/pdo/subdrivers/pdo_ibm_forge.php deleted file mode 100644 index 61ae037..0000000 --- a/src/Database/drivers/pdo/subdrivers/pdo_ibm_forge.php +++ /dev/null @@ -1,155 +0,0 @@ - 'INTEGER', - 'INT' => 'BIGINT', - 'INTEGER' => 'BIGINT' - ); - - /** - * DEFAULT value representation in CREATE/ALTER TABLE statements - * - * @var string - */ - protected $_default = FALSE; - - // -------------------------------------------------------------------- - - /** - * ALTER TABLE - * - * @param string $alter_type ALTER type - * @param string $table Table name - * @param mixed $field Column definition - * @return string|string[] - */ - protected function _alter_table($alter_type, $table, $field) - { - if ($alter_type === 'CHANGE') - { - $alter_type = 'MODIFY'; - } - - return parent::_alter_table($alter_type, $table, $field); - } - - // -------------------------------------------------------------------- - - /** - * Field attribute TYPE - * - * Performs a data type mapping between different databases. - * - * @param array &$attributes - * @return void - */ - protected function _attr_type(&$attributes) - { - switch (strtoupper($attributes['TYPE'])) - { - case 'TINYINT': - $attributes['TYPE'] = 'SMALLINT'; - $attributes['UNSIGNED'] = FALSE; - return; - case 'MEDIUMINT': - $attributes['TYPE'] = 'INTEGER'; - $attributes['UNSIGNED'] = FALSE; - return; - default: return; - } - } - - // -------------------------------------------------------------------- - - /** - * Field attribute UNIQUE - * - * @param array &$attributes - * @param array &$field - * @return void - */ - protected function _attr_unique(&$attributes, &$field) - { - if ( ! empty($attributes['UNIQUE']) && $attributes['UNIQUE'] === TRUE) - { - $field['unique'] = ' UNIQUE'; - - // UNIQUE must be used with NOT NULL - $field['null'] = ' NOT NULL'; - } - } - - // -------------------------------------------------------------------- - - /** - * Field attribute AUTO_INCREMENT - * - * @param array &$attributes - * @param array &$field - * @return void - */ - protected function _attr_auto_increment(&$attributes, &$field) - { - // Not supported - } - -} diff --git a/src/Database/drivers/pdo/subdrivers/pdo_informix_driver.php b/src/Database/drivers/pdo/subdrivers/pdo_informix_driver.php deleted file mode 100644 index 7c5d497..0000000 --- a/src/Database/drivers/pdo/subdrivers/pdo_informix_driver.php +++ /dev/null @@ -1,309 +0,0 @@ -dsn)) - { - $this->dsn = 'informix:'; - - // Pre-defined DSN - if (empty($this->hostname) && empty($this->host) && empty($this->port) && empty($this->service)) - { - if (isset($this->DSN)) - { - $this->dsn .= 'DSN='.$this->DSN; - } - elseif ( ! empty($this->database)) - { - $this->dsn .= 'DSN='.$this->database; - } - - return; - } - - if (isset($this->host)) - { - $this->dsn .= 'host='.$this->host; - } - else - { - $this->dsn .= 'host='.(empty($this->hostname) ? '127.0.0.1' : $this->hostname); - } - - if (isset($this->service)) - { - $this->dsn .= '; service='.$this->service; - } - elseif ( ! empty($this->port)) - { - $this->dsn .= '; service='.$this->port; - } - - empty($this->database) OR $this->dsn .= '; database='.$this->database; - empty($this->server) OR $this->dsn .= '; server='.$this->server; - - $this->dsn .= '; protocol='.(isset($this->protocol) ? $this->protocol : 'onsoctcp') - .'; EnableScrollableCursors=1'; - } - } - - // -------------------------------------------------------------------- - - /** - * Show table query - * - * Generates a platform-specific query string so that the table names can be fetched - * - * @param bool $prefix_limit - * @return string - */ - protected function _list_tables($prefix_limit = FALSE) - { - $sql = 'SELECT "tabname" FROM "systables" - WHERE "tabid" > 99 AND "tabtype" = \'T\' AND LOWER("owner") = '.$this->escape(strtolower($this->username)); - - if ($prefix_limit === TRUE && $this->dbprefix !== '') - { - $sql .= ' AND "tabname" LIKE \''.$this->escape_like_str($this->dbprefix)."%' " - .sprintf($this->_like_escape_str, $this->_like_escape_chr); - } - - return $sql; - } - - // -------------------------------------------------------------------- - - /** - * Show column query - * - * Generates a platform-specific query string so that the column names can be fetched - * - * @param string $table - * @return string - */ - protected function _list_columns($table = '') - { - if (strpos($table, '.') !== FALSE) - { - sscanf($table, '%[^.].%s', $owner, $table); - } - else - { - $owner = $this->username; - } - - return 'SELECT "colname" FROM "systables", "syscolumns" - WHERE "systables"."tabid" = "syscolumns"."tabid" - AND "systables"."tabtype" = \'T\' - AND LOWER("systables"."owner") = '.$this->escape(strtolower($owner)).' - AND LOWER("systables"."tabname") = '.$this->escape(strtolower($table)); - } - - // -------------------------------------------------------------------- - - /** - * Returns an object with field data - * - * @param string $table - * @return array - */ - public function field_data($table) - { - $sql = 'SELECT "syscolumns"."colname" AS "name", - CASE "syscolumns"."coltype" - WHEN 0 THEN \'CHAR\' - WHEN 1 THEN \'SMALLINT\' - WHEN 2 THEN \'INTEGER\' - WHEN 3 THEN \'FLOAT\' - WHEN 4 THEN \'SMALLFLOAT\' - WHEN 5 THEN \'DECIMAL\' - WHEN 6 THEN \'SERIAL\' - WHEN 7 THEN \'DATE\' - WHEN 8 THEN \'MONEY\' - WHEN 9 THEN \'NULL\' - WHEN 10 THEN \'DATETIME\' - WHEN 11 THEN \'BYTE\' - WHEN 12 THEN \'TEXT\' - WHEN 13 THEN \'VARCHAR\' - WHEN 14 THEN \'INTERVAL\' - WHEN 15 THEN \'NCHAR\' - WHEN 16 THEN \'NVARCHAR\' - WHEN 17 THEN \'INT8\' - WHEN 18 THEN \'SERIAL8\' - WHEN 19 THEN \'SET\' - WHEN 20 THEN \'MULTISET\' - WHEN 21 THEN \'LIST\' - WHEN 22 THEN \'Unnamed ROW\' - WHEN 40 THEN \'LVARCHAR\' - WHEN 41 THEN \'BLOB/CLOB/BOOLEAN\' - WHEN 4118 THEN \'Named ROW\' - ELSE "syscolumns"."coltype" - END AS "type", - "syscolumns"."collength" as "max_length", - CASE "sysdefaults"."type" - WHEN \'L\' THEN "sysdefaults"."default" - ELSE NULL - END AS "default" - FROM "syscolumns", "systables", "sysdefaults" - WHERE "syscolumns"."tabid" = "systables"."tabid" - AND "systables"."tabid" = "sysdefaults"."tabid" - AND "syscolumns"."colno" = "sysdefaults"."colno" - AND "systables"."tabtype" = \'T\' - AND LOWER("systables"."owner") = '.$this->escape(strtolower($this->username)).' - AND LOWER("systables"."tabname") = '.$this->escape(strtolower($table)).' - ORDER BY "syscolumns"."colno"'; - - return (($query = $this->query($sql)) !== FALSE) - ? $query->result_object() - : FALSE; - } - - // -------------------------------------------------------------------- - - /** - * Update statement - * - * Generates a platform-specific update string from the supplied data - * - * @param string $table - * @param array $values - * @return string - */ - protected function _update($table, $values) - { - $this->qb_limit = FALSE; - $this->qb_orderby = array(); - return parent::_update($table, $values); - } - - // -------------------------------------------------------------------- - - /** - * Truncate statement - * - * Generates a platform-specific truncate string from the supplied data - * - * If the database does not support the TRUNCATE statement, - * then this method maps to 'DELETE FROM table' - * - * @param string $table - * @return string - */ - protected function _truncate($table) - { - return 'TRUNCATE TABLE ONLY '.$table; - } - - // -------------------------------------------------------------------- - - /** - * Delete statement - * - * Generates a platform-specific delete string from the supplied data - * - * @param string $table - * @return string - */ - protected function _delete($table) - { - $this->qb_limit = FALSE; - return parent::_delete($table); - } - - // -------------------------------------------------------------------- - - /** - * LIMIT - * - * Generates a platform-specific LIMIT clause - * - * @param string $sql $SQL Query - * @return string - */ - protected function _limit($sql) - { - $select = 'SELECT '.($this->qb_offset ? 'SKIP '.$this->qb_offset : '').'FIRST '.$this->qb_limit.' '; - return preg_replace('/^(SELECT\s)/i', $select, $sql, 1); - } - -} diff --git a/src/Database/drivers/pdo/subdrivers/pdo_informix_forge.php b/src/Database/drivers/pdo/subdrivers/pdo_informix_forge.php deleted file mode 100644 index 0ba09ea..0000000 --- a/src/Database/drivers/pdo/subdrivers/pdo_informix_forge.php +++ /dev/null @@ -1,164 +0,0 @@ - 'INTEGER', - 'INT' => 'BIGINT', - 'INTEGER' => 'BIGINT', - 'REAL' => 'DOUBLE PRECISION', - 'SMALLFLOAT' => 'DOUBLE PRECISION' - ); - - /** - * DEFAULT value representation in CREATE/ALTER TABLE statements - * - * @var string - */ - protected $_default = ', '; - - // -------------------------------------------------------------------- - - /** - * ALTER TABLE - * - * @param string $alter_type ALTER type - * @param string $table Table name - * @param mixed $field Column definition - * @return string|string[] - */ - protected function _alter_table($alter_type, $table, $field) - { - if ($alter_type === 'CHANGE') - { - $alter_type = 'MODIFY'; - } - - return parent::_alter_table($alter_type, $table, $field); - } - - // -------------------------------------------------------------------- - - /** - * Field attribute TYPE - * - * Performs a data type mapping between different databases. - * - * @param array &$attributes - * @return void - */ - protected function _attr_type(&$attributes) - { - switch (strtoupper($attributes['TYPE'])) - { - case 'TINYINT': - $attributes['TYPE'] = 'SMALLINT'; - $attributes['UNSIGNED'] = FALSE; - return; - case 'MEDIUMINT': - $attributes['TYPE'] = 'INTEGER'; - $attributes['UNSIGNED'] = FALSE; - return; - case 'BYTE': - case 'TEXT': - case 'BLOB': - case 'CLOB': - $attributes['UNIQUE'] = FALSE; - if (isset($attributes['DEFAULT'])) - { - unset($attributes['DEFAULT']); - } - return; - default: return; - } - } - - // -------------------------------------------------------------------- - - /** - * Field attribute UNIQUE - * - * @param array &$attributes - * @param array &$field - * @return void - */ - protected function _attr_unique(&$attributes, &$field) - { - if ( ! empty($attributes['UNIQUE']) && $attributes['UNIQUE'] === TRUE) - { - $field['unique'] = ' UNIQUE CONSTRAINT '.$this->db->escape_identifiers($field['name']); - } - } - - // -------------------------------------------------------------------- - - /** - * Field attribute AUTO_INCREMENT - * - * @param array &$attributes - * @param array &$field - * @return void - */ - protected function _attr_auto_increment(&$attributes, &$field) - { - // Not supported - } - -} diff --git a/src/Database/drivers/pdo/subdrivers/pdo_mysql_driver.php b/src/Database/drivers/pdo/subdrivers/pdo_mysql_driver.php deleted file mode 100644 index be56c41..0000000 --- a/src/Database/drivers/pdo/subdrivers/pdo_mysql_driver.php +++ /dev/null @@ -1,339 +0,0 @@ -dsn)) - { - $this->dsn = 'mysql:host='.(empty($this->hostname) ? '127.0.0.1' : $this->hostname); - - empty($this->port) OR $this->dsn .= ';port='.$this->port; - empty($this->database) OR $this->dsn .= ';dbname='.$this->database; - empty($this->char_set) OR $this->dsn .= ';charset='.$this->char_set; - } - elseif ( ! empty($this->char_set) && strpos($this->dsn, 'charset=', 6) === FALSE && Core::isPHP('5.3.6')) - { - $this->dsn .= ';charset='.$this->char_set; - } - } - - // -------------------------------------------------------------------- - - /** - * Database connection - * - * @param bool $persistent - * @return object - */ - public function db_connect($persistent = FALSE) - { - /* Prior to PHP 5.3.6, even if the charset was supplied in the DSN - * on connect - it was ignored. This is a work-around for the issue. - * - * Reference: http://www.php.net/manual/en/ref.pdo-mysql.connection.php - */ - if ( ! Core::isPHP('5.3.6') && ! empty($this->char_set)) - { - $this->options[PDO::MYSQL_ATTR_INIT_COMMAND] = 'SET NAMES '.$this->char_set - .(empty($this->dbcollat) ? '' : ' COLLATE '.$this->dbcollat); - } - - if (isset($this->stricton)) - { - if ($this->stricton) - { - $sql = 'CONCAT(@@sql_mode, ",", "STRICT_ALL_TABLES")'; - } - else - { - $sql = 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( - @@sql_mode, - "STRICT_ALL_TABLES,", ""), - ",STRICT_ALL_TABLES", ""), - "STRICT_ALL_TABLES", ""), - "STRICT_TRANS_TABLES,", ""), - ",STRICT_TRANS_TABLES", ""), - "STRICT_TRANS_TABLES", "")'; - } - - if ( ! empty($sql)) - { - if (empty($this->options[PDO::MYSQL_ATTR_INIT_COMMAND])) - { - $this->options[PDO::MYSQL_ATTR_INIT_COMMAND] = 'SET SESSION sql_mode = '.$sql; - } - else - { - $this->options[PDO::MYSQL_ATTR_INIT_COMMAND] .= ', @@session.sql_mode = '.$sql; - } - } - } - - if ($this->compress === TRUE) - { - $this->options[PDO::MYSQL_ATTR_COMPRESS] = TRUE; - } - - // SSL support was added to PDO_MYSQL in PHP 5.3.7 - if (is_array($this->encrypt) && Core::isPHP('5.3.7')) - { - $ssl = array(); - empty($this->encrypt['ssl_key']) OR $ssl[PDO::MYSQL_ATTR_SSL_KEY] = $this->encrypt['ssl_key']; - empty($this->encrypt['ssl_cert']) OR $ssl[PDO::MYSQL_ATTR_SSL_CERT] = $this->encrypt['ssl_cert']; - empty($this->encrypt['ssl_ca']) OR $ssl[PDO::MYSQL_ATTR_SSL_CA] = $this->encrypt['ssl_ca']; - empty($this->encrypt['ssl_capath']) OR $ssl[PDO::MYSQL_ATTR_SSL_CAPATH] = $this->encrypt['ssl_capath']; - empty($this->encrypt['ssl_cipher']) OR $ssl[PDO::MYSQL_ATTR_SSL_CIPHER] = $this->encrypt['ssl_cipher']; - - // DO NOT use array_merge() here! - // It re-indexes numeric keys and the PDO_MYSQL_ATTR_SSL_* constants are integers. - empty($ssl) OR $this->options += $ssl; - } - - // Prior to version 5.7.3, MySQL silently downgrades to an unencrypted connection if SSL setup fails - if ( - ($pdo = parent::db_connect($persistent)) !== FALSE - && ! empty($ssl) - && version_compare($pdo->getAttribute(PDO::ATTR_CLIENT_VERSION), '5.7.3', '<=') - && empty($pdo->query("SHOW STATUS LIKE 'ssl_cipher'")->fetchObject()->Value) - ) - { - $message = 'PDO_MYSQL was configured for an SSL connection, but got an unencrypted connection instead!'; - Logger::logError($message); - return ($this->db->db_debug) ? $this->db->display_error($message, '', TRUE) : FALSE; - } - - return $pdo; - } - - // -------------------------------------------------------------------- - - /** - * Select the database - * - * @param string $database - * @return bool - */ - public function db_select($database = '') - { - if ($database === '') - { - $database = $this->database; - } - - if (FALSE !== $this->simple_query('USE '.$this->escape_identifiers($database))) - { - $this->database = $database; - return TRUE; - } - - return FALSE; - } - - // -------------------------------------------------------------------- - - /** - * Show table query - * - * Generates a platform-specific query string so that the table names can be fetched - * - * @param bool $prefix_limit - * @return string - */ - protected function _list_tables($prefix_limit = FALSE) - { - $sql = 'SHOW TABLES'; - - if ($prefix_limit === TRUE && $this->dbprefix !== '') - { - return $sql." LIKE '".$this->escape_like_str($this->dbprefix)."%'"; - } - - return $sql; - } - - // -------------------------------------------------------------------- - - /** - * Show column query - * - * Generates a platform-specific query string so that the column names can be fetched - * - * @param string $table - * @return string - */ - protected function _list_columns($table = '') - { - return 'SHOW COLUMNS FROM '.$this->protect_identifiers($table, TRUE, NULL, FALSE); - } - - // -------------------------------------------------------------------- - - /** - * Returns an object with field data - * - * @param string $table - * @return array - */ - public function field_data($table) - { - if (($query = $this->query('SHOW COLUMNS FROM '.$this->protect_identifiers($table, TRUE, NULL, FALSE))) === FALSE) - { - return FALSE; - } - $query = $query->result_object(); - - $retval = array(); - for ($i = 0, $c = count($query); $i < $c; $i++) - { - $retval[$i] = new stdClass(); - $retval[$i]->name = $query[$i]->Field; - - sscanf($query[$i]->Type, '%[a-z](%d)', - $retval[$i]->type, - $retval[$i]->max_length - ); - - $retval[$i]->default = $query[$i]->Default; - $retval[$i]->primary_key = (int) ($query[$i]->Key === 'PRI'); - } - - return $retval; - } - - // -------------------------------------------------------------------- - - /** - * Truncate statement - * - * Generates a platform-specific truncate string from the supplied data - * - * If the database does not support the TRUNCATE statement, - * then this method maps to 'DELETE FROM table' - * - * @param string $table - * @return string - */ - protected function _truncate($table) - { - return 'TRUNCATE '.$table; - } - - // -------------------------------------------------------------------- - - /** - * FROM tables - * - * Groups tables in FROM clauses if needed, so there is no confusion - * about operator precedence. - * - * @return string - */ - protected function _from_tables() - { - if ( ! empty($this->qb_join) && count($this->qb_from) > 1) - { - return '('.implode(', ', $this->qb_from).')'; - } - - return implode(', ', $this->qb_from); - } - -} diff --git a/src/Database/drivers/pdo/subdrivers/pdo_mysql_forge.php b/src/Database/drivers/pdo/subdrivers/pdo_mysql_forge.php deleted file mode 100644 index 514c5cc..0000000 --- a/src/Database/drivers/pdo/subdrivers/pdo_mysql_forge.php +++ /dev/null @@ -1,257 +0,0 @@ -db->char_set) && ! strpos($sql, 'CHARACTER SET') && ! strpos($sql, 'CHARSET')) - { - $sql .= ' DEFAULT CHARACTER SET = '.$this->db->char_set; - } - - if ( ! empty($this->db->dbcollat) && ! strpos($sql, 'COLLATE')) - { - $sql .= ' COLLATE = '.$this->db->dbcollat; - } - - return $sql; - } - - // -------------------------------------------------------------------- - - /** - * ALTER TABLE - * - * @param string $alter_type ALTER type - * @param string $table Table name - * @param mixed $field Column definition - * @return string|string[] - */ - protected function _alter_table($alter_type, $table, $field) - { - if ($alter_type === 'DROP') - { - return parent::_alter_table($alter_type, $table, $field); - } - - $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table); - for ($i = 0, $c = count($field); $i < $c; $i++) - { - if ($field[$i]['_literal'] !== FALSE) - { - $field[$i] = ($alter_type === 'ADD') - ? "\n\tADD ".$field[$i]['_literal'] - : "\n\tMODIFY ".$field[$i]['_literal']; - } - else - { - if ($alter_type === 'ADD') - { - $field[$i]['_literal'] = "\n\tADD "; - } - else - { - $field[$i]['_literal'] = empty($field[$i]['new_name']) ? "\n\tMODIFY " : "\n\tCHANGE "; - } - - $field[$i] = $field[$i]['_literal'].$this->_process_column($field[$i]); - } - } - - return array($sql.implode(',', $field)); - } - - // -------------------------------------------------------------------- - - /** - * Process column - * - * @param array $field - * @return string - */ - protected function _process_column($field) - { - $extra_clause = isset($field['after']) - ? ' AFTER '.$this->db->escape_identifiers($field['after']) : ''; - - if (empty($extra_clause) && isset($field['first']) && $field['first'] === TRUE) - { - $extra_clause = ' FIRST'; - } - - return $this->db->escape_identifiers($field['name']) - .(empty($field['new_name']) ? '' : ' '.$this->db->escape_identifiers($field['new_name'])) - .' '.$field['type'].$field['length'] - .$field['unsigned'] - .$field['null'] - .$field['default'] - .$field['auto_increment'] - .$field['unique'] - .(empty($field['comment']) ? '' : ' COMMENT '.$field['comment']) - .$extra_clause; - } - - // -------------------------------------------------------------------- - - /** - * Process indexes - * - * @param string $table (ignored) - * @return string - */ - protected function _process_indexes($table) - { - $sql = ''; - - for ($i = 0, $c = count($this->keys); $i < $c; $i++) - { - if (is_array($this->keys[$i])) - { - for ($i2 = 0, $c2 = count($this->keys[$i]); $i2 < $c2; $i2++) - { - if ( ! isset($this->fields[$this->keys[$i][$i2]])) - { - unset($this->keys[$i][$i2]); - continue; - } - } - } - elseif ( ! isset($this->fields[$this->keys[$i]])) - { - unset($this->keys[$i]); - continue; - } - - is_array($this->keys[$i]) OR $this->keys[$i] = array($this->keys[$i]); - - $sql .= ",\n\tKEY ".$this->db->escape_identifiers(implode('_', $this->keys[$i])) - .' ('.implode(', ', $this->db->escape_identifiers($this->keys[$i])).')'; - } - - $this->keys = array(); - - return $sql; - } - -} diff --git a/src/Database/drivers/pdo/subdrivers/pdo_oci_driver.php b/src/Database/drivers/pdo/subdrivers/pdo_oci_driver.php deleted file mode 100644 index 37d673b..0000000 --- a/src/Database/drivers/pdo/subdrivers/pdo_oci_driver.php +++ /dev/null @@ -1,326 +0,0 @@ -dsn)) - { - $this->dsn = 'oci:dbname='; - - // Oracle has a slightly different PDO DSN format (Easy Connect), - // which also supports pre-defined DSNs. - if (empty($this->hostname) && empty($this->port)) - { - $this->dsn .= $this->database; - } - else - { - $this->dsn .= '//'.(empty($this->hostname) ? '127.0.0.1' : $this->hostname) - .(empty($this->port) ? '' : ':'.$this->port).'/'; - - empty($this->database) OR $this->dsn .= $this->database; - } - - empty($this->char_set) OR $this->dsn .= ';charset='.$this->char_set; - } - elseif ( ! empty($this->char_set) && strpos($this->dsn, 'charset=', 4) === FALSE) - { - $this->dsn .= ';charset='.$this->char_set; - } - } - - // -------------------------------------------------------------------- - - /** - * Database version number - * - * @return string - */ - public function version() - { - if (isset($this->data_cache['version'])) - { - return $this->data_cache['version']; - } - - $version_string = parent::version(); - if (preg_match('#Release\s(?\d+(?:\.\d+)+)#', $version_string, $match)) - { - return $this->data_cache['version'] = $match[1]; - } - - return FALSE; - } - - // -------------------------------------------------------------------- - - /** - * Show table query - * - * Generates a platform-specific query string so that the table names can be fetched - * - * @param bool $prefix_limit - * @return string - */ - protected function _list_tables($prefix_limit = FALSE) - { - $sql = 'SELECT "TABLE_NAME" FROM "ALL_TABLES"'; - - if ($prefix_limit === TRUE && $this->dbprefix !== '') - { - return $sql.' WHERE "TABLE_NAME" LIKE \''.$this->escape_like_str($this->dbprefix)."%' " - .sprintf($this->_like_escape_str, $this->_like_escape_chr); - } - - return $sql; - } - - // -------------------------------------------------------------------- - - /** - * Show column query - * - * Generates a platform-specific query string so that the column names can be fetched - * - * @param string $table - * @return string - */ - protected function _list_columns($table = '') - { - if (strpos($table, '.') !== FALSE) - { - sscanf($table, '%[^.].%s', $owner, $table); - } - else - { - $owner = $this->username; - } - - return 'SELECT COLUMN_NAME FROM ALL_TAB_COLUMNS - WHERE UPPER(OWNER) = '.$this->escape(strtoupper($owner)).' - AND UPPER(TABLE_NAME) = '.$this->escape(strtoupper($table)); - } - - // -------------------------------------------------------------------- - - /** - * Returns an object with field data - * - * @param string $table - * @return array - */ - public function field_data($table) - { - if (strpos($table, '.') !== FALSE) - { - sscanf($table, '%[^.].%s', $owner, $table); - } - else - { - $owner = $this->username; - } - - $sql = 'SELECT COLUMN_NAME, DATA_TYPE, CHAR_LENGTH, DATA_PRECISION, DATA_LENGTH, DATA_DEFAULT, NULLABLE - FROM ALL_TAB_COLUMNS - WHERE UPPER(OWNER) = '.$this->escape(strtoupper($owner)).' - AND UPPER(TABLE_NAME) = '.$this->escape(strtoupper($table)); - - if (($query = $this->query($sql)) === FALSE) - { - return FALSE; - } - $query = $query->result_object(); - - $retval = array(); - for ($i = 0, $c = count($query); $i < $c; $i++) - { - $retval[$i] = new stdClass(); - $retval[$i]->name = $query[$i]->COLUMN_NAME; - $retval[$i]->type = $query[$i]->DATA_TYPE; - - $length = ($query[$i]->CHAR_LENGTH > 0) - ? $query[$i]->CHAR_LENGTH : $query[$i]->DATA_PRECISION; - if ($length === NULL) - { - $length = $query[$i]->DATA_LENGTH; - } - $retval[$i]->max_length = $length; - - $default = $query[$i]->DATA_DEFAULT; - if ($default === NULL && $query[$i]->NULLABLE === 'N') - { - $default = ''; - } - $retval[$i]->default = $query[$i]->COLUMN_DEFAULT; - } - - return $retval; - } - - // -------------------------------------------------------------------- - - /** - * Insert batch statement - * - * @param string $table Table name - * @param array $keys INSERT keys - * @param array $values INSERT values - * @return string - */ - protected function _insert_batch($table, $keys, $values) - { - $keys = implode(', ', $keys); - $sql = "INSERT ALL\n"; - - for ($i = 0, $c = count($values); $i < $c; $i++) - { - $sql .= ' INTO '.$table.' ('.$keys.') VALUES '.$values[$i]."\n"; - } - - return $sql.'SELECT * FROM dual'; - } - - // -------------------------------------------------------------------- - - /** - * Delete statement - * - * Generates a platform-specific delete string from the supplied data - * - * @param string $table - * @return string - */ - protected function _delete($table) - { - if ($this->qb_limit) - { - $this->where('rownum <= ',$this->qb_limit, FALSE); - $this->qb_limit = FALSE; - } - - return parent::_delete($table); - } - - // -------------------------------------------------------------------- - - /** - * LIMIT - * - * Generates a platform-specific LIMIT clause - * - * @param string $sql SQL Query - * @return string - */ - protected function _limit($sql) - { - if (version_compare($this->version(), '12.1', '>=')) - { - // OFFSET-FETCH can be used only with the ORDER BY clause - empty($this->qb_orderby) && $sql .= ' ORDER BY 1'; - - return $sql.' OFFSET '.(int) $this->qb_offset.' ROWS FETCH NEXT '.$this->qb_limit.' ROWS ONLY'; - } - - return 'SELECT * FROM (SELECT inner_query.*, rownum rnum FROM ('.$sql.') inner_query WHERE rownum < '.($this->qb_offset + $this->qb_limit + 1).')' - .($this->qb_offset ? ' WHERE rnum >= '.($this->qb_offset + 1): ''); - } - -} diff --git a/src/Database/drivers/pdo/subdrivers/pdo_oci_forge.php b/src/Database/drivers/pdo/subdrivers/pdo_oci_forge.php deleted file mode 100644 index 9e9c37b..0000000 --- a/src/Database/drivers/pdo/subdrivers/pdo_oci_forge.php +++ /dev/null @@ -1,150 +0,0 @@ -db->escape_identifiers($table); - $sqls = array(); - for ($i = 0, $c = count($field); $i < $c; $i++) - { - if ($field[$i]['_literal'] !== FALSE) - { - $field[$i] = "\n\t".$field[$i]['_literal']; - } - else - { - $field[$i]['_literal'] = "\n\t".$this->_process_column($field[$i]); - - if ( ! empty($field[$i]['comment'])) - { - $sqls[] = 'COMMENT ON COLUMN ' - .$this->db->escape_identifiers($table).'.'.$this->db->escape_identifiers($field[$i]['name']) - .' IS '.$field[$i]['comment']; - } - - if ($alter_type === 'MODIFY' && ! empty($field[$i]['new_name'])) - { - $sqls[] = $sql.' RENAME COLUMN '.$this->db->escape_identifiers($field[$i]['name']) - .' '.$this->db->escape_identifiers($field[$i]['new_name']); - } - } - } - - $sql .= ' '.$alter_type.' '; - $sql .= (count($field) === 1) - ? $field[0] - : '('.implode(',', $field).')'; - - // RENAME COLUMN must be executed after MODIFY - array_unshift($sqls, $sql); - return $sql; - } - - // -------------------------------------------------------------------- - - /** - * Field attribute AUTO_INCREMENT - * - * @param array &$attributes - * @param array &$field - * @return void - */ - protected function _attr_auto_increment(&$attributes, &$field) - { - // Not supported - sequences and triggers must be used instead - } - -} diff --git a/src/Database/drivers/pdo/subdrivers/pdo_odbc_driver.php b/src/Database/drivers/pdo/subdrivers/pdo_odbc_driver.php deleted file mode 100644 index cef301b..0000000 --- a/src/Database/drivers/pdo/subdrivers/pdo_odbc_driver.php +++ /dev/null @@ -1,284 +0,0 @@ -dsn)) - { - $this->dsn = 'odbc:'; - - // Pre-defined DSN - if (empty($this->hostname) && empty($this->HOSTNAME) && empty($this->port) && empty($this->PORT)) - { - if (isset($this->DSN)) - { - $this->dsn .= 'DSN='.$this->DSN; - } - elseif ( ! empty($this->database)) - { - $this->dsn .= 'DSN='.$this->database; - } - - return; - } - - // If the DSN is not pre-configured - try to build an IBM DB2 connection string - $this->dsn .= 'DRIVER='.(isset($this->DRIVER) ? '{'.$this->DRIVER.'}' : '{IBM DB2 ODBC DRIVER}').';'; - - if (isset($this->DATABASE)) - { - $this->dsn .= 'DATABASE='.$this->DATABASE.';'; - } - elseif ( ! empty($this->database)) - { - $this->dsn .= 'DATABASE='.$this->database.';'; - } - - if (isset($this->HOSTNAME)) - { - $this->dsn .= 'HOSTNAME='.$this->HOSTNAME.';'; - } - else - { - $this->dsn .= 'HOSTNAME='.(empty($this->hostname) ? '127.0.0.1;' : $this->hostname.';'); - } - - if (isset($this->PORT)) - { - $this->dsn .= 'PORT='.$this->port.';'; - } - elseif ( ! empty($this->port)) - { - $this->dsn .= ';PORT='.$this->port.';'; - } - - $this->dsn .= 'PROTOCOL='.(isset($this->PROTOCOL) ? $this->PROTOCOL.';' : 'TCPIP;'); - } - } - - // -------------------------------------------------------------------- - - /** - * Determines if a query is a "write" type. - * - * @param string An SQL query string - * @return bool - */ - public function is_write_type($sql) - { - if (preg_match('#^(INSERT|UPDATE).*RETURNING\s.+(\,\s?.+)*$#i', $sql)) - { - return FALSE; - } - - return parent::is_write_type($sql); - } - - // -------------------------------------------------------------------- - - /** - * Show table query - * - * Generates a platform-specific query string so that the table names can be fetched - * - * @param bool $prefix_limit - * @return string - */ - protected function _list_tables($prefix_limit = FALSE) - { - $sql = "SELECT table_name FROM information_schema.tables WHERE table_schema = '".$this->schema."'"; - - if ($prefix_limit !== FALSE && $this->dbprefix !== '') - { - return $sql." AND table_name LIKE '".$this->escape_like_str($this->dbprefix)."%' " - .sprintf($this->_like_escape_str, $this->_like_escape_chr); - } - - return $sql; - } - - // -------------------------------------------------------------------- - - /** - * Show column query - * - * Generates a platform-specific query string so that the column names can be fetched - * - * @param string $table - * @return string - */ - protected function _list_columns($table = '') - { - return 'SELECT column_name FROM information_schema.columns WHERE table_name = '.$this->escape($table); - } - - // -------------------------------------------------------------------- - - /** - * Update statement - * - * Generates a platform-specific update string from the supplied data - * - * @param string $table - * @param array $values - * @return string - */ - protected function _update($table, $values) - { - $this->qb_limit = FALSE; - $this->qb_orderby = array(); - return parent::_update($table, $values); - } - - // -------------------------------------------------------------------- - - /** - * Truncate statement - * - * Generates a platform-specific truncate string from the supplied data - * - * If the database does not support the TRUNCATE statement, - * then this method maps to 'DELETE FROM table' - * - * @param string $table - * @return string - */ - protected function _truncate($table) - { - return 'DELETE FROM '.$table; - } - - // -------------------------------------------------------------------- - - /** - * Delete statement - * - * Generates a platform-specific delete string from the supplied data - * - * @param string the table name - * @return string - */ - protected function _delete($table) - { - $this->qb_limit = FALSE; - return parent::_delete($table); - } - - // -------------------------------------------------------------------- - - /** - * LIMIT - * - * Generates a platform-specific LIMIT clause - * - * @param string $sql SQL Query - * @return string - */ - protected function _limit($sql) - { - return preg_replace('/(^\SELECT (DISTINCT)?)/i','\\1 TOP '.$this->qb_limit.' ', $sql); - } - -} diff --git a/src/Database/drivers/pdo/subdrivers/pdo_odbc_forge.php b/src/Database/drivers/pdo/subdrivers/pdo_odbc_forge.php deleted file mode 100644 index b64b676..0000000 --- a/src/Database/drivers/pdo/subdrivers/pdo_odbc_forge.php +++ /dev/null @@ -1,71 +0,0 @@ -dsn)) - { - $this->dsn = 'pgsql:host='.(empty($this->hostname) ? '127.0.0.1' : $this->hostname); - - empty($this->port) OR $this->dsn .= ';port='.$this->port; - empty($this->database) OR $this->dsn .= ';dbname='.$this->database; - - if ( ! empty($this->username)) - { - $this->dsn .= ';username='.$this->username; - empty($this->password) OR $this->dsn .= ';password='.$this->password; - } - } - } - - // -------------------------------------------------------------------- - - /** - * Database connection - * - * @param bool $persistent - * @return object - */ - public function db_connect($persistent = FALSE) - { - $this->conn_id = parent::db_connect($persistent); - - if (is_object($this->conn_id) && ! empty($this->schema)) - { - $this->simple_query('SET search_path TO '.$this->schema.',public'); - } - - return $this->conn_id; - } - - // -------------------------------------------------------------------- - - /** - * Insert ID - * - * @param string $name - * @return int - */ - public function insert_id($name = NULL) - { - if ($name === NULL && version_compare($this->version(), '8.1', '>=')) - { - $query = $this->query('SELECT LASTVAL() AS ins_id'); - $query = $query->row(); - return $query->ins_id; - } - - return $this->conn_id->lastInsertId($name); - } - - // -------------------------------------------------------------------- - - /** - * Determines if a query is a "write" type. - * - * @param string An SQL query string - * @return bool - */ - public function is_write_type($sql) - { - if (preg_match('#^(INSERT|UPDATE).*RETURNING\s.+(\,\s?.+)*$#i', $sql)) - { - return FALSE; - } - - return parent::is_write_type($sql); - } - - // -------------------------------------------------------------------- - - /** - * "Smart" Escape String - * - * Escapes data based on type - * - * @param string $str - * @return mixed - */ - public function escape($str) - { - if (is_bool($str)) - { - return ($str) ? 'TRUE' : 'FALSE'; - } - - return parent::escape($str); - } - - // -------------------------------------------------------------------- - - /** - * ORDER BY - * - * @param string $orderby - * @param string $direction ASC, DESC or RANDOM - * @param bool $escape - * @return object - */ - public function order_by($orderby, $direction = '', $escape = NULL) - { - $direction = strtoupper(trim($direction)); - if ($direction === 'RANDOM') - { - if ( ! is_float($orderby) && ctype_digit((string) $orderby)) - { - $orderby = ($orderby > 1) - ? (float) '0.'.$orderby - : (float) $orderby; - } - - if (is_float($orderby)) - { - $this->simple_query('SET SEED '.$orderby); - } - - $orderby = $this->_random_keyword[0]; - $direction = ''; - $escape = FALSE; - } - - return parent::order_by($orderby, $direction, $escape); - } - - // -------------------------------------------------------------------- - - /** - * Show table query - * - * Generates a platform-specific query string so that the table names can be fetched - * - * @param bool $prefix_limit - * @return string - */ - protected function _list_tables($prefix_limit = FALSE) - { - $sql = 'SELECT "table_name" FROM "information_schema"."tables" WHERE "table_schema" = \''.$this->schema."'"; - - if ($prefix_limit === TRUE && $this->dbprefix !== '') - { - return $sql.' AND "table_name" LIKE \'' - .$this->escape_like_str($this->dbprefix)."%' " - .sprintf($this->_like_escape_str, $this->_like_escape_chr); - } - - return $sql; - } - - // -------------------------------------------------------------------- - - /** - * List column query - * - * Generates a platform-specific query string so that the column names can be fetched - * - * @param string $table - * @return string - */ - protected function _list_columns($table = '') - { - return 'SELECT "column_name" - FROM "information_schema"."columns" - WHERE LOWER("table_name") = '.$this->escape(strtolower($table)); - } - - // -------------------------------------------------------------------- - - /** - * Returns an object with field data - * - * @param string $table - * @return array - */ - public function field_data($table) - { - $sql = 'SELECT "column_name", "data_type", "character_maximum_length", "numeric_precision", "column_default" - FROM "information_schema"."columns" - WHERE LOWER("table_name") = '.$this->escape(strtolower($table)); - - if (($query = $this->query($sql)) === FALSE) - { - return FALSE; - } - $query = $query->result_object(); - - $retval = array(); - for ($i = 0, $c = count($query); $i < $c; $i++) - { - $retval[$i] = new stdClass(); - $retval[$i]->name = $query[$i]->column_name; - $retval[$i]->type = $query[$i]->data_type; - $retval[$i]->max_length = ($query[$i]->character_maximum_length > 0) ? $query[$i]->character_maximum_length : $query[$i]->numeric_precision; - $retval[$i]->default = $query[$i]->column_default; - } - - return $retval; - } - - // -------------------------------------------------------------------- - - /** - * Update statement - * - * Generates a platform-specific update string from the supplied data - * - * @param string $table - * @param array $values - * @return string - */ - protected function _update($table, $values) - { - $this->qb_limit = FALSE; - $this->qb_orderby = array(); - return parent::_update($table, $values); - } - - // -------------------------------------------------------------------- - - /** - * Update_Batch statement - * - * Generates a platform-specific batch update string from the supplied data - * - * @param string $table Table name - * @param array $values Update data - * @param string $index WHERE key - * @return string - */ - protected function _update_batch($table, $values, $index) - { - $ids = array(); - foreach ($values as $key => $val) - { - $ids[] = $val[$index]; - - foreach (array_keys($val) as $field) - { - if ($field !== $index) - { - $final[$field][] = 'WHEN '.$val[$index].' THEN '.$val[$field]; - } - } - } - - $cases = ''; - foreach ($final as $k => $v) - { - $cases .= $k.' = (CASE '.$index."\n" - .implode("\n", $v)."\n" - .'ELSE '.$k.' END), '; - } - - $this->where($index.' IN('.implode(',', $ids).')', NULL, FALSE); - - return 'UPDATE '.$table.' SET '.substr($cases, 0, -2).$this->_compile_wh('qb_where'); - } - - // -------------------------------------------------------------------- - - /** - * Delete statement - * - * Generates a platform-specific delete string from the supplied data - * - * @param string $table - * @return string - */ - protected function _delete($table) - { - $this->qb_limit = FALSE; - return parent::_delete($table); - } - - // -------------------------------------------------------------------- - - /** - * LIMIT - * - * Generates a platform-specific LIMIT clause - * - * @param string $sql SQL Query - * @return string - */ - protected function _limit($sql) - { - return $sql.' LIMIT '.$this->qb_limit.($this->qb_offset ? ' OFFSET '.$this->qb_offset : ''); - } - -} diff --git a/src/Database/drivers/pdo/subdrivers/pdo_pgsql_forge.php b/src/Database/drivers/pdo/subdrivers/pdo_pgsql_forge.php deleted file mode 100644 index d91d041..0000000 --- a/src/Database/drivers/pdo/subdrivers/pdo_pgsql_forge.php +++ /dev/null @@ -1,211 +0,0 @@ - 'INTEGER', - 'SMALLINT' => 'INTEGER', - 'INT' => 'BIGINT', - 'INT4' => 'BIGINT', - 'INTEGER' => 'BIGINT', - 'INT8' => 'NUMERIC', - 'BIGINT' => 'NUMERIC', - 'REAL' => 'DOUBLE PRECISION', - 'FLOAT' => 'DOUBLE PRECISION' - ); - - /** - * NULL value representation in CREATE/ALTER TABLE statements - * - * @var string - */ - protected $_null = 'NULL'; - - // -------------------------------------------------------------------- - - /** - * Class constructor - * - * @param object &$db Database object - * @return void - */ - public function __construct(&$db) - { - parent::__construct($db); - - if (version_compare($this->db->version(), '9.0', '>')) - { - $this->create_table_if = 'CREATE TABLE IF NOT EXISTS'; - } - } - - // -------------------------------------------------------------------- - - /** - * ALTER TABLE - * - * @param string $alter_type ALTER type - * @param string $table Table name - * @param mixed $field Column definition - * @return string|string[] - */ - protected function _alter_table($alter_type, $table, $field) - { - if (in_array($alter_type, array('DROP', 'ADD'), TRUE)) - { - return parent::_alter_table($alter_type, $table, $field); - } - - $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table); - $sqls = array(); - for ($i = 0, $c = count($field); $i < $c; $i++) - { - if ($field[$i]['_literal'] !== FALSE) - { - return FALSE; - } - - if (version_compare($this->db->version(), '8', '>=') && isset($field[$i]['type'])) - { - $sqls[] = $sql.' ALTER COLUMN '.$this->db->escape_identifiers($field[$i]['name']) - .' TYPE '.$field[$i]['type'].$field[$i]['length']; - } - - if ( ! empty($field[$i]['default'])) - { - $sqls[] = $sql.' ALTER COLUMN '.$this->db->escape_identifiers($field[$i]['name']) - .' SET DEFAULT '.$field[$i]['default']; - } - - if (isset($field[$i]['null'])) - { - $sqls[] = $sql.' ALTER COLUMN '.$this->db->escape_identifiers($field[$i]['name']) - .($field[$i]['null'] === TRUE ? ' DROP NOT NULL' : ' SET NOT NULL'); - } - - if ( ! empty($field[$i]['new_name'])) - { - $sqls[] = $sql.' RENAME COLUMN '.$this->db->escape_identifiers($field[$i]['name']) - .' TO '.$this->db->escape_identifiers($field[$i]['new_name']); - } - - if ( ! empty($field[$i]['comment'])) - { - $sqls[] = 'COMMENT ON COLUMN ' - .$this->db->escape_identifiers($table).'.'.$this->db->escape_identifiers($field[$i]['name']) - .' IS '.$field[$i]['comment']; - } - } - - return $sqls; - } - - // -------------------------------------------------------------------- - - /** - * Field attribute TYPE - * - * Performs a data type mapping between different databases. - * - * @param array &$attributes - * @return void - */ - protected function _attr_type(&$attributes) - { - // Reset field lenghts for data types that don't support it - if (isset($attributes['CONSTRAINT']) && stripos($attributes['TYPE'], 'int') !== FALSE) - { - $attributes['CONSTRAINT'] = NULL; - } - - switch (strtoupper($attributes['TYPE'])) - { - case 'TINYINT': - $attributes['TYPE'] = 'SMALLINT'; - $attributes['UNSIGNED'] = FALSE; - return; - case 'MEDIUMINT': - $attributes['TYPE'] = 'INTEGER'; - $attributes['UNSIGNED'] = FALSE; - return; - default: return; - } - } - - // -------------------------------------------------------------------- - - /** - * Field attribute AUTO_INCREMENT - * - * @param array &$attributes - * @param array &$field - * @return void - */ - protected function _attr_auto_increment(&$attributes, &$field) - { - if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE) - { - $field['type'] = ($field['type'] === 'NUMERIC') - ? 'BIGSERIAL' - : 'SERIAL'; - } - } - -} diff --git a/src/Database/drivers/pdo/subdrivers/pdo_sqlite_driver.php b/src/Database/drivers/pdo/subdrivers/pdo_sqlite_driver.php deleted file mode 100644 index af421f8..0000000 --- a/src/Database/drivers/pdo/subdrivers/pdo_sqlite_driver.php +++ /dev/null @@ -1,219 +0,0 @@ -dsn)) - { - $this->dsn = 'sqlite:'; - - if (empty($this->database) && empty($this->hostname)) - { - $this->database = ':memory:'; - } - - $this->database = empty($this->database) ? $this->hostname : $this->database; - } - } - - // -------------------------------------------------------------------- - - /** - * Show table query - * - * Generates a platform-specific query string so that the table names can be fetched - * - * @param bool $prefix_limit - * @return string - */ - protected function _list_tables($prefix_limit = FALSE) - { - $sql = 'SELECT "NAME" FROM "SQLITE_MASTER" WHERE "TYPE" = \'table\''; - - if ($prefix_limit === TRUE && $this->dbprefix !== '') - { - return $sql.' AND "NAME" LIKE \''.$this->escape_like_str($this->dbprefix)."%' " - .sprintf($this->_like_escape_str, $this->_like_escape_chr); - } - - return $sql; - } - - // -------------------------------------------------------------------- - - /** - * Fetch Field Names - * - * @param string $table Table name - * @return array - */ - public function list_fields($table) - { - // Is there a cached result? - if (isset($this->data_cache['field_names'][$table])) - { - return $this->data_cache['field_names'][$table]; - } - - if (($result = $this->query('PRAGMA TABLE_INFO('.$this->protect_identifiers($table, TRUE, NULL, FALSE).')')) === FALSE) - { - return FALSE; - } - - $this->data_cache['field_names'][$table] = array(); - foreach ($result->result_array() as $row) - { - $this->data_cache['field_names'][$table][] = $row['name']; - } - - return $this->data_cache['field_names'][$table]; - } - - // -------------------------------------------------------------------- - - /** - * Returns an object with field data - * - * @param string $table - * @return array - */ - public function field_data($table) - { - if (($query = $this->query('PRAGMA TABLE_INFO('.$this->protect_identifiers($table, TRUE, NULL, FALSE).')')) === FALSE) - { - return FALSE; - } - - $query = $query->result_array(); - if (empty($query)) - { - return FALSE; - } - - $retval = array(); - for ($i = 0, $c = count($query); $i < $c; $i++) - { - $retval[$i] = new stdClass(); - $retval[$i]->name = $query[$i]['name']; - $retval[$i]->type = $query[$i]['type']; - $retval[$i]->max_length = NULL; - $retval[$i]->default = $query[$i]['dflt_value']; - $retval[$i]->primary_key = isset($query[$i]['pk']) ? (int) $query[$i]['pk'] : 0; - } - - return $retval; - } - - // -------------------------------------------------------------------- - - /** - * Replace statement - * - * @param string $table Table name - * @param array $keys INSERT keys - * @param array $values INSERT values - * @return string - */ - protected function _replace($table, $keys, $values) - { - return 'INSERT OR '.parent::_replace($table, $keys, $values); - } - - // -------------------------------------------------------------------- - - /** - * Truncate statement - * - * Generates a platform-specific truncate string from the supplied data - * - * If the database does not support the TRUNCATE statement, - * then this method maps to 'DELETE FROM table' - * - * @param string $table - * @return string - */ - protected function _truncate($table) - { - return 'DELETE FROM '.$table; - } - -} diff --git a/src/Database/drivers/pdo/subdrivers/pdo_sqlite_forge.php b/src/Database/drivers/pdo/subdrivers/pdo_sqlite_forge.php deleted file mode 100644 index 3175624..0000000 --- a/src/Database/drivers/pdo/subdrivers/pdo_sqlite_forge.php +++ /dev/null @@ -1,239 +0,0 @@ -db->version(), '3.3', '<')) - { - $this->_create_table_if = FALSE; - $this->_drop_table_if = FALSE; - } - } - - // -------------------------------------------------------------------- - - /** - * Create database - * - * @param string $db_name (ignored) - * @return bool - */ - public function create_database($db_name = '') - { - // In SQLite, a database is created when you connect to the database. - // We'll return TRUE so that an error isn't generated - return TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Drop database - * - * @param string $db_name (ignored) - * @return bool - */ - public function drop_database($db_name = '') - { - // In SQLite, a database is dropped when we delete a file - if (file_exists($this->db->database)) - { - // We need to close the pseudo-connection first - $this->db->close(); - if ( ! @unlink($this->db->database)) - { - return $this->db->db_debug ? $this->db->display_error('db_unable_to_drop') : FALSE; - } - elseif ( ! empty($this->db->data_cache['db_names'])) - { - $key = array_search(strtolower($this->db->database), array_map('strtolower', $this->db->data_cache['db_names']), TRUE); - if ($key !== FALSE) - { - unset($this->db->data_cache['db_names'][$key]); - } - } - - return TRUE; - } - - return $this->db->db_debug ? $this->db->display_error('db_unable_to_drop') : FALSE; - } - - // -------------------------------------------------------------------- - - /** - * ALTER TABLE - * - * @param string $alter_type ALTER type - * @param string $table Table name - * @param mixed $field Column definition - * @return string|string[] - */ - protected function _alter_table($alter_type, $table, $field) - { - if ($alter_type === 'DROP' OR $alter_type === 'CHANGE') - { - // drop_column(): - // BEGIN TRANSACTION; - // CREATE TEMPORARY TABLE t1_backup(a,b); - // INSERT INTO t1_backup SELECT a,b FROM t1; - // DROP TABLE t1; - // CREATE TABLE t1(a,b); - // INSERT INTO t1 SELECT a,b FROM t1_backup; - // DROP TABLE t1_backup; - // COMMIT; - - return FALSE; - } - - return parent::_alter_table($alter_type, $table, $field); - } - - // -------------------------------------------------------------------- - - /** - * Process column - * - * @param array $field - * @return string - */ - protected function _process_column($field) - { - return $this->db->escape_identifiers($field['name']) - .' '.$field['type'] - .$field['auto_increment'] - .$field['null'] - .$field['unique'] - .$field['default']; - } - - // -------------------------------------------------------------------- - - /** - * Field attribute TYPE - * - * Performs a data type mapping between different databases. - * - * @param array &$attributes - * @return void - */ - protected function _attr_type(&$attributes) - { - switch (strtoupper($attributes['TYPE'])) - { - case 'ENUM': - case 'SET': - $attributes['TYPE'] = 'TEXT'; - return; - default: return; - } - } - - // -------------------------------------------------------------------- - - /** - * Field attribute AUTO_INCREMENT - * - * @param array &$attributes - * @param array &$field - * @return void - */ - protected function _attr_auto_increment(&$attributes, &$field) - { - if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE && stripos($field['type'], 'int') !== FALSE) - { - $field['type'] = 'INTEGER PRIMARY KEY'; - $field['default'] = ''; - $field['null'] = ''; - $field['unique'] = ''; - $field['auto_increment'] = ' AUTOINCREMENT'; - - $this->primary_keys = array(); - } - } - -} diff --git a/src/Database/drivers/pdo/subdrivers/pdo_sqlsrv_driver.php b/src/Database/drivers/pdo/subdrivers/pdo_sqlsrv_driver.php deleted file mode 100644 index fed6c93..0000000 --- a/src/Database/drivers/pdo/subdrivers/pdo_sqlsrv_driver.php +++ /dev/null @@ -1,369 +0,0 @@ -dsn)) - { - $this->dsn = 'sqlsrv:Server='.(empty($this->hostname) ? '127.0.0.1' : $this->hostname); - - empty($this->port) OR $this->dsn .= ','.$this->port; - empty($this->database) OR $this->dsn .= ';Database='.$this->database; - - // Some custom options - - if (isset($this->QuotedId)) - { - $this->dsn .= ';QuotedId='.$this->QuotedId; - $this->_quoted_identifier = (bool) $this->QuotedId; - } - - if (isset($this->ConnectionPooling)) - { - $this->dsn .= ';ConnectionPooling='.$this->ConnectionPooling; - } - - if ($this->encrypt === TRUE) - { - $this->dsn .= ';Encrypt=1'; - } - - if (isset($this->TraceOn)) - { - $this->dsn .= ';TraceOn='.$this->TraceOn; - } - - if (isset($this->TrustServerCertificate)) - { - $this->dsn .= ';TrustServerCertificate='.$this->TrustServerCertificate; - } - - empty($this->APP) OR $this->dsn .= ';APP='.$this->APP; - empty($this->Failover_Partner) OR $this->dsn .= ';Failover_Partner='.$this->Failover_Partner; - empty($this->LoginTimeout) OR $this->dsn .= ';LoginTimeout='.$this->LoginTimeout; - empty($this->MultipleActiveResultSets) OR $this->dsn .= ';MultipleActiveResultSets='.$this->MultipleActiveResultSets; - empty($this->TraceFile) OR $this->dsn .= ';TraceFile='.$this->TraceFile; - empty($this->WSID) OR $this->dsn .= ';WSID='.$this->WSID; - } - elseif (preg_match('/QuotedId=(0|1)/', $this->dsn, $match)) - { - $this->_quoted_identifier = (bool) $match[1]; - } - } - - // -------------------------------------------------------------------- - - /** - * Database connection - * - * @param bool $persistent - * @return object - */ - public function db_connect($persistent = FALSE) - { - if ( ! empty($this->char_set) && preg_match('/utf[^8]*8/i', $this->char_set)) - { - $this->options[PDO::SQLSRV_ENCODING_UTF8] = 1; - } - - $this->conn_id = parent::db_connect($persistent); - - if ( ! is_object($this->conn_id) OR is_bool($this->_quoted_identifier)) - { - return $this->conn_id; - } - - // Determine how identifiers are escaped - $query = $this->query('SELECT CASE WHEN (@@OPTIONS | 256) = @@OPTIONS THEN 1 ELSE 0 END AS qi'); - $query = $query->row_array(); - $this->_quoted_identifier = empty($query) ? FALSE : (bool) $query['qi']; - $this->_escape_char = ($this->_quoted_identifier) ? '"' : array('[', ']'); - - return $this->conn_id; - } - - // -------------------------------------------------------------------- - - /** - * Show table query - * - * Generates a platform-specific query string so that the table names can be fetched - * - * @param bool $prefix_limit - * @return string - */ - protected function _list_tables($prefix_limit = FALSE) - { - $sql = 'SELECT '.$this->escape_identifiers('name') - .' FROM '.$this->escape_identifiers('sysobjects') - .' WHERE '.$this->escape_identifiers('type')." = 'U'"; - - if ($prefix_limit === TRUE && $this->dbprefix !== '') - { - $sql .= ' AND '.$this->escape_identifiers('name')." LIKE '".$this->escape_like_str($this->dbprefix)."%' " - .sprintf($this->_like_escape_str, $this->_like_escape_chr); - } - - return $sql.' ORDER BY '.$this->escape_identifiers('name'); - } - - // -------------------------------------------------------------------- - - /** - * Show column query - * - * Generates a platform-specific query string so that the column names can be fetched - * - * @param string $table - * @return string - */ - protected function _list_columns($table = '') - { - return 'SELECT COLUMN_NAME - FROM INFORMATION_SCHEMA.Columns - WHERE UPPER(TABLE_NAME) = '.$this->escape(strtoupper($table)); - } - - // -------------------------------------------------------------------- - - /** - * Returns an object with field data - * - * @param string $table - * @return array - */ - public function field_data($table) - { - $sql = 'SELECT COLUMN_NAME, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH, NUMERIC_PRECISION, COLUMN_DEFAULT - FROM INFORMATION_SCHEMA.Columns - WHERE UPPER(TABLE_NAME) = '.$this->escape(strtoupper($table)); - - if (($query = $this->query($sql)) === FALSE) - { - return FALSE; - } - $query = $query->result_object(); - - $retval = array(); - for ($i = 0, $c = count($query); $i < $c; $i++) - { - $retval[$i] = new stdClass(); - $retval[$i]->name = $query[$i]->COLUMN_NAME; - $retval[$i]->type = $query[$i]->DATA_TYPE; - $retval[$i]->max_length = ($query[$i]->CHARACTER_MAXIMUM_LENGTH > 0) ? $query[$i]->CHARACTER_MAXIMUM_LENGTH : $query[$i]->NUMERIC_PRECISION; - $retval[$i]->default = $query[$i]->COLUMN_DEFAULT; - } - - return $retval; - } - - // -------------------------------------------------------------------- - - /** - * Update statement - * - * Generates a platform-specific update string from the supplied data - * - * @param string $table - * @param array $values - * @return string - */ - protected function _update($table, $values) - { - $this->qb_limit = FALSE; - $this->qb_orderby = array(); - return parent::_update($table, $values); - } - - // -------------------------------------------------------------------- - - /** - * Delete statement - * - * Generates a platform-specific delete string from the supplied data - * - * @param string $table - * @return string - */ - protected function _delete($table) - { - if ($this->qb_limit) - { - return 'WITH fw_delete AS (SELECT TOP '.$this->qb_limit.' * FROM '.$table.$this->_compile_wh('qb_where').') DELETE FROM fw_delete'; - } - - return parent::_delete($table); - } - - // -------------------------------------------------------------------- - - /** - * LIMIT - * - * Generates a platform-specific LIMIT clause - * - * @param string $sql SQL Query - * @return string - */ - protected function _limit($sql) - { - // As of SQL Server 2012 (11.0.*) OFFSET is supported - if (version_compare($this->version(), '11', '>=')) - { - // SQL Server OFFSET-FETCH can be used only with the ORDER BY clause - empty($this->qb_orderby) && $sql .= ' ORDER BY 1'; - - return $sql.' OFFSET '.(int) $this->qb_offset.' ROWS FETCH NEXT '.$this->qb_limit.' ROWS ONLY'; - } - - $limit = $this->qb_offset + $this->qb_limit; - - // An ORDER BY clause is required for ROW_NUMBER() to work - if ($this->qb_offset && ! empty($this->qb_orderby)) - { - $orderby = $this->_compile_order_by(); - - // We have to strip the ORDER BY clause - $sql = trim(substr($sql, 0, strrpos($sql, $orderby))); - - // Get the fields to select from our subquery, so that we can avoid FW_rownum appearing in the actual results - if (count($this->qb_select) === 0) - { - $select = '*'; // Inevitable - } - else - { - // Use only field names and their aliases, everything else is out of our scope. - $select = array(); - $field_regexp = ($this->_quoted_identifier) - ? '("[^\"]+")' : '(\[[^\]]+\])'; - for ($i = 0, $c = count($this->qb_select); $i < $c; $i++) - { - $select[] = preg_match('/(?:\s|\.)'.$field_regexp.'$/i', $this->qb_select[$i], $m) - ? $m[1] : $this->qb_select[$i]; - } - $select = implode(', ', $select); - } - - return 'SELECT '.$select." FROM (\n\n" - .preg_replace('/^(SELECT( DISTINCT)?)/i', '\\1 ROW_NUMBER() OVER('.trim($orderby).') AS '.$this->escape_identifiers('FW_rownum').', ', $sql) - ."\n\n) ".$this->escape_identifiers('FW_subquery') - ."\nWHERE ".$this->escape_identifiers('FW_rownum').' BETWEEN '.($this->qb_offset + 1).' AND '.$limit; - } - - return preg_replace('/(^\SELECT (DISTINCT)?)/i','\\1 TOP '.$limit.' ', $sql); - } - - // -------------------------------------------------------------------- - - /** - * Insert batch statement - * - * Generates a platform-specific insert string from the supplied data. - * - * @param string $table Table name - * @param array $keys INSERT keys - * @param array $values INSERT values - * @return string|bool - */ - protected function _insert_batch($table, $keys, $values) - { - // Multiple-value inserts are only supported as of SQL Server 2008 - if (version_compare($this->version(), '10', '>=')) - { - return parent::_insert_batch($table, $keys, $values); - } - - return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE; - } - -} diff --git a/src/Database/drivers/pdo/subdrivers/pdo_sqlsrv_forge.php b/src/Database/drivers/pdo/subdrivers/pdo_sqlsrv_forge.php deleted file mode 100644 index d9eee8f..0000000 --- a/src/Database/drivers/pdo/subdrivers/pdo_sqlsrv_forge.php +++ /dev/null @@ -1,145 +0,0 @@ - 'SMALLINT', - 'SMALLINT' => 'INT', - 'INT' => 'BIGINT', - 'REAL' => 'FLOAT' - ); - - // -------------------------------------------------------------------- - - /** - * ALTER TABLE - * - * @param string $alter_type ALTER type - * @param string $table Table name - * @param mixed $field Column definition - * @return string|string[] - */ - protected function _alter_table($alter_type, $table, $field) - { - if (in_array($alter_type, array('ADD', 'DROP'), TRUE)) - { - return parent::_alter_table($alter_type, $table, $field); - } - - $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table).' ALTER COLUMN '; - $sqls = array(); - for ($i = 0, $c = count($field); $i < $c; $i++) - { - $sqls[] = $sql.$this->_process_column($field[$i]); - } - - return $sqls; - } - - // -------------------------------------------------------------------- - - /** - * Field attribute TYPE - * - * Performs a data type mapping between different databases. - * - * @param array &$attributes - * @return void - */ - protected function _attr_type(&$attributes) - { - switch (strtoupper($attributes['TYPE'])) - { - case 'MEDIUMINT': - $attributes['TYPE'] = 'INTEGER'; - $attributes['UNSIGNED'] = FALSE; - return; - case 'INTEGER': - $attributes['TYPE'] = 'INT'; - return; - default: return; - } - } - - // -------------------------------------------------------------------- - - /** - * Field attribute AUTO_INCREMENT - * - * @param array &$attributes - * @param array &$field - * @return void - */ - protected function _attr_auto_increment(&$attributes, &$field) - { - if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE && stripos($field['type'], 'int') !== FALSE) - { - $field['auto_increment'] = ' IDENTITY(1,1)'; - } - } - -} diff --git a/src/Database/drivers/postgre/postgre_driver.php b/src/Database/drivers/postgre/postgre_driver.php deleted file mode 100644 index 9acfac2..0000000 --- a/src/Database/drivers/postgre/postgre_driver.php +++ /dev/null @@ -1,622 +0,0 @@ -dsn)) - { - return; - } - - $this->dsn === '' OR $this->dsn = ''; - - if (strpos($this->hostname, '/') !== FALSE) - { - // If UNIX sockets are used, we shouldn't set a port - $this->port = ''; - } - - $this->hostname === '' OR $this->dsn = 'host='.$this->hostname.' '; - - if ( ! empty($this->port) && ctype_digit($this->port)) - { - $this->dsn .= 'port='.$this->port.' '; - } - - if ($this->username !== '') - { - $this->dsn .= 'user='.$this->username.' '; - - /* An empty password is valid! - * - * $db['password'] = NULL must be done in order to ignore it. - */ - $this->password === NULL OR $this->dsn .= "password='".$this->password."' "; - } - - $this->database === '' OR $this->dsn .= 'dbname='.$this->database.' '; - - /* We don't have these options as elements in our standard configuration - * array, but they might be set by parse_url() if the configuration was - * provided via string. Example: - * - * postgre://username:password@localhost:5432/database?connect_timeout=5&sslmode=1 - */ - foreach (array('connect_timeout', 'options', 'sslmode', 'service') as $key) - { - if (isset($this->$key) && is_string($this->key) && $this->key !== '') - { - $this->dsn .= $key."='".$this->key."' "; - } - } - - $this->dsn = rtrim($this->dsn); - } - - // -------------------------------------------------------------------- - - /** - * Database connection - * - * @param bool $persistent - * @return resource - */ - public function db_connect($persistent = FALSE) - { - $this->conn_id = ($persistent === TRUE) - ? pg_pconnect($this->dsn) - : pg_connect($this->dsn); - - if ($this->conn_id !== FALSE) - { - if ($persistent === TRUE - && pg_connection_status($this->conn_id) === PGSQL_CONNECTION_BAD - && pg_ping($this->conn_id) === FALSE - ) - { - return FALSE; - } - - empty($this->schema) OR $this->simple_query('SET search_path TO '.$this->schema.',public'); - } - - return $this->conn_id; - } - - // -------------------------------------------------------------------- - - /** - * Reconnect - * - * Keep / reestablish the db connection if no queries have been - * sent for a length of time exceeding the server's idle timeout - * - * @return void - */ - public function reconnect() - { - if (pg_ping($this->conn_id) === FALSE) - { - $this->conn_id = FALSE; - } - } - - // -------------------------------------------------------------------- - - /** - * Set client character set - * - * @param string $charset - * @return bool - */ - protected function _db_set_charset($charset) - { - return (pg_set_client_encoding($this->conn_id, $charset) === 0); - } - - // -------------------------------------------------------------------- - - /** - * Database version number - * - * @return string - */ - public function version() - { - if (isset($this->data_cache['version'])) - { - return $this->data_cache['version']; - } - - if ( ! $this->conn_id OR ($pg_version = pg_version($this->conn_id)) === FALSE) - { - return FALSE; - } - - /* If PHP was compiled with PostgreSQL lib versions earlier - * than 7.4, pg_version() won't return the server version - * and so we'll have to fall back to running a query in - * order to get it. - */ - return isset($pg_version['server']) - ? $this->data_cache['version'] = $pg_version['server'] - : parent::version(); - } - - // -------------------------------------------------------------------- - - /** - * Execute the query - * - * @param string $sql an SQL query - * @return resource - */ - protected function _execute($sql) - { - return pg_query($this->conn_id, $sql); - } - - // -------------------------------------------------------------------- - - /** - * Begin Transaction - * - * @return bool - */ - protected function _trans_begin() - { - return (bool) pg_query($this->conn_id, 'BEGIN'); - } - - // -------------------------------------------------------------------- - - /** - * Commit Transaction - * - * @return bool - */ - protected function _trans_commit() - { - return (bool) pg_query($this->conn_id, 'COMMIT'); - } - - // -------------------------------------------------------------------- - - /** - * Rollback Transaction - * - * @return bool - */ - protected function _trans_rollback() - { - return (bool) pg_query($this->conn_id, 'ROLLBACK'); - } - - // -------------------------------------------------------------------- - - /** - * Determines if a query is a "write" type. - * - * @param string An SQL query string - * @return bool - */ - public function is_write_type($sql) - { - if (preg_match('#^(INSERT|UPDATE).*RETURNING\s.+(\,\s?.+)*$#i', $sql)) - { - return FALSE; - } - - return parent::is_write_type($sql); - } - - // -------------------------------------------------------------------- - - /** - * Platform-dependant string escape - * - * @param string - * @return string - */ - protected function _escape_str($str) - { - return pg_escape_string($this->conn_id, $str); - } - - // -------------------------------------------------------------------- - - /** - * "Smart" Escape String - * - * Escapes data based on type - * - * @param string $str - * @return mixed - */ - public function escape($str) - { - if (Core::isPHP('5.4.4') && (is_string($str) OR (is_object($str) && method_exists($str, '__toString')))) - { - return pg_escape_literal($this->conn_id, $str); - } - elseif (is_bool($str)) - { - return ($str) ? 'TRUE' : 'FALSE'; - } - - return parent::escape($str); - } - - // -------------------------------------------------------------------- - - /** - * Affected Rows - * - * @return int - */ - public function affected_rows() - { - return pg_affected_rows($this->result_id); - } - - // -------------------------------------------------------------------- - - /** - * Insert ID - * - * @return string - */ - public function insert_id() - { - $v = pg_version($this->conn_id); - $v = isset($v['server']) ? $v['server'] : 0; // 'server' key is only available since PosgreSQL 7.4 - - $table = (func_num_args() > 0) ? func_get_arg(0) : NULL; - $column = (func_num_args() > 1) ? func_get_arg(1) : NULL; - - if ($table === NULL && $v >= '8.1') - { - $sql = 'SELECT LASTVAL() AS ins_id'; - } - elseif ($table !== NULL) - { - if ($column !== NULL && $v >= '8.0') - { - $sql = 'SELECT pg_get_serial_sequence(\''.$table."', '".$column."') AS seq"; - $query = $this->query($sql); - $query = $query->row(); - $seq = $query->seq; - } - else - { - // seq_name passed in table parameter - $seq = $table; - } - - $sql = 'SELECT CURRVAL(\''.$seq."') AS ins_id"; - } - else - { - return pg_last_oid($this->result_id); - } - - $query = $this->query($sql); - $query = $query->row(); - return (int) $query->ins_id; - } - - // -------------------------------------------------------------------- - - /** - * Show table query - * - * Generates a platform-specific query string so that the table names can be fetched - * - * @param bool $prefix_limit - * @return string - */ - protected function _list_tables($prefix_limit = FALSE) - { - $sql = 'SELECT "table_name" FROM "information_schema"."tables" WHERE "table_schema" = \''.$this->schema."'"; - - if ($prefix_limit !== FALSE && $this->dbprefix !== '') - { - return $sql.' AND "table_name" LIKE \'' - .$this->escape_like_str($this->dbprefix)."%' " - .sprintf($this->_like_escape_str, $this->_like_escape_chr); - } - - return $sql; - } - - // -------------------------------------------------------------------- - - /** - * List column query - * - * Generates a platform-specific query string so that the column names can be fetched - * - * @param string $table - * @return string - */ - protected function _list_columns($table = '') - { - return 'SELECT "column_name" - FROM "information_schema"."columns" - WHERE LOWER("table_name") = '.$this->escape(strtolower($table)); - } - - // -------------------------------------------------------------------- - - /** - * Returns an object with field data - * - * @param string $table - * @return array - */ - public function field_data($table) - { - $sql = 'SELECT "column_name", "data_type", "character_maximum_length", "numeric_precision", "column_default" - FROM "information_schema"."columns" - WHERE LOWER("table_name") = '.$this->escape(strtolower($table)); - - if (($query = $this->query($sql)) === FALSE) - { - return FALSE; - } - $query = $query->result_object(); - - $retval = array(); - for ($i = 0, $c = count($query); $i < $c; $i++) - { - $retval[$i] = new stdClass(); - $retval[$i]->name = $query[$i]->column_name; - $retval[$i]->type = $query[$i]->data_type; - $retval[$i]->max_length = ($query[$i]->character_maximum_length > 0) ? $query[$i]->character_maximum_length : $query[$i]->numeric_precision; - $retval[$i]->default = $query[$i]->column_default; - } - - return $retval; - } - - // -------------------------------------------------------------------- - - /** - * Error - * - * Returns an array containing code and message of the last - * database error that has occured. - * - * @return array - */ - public function error() - { - return array('code' => '', 'message' => pg_last_error($this->conn_id)); - } - - // -------------------------------------------------------------------- - - /** - * ORDER BY - * - * @param string $orderby - * @param string $direction ASC, DESC or RANDOM - * @param bool $escape - * @return object - */ - public function order_by($orderby, $direction = '', $escape = NULL) - { - $direction = strtoupper(trim($direction)); - if ($direction === 'RANDOM') - { - if ( ! is_float($orderby) && ctype_digit((string) $orderby)) - { - $orderby = ($orderby > 1) - ? (float) '0.'.$orderby - : (float) $orderby; - } - - if (is_float($orderby)) - { - $this->simple_query('SET SEED '.$orderby); - } - - $orderby = $this->_random_keyword[0]; - $direction = ''; - $escape = FALSE; - } - - return parent::order_by($orderby, $direction, $escape); - } - - // -------------------------------------------------------------------- - - /** - * Update statement - * - * Generates a platform-specific update string from the supplied data - * - * @param string $table - * @param array $values - * @return string - */ - protected function _update($table, $values) - { - $this->qb_limit = FALSE; - $this->qb_orderby = array(); - return parent::_update($table, $values); - } - - // -------------------------------------------------------------------- - - /** - * Update_Batch statement - * - * Generates a platform-specific batch update string from the supplied data - * - * @param string $table Table name - * @param array $values Update data - * @param string $index WHERE key - * @return string - */ - protected function _update_batch($table, $values, $index) - { - $ids = array(); - foreach ($values as $key => $val) - { - $ids[] = $val[$index]; - - foreach (array_keys($val) as $field) - { - if ($field !== $index) - { - $final[$field][] = 'WHEN '.$val[$index].' THEN '.$val[$field]; - } - } - } - - $cases = ''; - foreach ($final as $k => $v) - { - $cases .= $k.' = (CASE '.$index."\n" - .implode("\n", $v)."\n" - .'ELSE '.$k.' END), '; - } - - $this->where($index.' IN('.implode(',', $ids).')', NULL, FALSE); - - return 'UPDATE '.$table.' SET '.substr($cases, 0, -2).$this->_compile_wh('qb_where'); - } - - // -------------------------------------------------------------------- - - /** - * Delete statement - * - * Generates a platform-specific delete string from the supplied data - * - * @param string $table - * @return string - */ - protected function _delete($table) - { - $this->qb_limit = FALSE; - return parent::_delete($table); - } - - // -------------------------------------------------------------------- - - /** - * LIMIT - * - * Generates a platform-specific LIMIT clause - * - * @param string $sql SQL Query - * @return string - */ - protected function _limit($sql) - { - return $sql.' LIMIT '.$this->qb_limit.($this->qb_offset ? ' OFFSET '.$this->qb_offset : ''); - } - - // -------------------------------------------------------------------- - - /** - * Close DB Connection - * - * @return void - */ - protected function _close() - { - pg_close($this->conn_id); - } - -} diff --git a/src/Database/drivers/postgre/postgre_forge.php b/src/Database/drivers/postgre/postgre_forge.php deleted file mode 100644 index 4c7a07f..0000000 --- a/src/Database/drivers/postgre/postgre_forge.php +++ /dev/null @@ -1,205 +0,0 @@ - 'INTEGER', - 'SMALLINT' => 'INTEGER', - 'INT' => 'BIGINT', - 'INT4' => 'BIGINT', - 'INTEGER' => 'BIGINT', - 'INT8' => 'NUMERIC', - 'BIGINT' => 'NUMERIC', - 'REAL' => 'DOUBLE PRECISION', - 'FLOAT' => 'DOUBLE PRECISION' - ); - - /** - * NULL value representation in CREATE/ALTER TABLE statements - * - * @var string - */ - protected $_null = 'NULL'; - - // -------------------------------------------------------------------- - - /** - * Class constructor - * - * @param object &$db Database object - * @return void - */ - public function __construct(&$db) - { - parent::__construct($db); - - if (version_compare($this->db->version(), '9.0', '>')) - { - $this->create_table_if = 'CREATE TABLE IF NOT EXISTS'; - } - } - - // -------------------------------------------------------------------- - - /** - * ALTER TABLE - * - * @param string $alter_type ALTER type - * @param string $table Table name - * @param mixed $field Column definition - * @return string|string[] - */ - protected function _alter_table($alter_type, $table, $field) - { - if (in_array($alter_type, array('DROP', 'ADD'), TRUE)) - { - return parent::_alter_table($alter_type, $table, $field); - } - - $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table); - $sqls = array(); - for ($i = 0, $c = count($field); $i < $c; $i++) - { - if ($field[$i]['_literal'] !== FALSE) - { - return FALSE; - } - - if (version_compare($this->db->version(), '8', '>=') && isset($field[$i]['type'])) - { - $sqls[] = $sql.' ALTER COLUMN '.$this->db->escape_identifiers($field[$i]['name']) - .' TYPE '.$field[$i]['type'].$field[$i]['length']; - } - - if ( ! empty($field[$i]['default'])) - { - $sqls[] = $sql.' ALTER COLUMN '.$this->db->escape_identifiers($field[$i]['name']) - .' SET DEFAULT '.$field[$i]['default']; - } - - if (isset($field[$i]['null'])) - { - $sqls[] = $sql.' ALTER COLUMN '.$this->db->escape_identifiers($field[$i]['name']) - .($field[$i]['null'] === TRUE ? ' DROP NOT NULL' : ' SET NOT NULL'); - } - - if ( ! empty($field[$i]['new_name'])) - { - $sqls[] = $sql.' RENAME COLUMN '.$this->db->escape_identifiers($field[$i]['name']) - .' TO '.$this->db->escape_identifiers($field[$i]['new_name']); - } - - if ( ! empty($field[$i]['comment'])) - { - $sqls[] = 'COMMENT ON COLUMN ' - .$this->db->escape_identifiers($table).'.'.$this->db->escape_identifiers($field[$i]['name']) - .' IS '.$field[$i]['comment']; - } - } - - return $sqls; - } - - // -------------------------------------------------------------------- - - /** - * Field attribute TYPE - * - * Performs a data type mapping between different databases. - * - * @param array &$attributes - * @return void - */ - protected function _attr_type(&$attributes) - { - // Reset field lenghts for data types that don't support it - if (isset($attributes['CONSTRAINT']) && stripos($attributes['TYPE'], 'int') !== FALSE) - { - $attributes['CONSTRAINT'] = NULL; - } - - switch (strtoupper($attributes['TYPE'])) - { - case 'TINYINT': - $attributes['TYPE'] = 'SMALLINT'; - $attributes['UNSIGNED'] = FALSE; - return; - case 'MEDIUMINT': - $attributes['TYPE'] = 'INTEGER'; - $attributes['UNSIGNED'] = FALSE; - return; - default: return; - } - } - - // -------------------------------------------------------------------- - - /** - * Field attribute AUTO_INCREMENT - * - * @param array &$attributes - * @param array &$field - * @return void - */ - protected function _attr_auto_increment(&$attributes, &$field) - { - if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE) - { - $field['type'] = ($field['type'] === 'NUMERIC') - ? 'BIGSERIAL' - : 'SERIAL'; - } - } - -} diff --git a/src/Database/drivers/postgre/postgre_result.php b/src/Database/drivers/postgre/postgre_result.php deleted file mode 100644 index de53d49..0000000 --- a/src/Database/drivers/postgre/postgre_result.php +++ /dev/null @@ -1,182 +0,0 @@ -num_rows) - ? $this->num_rows - : $this->num_rows = pg_num_rows($this->result_id); - } - - // -------------------------------------------------------------------- - - /** - * Number of fields in the result set - * - * @return int - */ - public function num_fields() - { - return pg_num_fields($this->result_id); - } - - // -------------------------------------------------------------------- - - /** - * Fetch Field Names - * - * Generates an array of column names - * - * @return array - */ - public function list_fields() - { - $field_names = array(); - for ($i = 0, $c = $this->num_fields(); $i < $c; $i++) - { - $field_names[] = pg_field_name($this->result_id, $i); - } - - return $field_names; - } - - // -------------------------------------------------------------------- - - /** - * Field data - * - * Generates an array of objects containing field meta-data - * - * @return array - */ - public function field_data() - { - $retval = array(); - for ($i = 0, $c = $this->num_fields(); $i < $c; $i++) - { - $retval[$i] = new stdClass(); - $retval[$i]->name = pg_field_name($this->result_id, $i); - $retval[$i]->type = pg_field_type($this->result_id, $i); - $retval[$i]->max_length = pg_field_size($this->result_id, $i); - } - - return $retval; - } - - // -------------------------------------------------------------------- - - /** - * Free the result - * - * @return void - */ - public function free_result() - { - if (is_resource($this->result_id)) - { - pg_free_result($this->result_id); - $this->result_id = FALSE; - } - } - - // -------------------------------------------------------------------- - - /** - * Data Seek - * - * Moves the internal pointer to the desired offset. We call - * this internally before fetching results to make sure the - * result set starts at zero. - * - * @param int $n - * @return bool - */ - public function data_seek($n = 0) - { - return pg_result_seek($this->result_id, $n); - } - - // -------------------------------------------------------------------- - - /** - * Result - associative array - * - * Returns the result set as an array - * - * @return array - */ - protected function _fetch_assoc() - { - return pg_fetch_assoc($this->result_id); - } - - // -------------------------------------------------------------------- - - /** - * Result - object - * - * Returns the result set as an object - * - * @param string $class_name - * @return object - */ - protected function _fetch_object($class_name = 'stdClass') - { - return pg_fetch_object($this->result_id, NULL, $class_name); - } - -} diff --git a/src/Database/drivers/postgre/postgre_utility.php b/src/Database/drivers/postgre/postgre_utility.php deleted file mode 100644 index 897c366..0000000 --- a/src/Database/drivers/postgre/postgre_utility.php +++ /dev/null @@ -1,78 +0,0 @@ -db->display_error('db_unsupported_feature'); - } -} diff --git a/src/Database/drivers/sqlite/sqlite_driver.php b/src/Database/drivers/sqlite/sqlite_driver.php deleted file mode 100644 index 300648a..0000000 --- a/src/Database/drivers/sqlite/sqlite_driver.php +++ /dev/null @@ -1,332 +0,0 @@ -database, 0666, $error) - : sqlite_open($this->database, 0666, $error); - - isset($error) && Logger::logError($error); - - return $conn_id; - } - - // -------------------------------------------------------------------- - - /** - * Database version number - * - * @return string - */ - public function version() - { - return isset($this->data_cache['version']) - ? $this->data_cache['version'] - : $this->data_cache['version'] = sqlite_libversion(); - } - - // -------------------------------------------------------------------- - - /** - * Execute the query - * - * @param string $sql an SQL query - * @return resource - */ - protected function _execute($sql) - { - return $this->is_write_type($sql) - ? sqlite_exec($this->conn_id, $sql) - : sqlite_query($this->conn_id, $sql); - } - - // -------------------------------------------------------------------- - - /** - * Begin Transaction - * - * @return bool - */ - protected function _trans_begin() - { - return $this->simple_query('BEGIN TRANSACTION'); - } - - // -------------------------------------------------------------------- - - /** - * Commit Transaction - * - * @return bool - */ - protected function _trans_commit() - { - return $this->simple_query('COMMIT'); - } - - // -------------------------------------------------------------------- - - /** - * Rollback Transaction - * - * @return bool - */ - protected function _trans_rollback() - { - return $this->simple_query('ROLLBACK'); - } - - // -------------------------------------------------------------------- - - /** - * Platform-dependant string escape - * - * @param string - * @return string - */ - protected function _escape_str($str) - { - return sqlite_escape_string($str); - } - - // -------------------------------------------------------------------- - - /** - * Affected Rows - * - * @return int - */ - public function affected_rows() - { - return sqlite_changes($this->conn_id); - } - - // -------------------------------------------------------------------- - - /** - * Insert ID - * - * @return int - */ - public function insert_id() - { - return sqlite_last_insert_rowid($this->conn_id); - } - - // -------------------------------------------------------------------- - - /** - * List table query - * - * Generates a platform-specific query string so that the table names can be fetched - * - * @param bool $prefix_limit - * @return string - */ - protected function _list_tables($prefix_limit = FALSE) - { - $sql = "SELECT name FROM sqlite_master WHERE type='table'"; - - if ($prefix_limit !== FALSE && $this->dbprefix != '') - { - return $sql." AND 'name' LIKE '".$this->escape_like_str($this->dbprefix)."%' ".sprintf($this->_like_escape_str, $this->_like_escape_chr); - } - - return $sql; - } - - // -------------------------------------------------------------------- - - /** - * Show column query - * - * Generates a platform-specific query string so that the column names can be fetched - * - * @param string $table - * @return bool - */ - protected function _list_columns($table = '') - { - // Not supported - return FALSE; - } - - // -------------------------------------------------------------------- - - /** - * Returns an object with field data - * - * @param string $table - * @return array - */ - public function field_data($table) - { - if (($query = $this->query('PRAGMA TABLE_INFO('.$this->protect_identifiers($table, TRUE, NULL, FALSE).')')) === FALSE) - { - return FALSE; - } - - $query = $query->result_array(); - if (empty($query)) - { - return FALSE; - } - - $retval = array(); - for ($i = 0, $c = count($query); $i < $c; $i++) - { - $retval[$i] = new stdClass(); - $retval[$i]->name = $query[$i]['name']; - $retval[$i]->type = $query[$i]['type']; - $retval[$i]->max_length = NULL; - $retval[$i]->default = $query[$i]['dflt_value']; - $retval[$i]->primary_key = isset($query[$i]['pk']) ? (int) $query[$i]['pk'] : 0; - } - - return $retval; - } - - // -------------------------------------------------------------------- - - /** - * Error - * - * Returns an array containing code and message of the last - * database error that has occured. - * - * @return array - */ - public function error() - { - $error = array('code' => sqlite_last_error($this->conn_id)); - $error['message'] = sqlite_error_string($error['code']); - return $error; - } - - // -------------------------------------------------------------------- - - /** - * Replace statement - * - * Generates a platform-specific replace string from the supplied data - * - * @param string $table Table name - * @param array $keys INSERT keys - * @param array $values INSERT values - * @return string - */ - protected function _replace($table, $keys, $values) - { - return 'INSERT OR '.parent::_replace($table, $keys, $values); - } - - // -------------------------------------------------------------------- - - /** - * Truncate statement - * - * Generates a platform-specific truncate string from the supplied data - * - * If the database does not support the TRUNCATE statement, - * then this function maps to 'DELETE FROM table' - * - * @param string $table - * @return string - */ - protected function _truncate($table) - { - return 'DELETE FROM '.$table; - } - - // -------------------------------------------------------------------- - - /** - * Close DB Connection - * - * @return void - */ - protected function _close() - { - sqlite_close($this->conn_id); - } - -} diff --git a/src/Database/drivers/sqlite/sqlite_forge.php b/src/Database/drivers/sqlite/sqlite_forge.php deleted file mode 100644 index 700a804..0000000 --- a/src/Database/drivers/sqlite/sqlite_forge.php +++ /dev/null @@ -1,206 +0,0 @@ -db->database) OR ! @unlink($this->db->database)) - { - return ($this->db->db_debug) ? $this->db->display_error('db_unable_to_drop') : FALSE; - } - elseif ( ! empty($this->db->data_cache['db_names'])) - { - $key = array_search(strtolower($this->db->database), array_map('strtolower', $this->db->data_cache['db_names']), TRUE); - if ($key !== FALSE) - { - unset($this->db->data_cache['db_names'][$key]); - } - } - - return TRUE; - } - - // -------------------------------------------------------------------- - - /** - * ALTER TABLE - * - * @todo implement drop_column(), modify_column() - * @param string $alter_type ALTER type - * @param string $table Table name - * @param mixed $field Column definition - * @return string|string[] - */ - protected function _alter_table($alter_type, $table, $field) - { - if ($alter_type === 'DROP' OR $alter_type === 'CHANGE') - { - // drop_column(): - // BEGIN TRANSACTION; - // CREATE TEMPORARY TABLE t1_backup(a,b); - // INSERT INTO t1_backup SELECT a,b FROM t1; - // DROP TABLE t1; - // CREATE TABLE t1(a,b); - // INSERT INTO t1 SELECT a,b FROM t1_backup; - // DROP TABLE t1_backup; - // COMMIT; - - return FALSE; - } - - return parent::_alter_table($alter_type, $table, $field); - } - - // -------------------------------------------------------------------- - - /** - * Process column - * - * @param array $field - * @return string - */ - protected function _process_column($field) - { - return $this->db->escape_identifiers($field['name']) - .' '.$field['type'] - .$field['auto_increment'] - .$field['null'] - .$field['unique'] - .$field['default']; - } - - // -------------------------------------------------------------------- - - /** - * Field attribute TYPE - * - * Performs a data type mapping between different databases. - * - * @param array &$attributes - * @return void - */ - protected function _attr_type(&$attributes) - { - switch (strtoupper($attributes['TYPE'])) - { - case 'ENUM': - case 'SET': - $attributes['TYPE'] = 'TEXT'; - return; - default: return; - } - } - - // -------------------------------------------------------------------- - - /** - * Field attribute AUTO_INCREMENT - * - * @param array &$attributes - * @param array &$field - * @return void - */ - protected function _attr_auto_increment(&$attributes, &$field) - { - if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE && stripos($field['type'], 'int') !== FALSE) - { - $field['type'] = 'INTEGER PRIMARY KEY'; - $field['default'] = ''; - $field['null'] = ''; - $field['unique'] = ''; - $field['auto_increment'] = ' AUTOINCREMENT'; - - $this->primary_keys = array(); - } - } - -} diff --git a/src/Database/drivers/sqlite/sqlite_result.php b/src/Database/drivers/sqlite/sqlite_result.php deleted file mode 100644 index ebf08c7..0000000 --- a/src/Database/drivers/sqlite/sqlite_result.php +++ /dev/null @@ -1,165 +0,0 @@ -num_rows) - ? $this->num_rows - : $this->num_rows = @sqlite_num_rows($this->result_id); - } - - // -------------------------------------------------------------------- - - /** - * Number of fields in the result set - * - * @return int - */ - public function num_fields() - { - return @sqlite_num_fields($this->result_id); - } - - // -------------------------------------------------------------------- - - /** - * Fetch Field Names - * - * Generates an array of column names - * - * @return array - */ - public function list_fields() - { - $field_names = array(); - for ($i = 0, $c = $this->num_fields(); $i < $c; $i++) - { - $field_names[$i] = sqlite_field_name($this->result_id, $i); - } - - return $field_names; - } - - // -------------------------------------------------------------------- - - /** - * Field data - * - * Generates an array of objects containing field meta-data - * - * @return array - */ - public function field_data() - { - $retval = array(); - for ($i = 0, $c = $this->num_fields(); $i < $c; $i++) - { - $retval[$i] = new stdClass(); - $retval[$i]->name = sqlite_field_name($this->result_id, $i); - $retval[$i]->type = NULL; - $retval[$i]->max_length = NULL; - } - - return $retval; - } - - // -------------------------------------------------------------------- - - /** - * Data Seek - * - * Moves the internal pointer to the desired offset. We call - * this internally before fetching results to make sure the - * result set starts at zero. - * - * @param int $n - * @return bool - */ - public function data_seek($n = 0) - { - return sqlite_seek($this->result_id, $n); - } - - // -------------------------------------------------------------------- - - /** - * Result - associative array - * - * Returns the result set as an array - * - * @return array - */ - protected function _fetch_assoc() - { - return sqlite_fetch_array($this->result_id); - } - - // -------------------------------------------------------------------- - - /** - * Result - object - * - * Returns the result set as an object - * - * @param string $class_name - * @return object - */ - protected function _fetch_object($class_name = 'stdClass') - { - return sqlite_fetch_object($this->result_id, $class_name); - } - -} diff --git a/src/Database/drivers/sqlite3/sqlite3_driver.php b/src/Database/drivers/sqlite3/sqlite3_driver.php deleted file mode 100644 index cf0e0fa..0000000 --- a/src/Database/drivers/sqlite3/sqlite3_driver.php +++ /dev/null @@ -1,353 +0,0 @@ -password) - ? new SQLite3($this->database) - : new SQLite3($this->database, SQLITE3_OPEN_READWRITE | SQLITE3_OPEN_CREATE, $this->password); - } - catch (Exception $e) - { - return FALSE; - } - } - - // -------------------------------------------------------------------- - - /** - * Database version number - * - * @return string - */ - public function version() - { - if (isset($this->data_cache['version'])) - { - return $this->data_cache['version']; - } - - $version = SQLite3::version(); - return $this->data_cache['version'] = $version['versionString']; - } - - // -------------------------------------------------------------------- - - /** - * Execute the query - * - * @todo Implement use of SQLite3::querySingle(), if needed - * @param string $sql - * @return mixed SQLite3Result object or bool - */ - protected function _execute($sql) - { - return $this->is_write_type($sql) - ? $this->conn_id->exec($sql) - : $this->conn_id->query($sql); - } - - // -------------------------------------------------------------------- - - /** - * Begin Transaction - * - * @return bool - */ - protected function _trans_begin() - { - return $this->conn_id->exec('BEGIN TRANSACTION'); - } - - // -------------------------------------------------------------------- - - /** - * Commit Transaction - * - * @return bool - */ - protected function _trans_commit() - { - return $this->conn_id->exec('END TRANSACTION'); - } - - // -------------------------------------------------------------------- - - /** - * Rollback Transaction - * - * @return bool - */ - protected function _trans_rollback() - { - return $this->conn_id->exec('ROLLBACK'); - } - - // -------------------------------------------------------------------- - - /** - * Platform-dependant string escape - * - * @param string - * @return string - */ - protected function _escape_str($str) - { - return $this->conn_id->escapeString($str); - } - - // -------------------------------------------------------------------- - - /** - * Affected Rows - * - * @return int - */ - public function affected_rows() - { - return $this->conn_id->changes(); - } - - // -------------------------------------------------------------------- - - /** - * Insert ID - * - * @return int - */ - public function insert_id() - { - return $this->conn_id->lastInsertRowID(); - } - - // -------------------------------------------------------------------- - - /** - * Show table query - * - * Generates a platform-specific query string so that the table names can be fetched - * - * @param bool $prefix_limit - * @return string - */ - protected function _list_tables($prefix_limit = FALSE) - { - return 'SELECT "NAME" FROM "SQLITE_MASTER" WHERE "TYPE" = \'table\'' - .(($prefix_limit !== FALSE && $this->dbprefix != '') - ? ' AND "NAME" LIKE \''.$this->escape_like_str($this->dbprefix).'%\' '.sprintf($this->_like_escape_str, $this->_like_escape_chr) - : ''); - } - - // -------------------------------------------------------------------- - - /** - * Fetch Field Names - * - * @param string $table Table name - * @return array - */ - public function list_fields($table) - { - // Is there a cached result? - if (isset($this->data_cache['field_names'][$table])) - { - return $this->data_cache['field_names'][$table]; - } - - if (($result = $this->query('PRAGMA TABLE_INFO('.$this->protect_identifiers($table, TRUE, NULL, FALSE).')')) === FALSE) - { - return FALSE; - } - - $this->data_cache['field_names'][$table] = array(); - foreach ($result->result_array() as $row) - { - $this->data_cache['field_names'][$table][] = $row['name']; - } - - return $this->data_cache['field_names'][$table]; - } - - // -------------------------------------------------------------------- - - /** - * Returns an object with field data - * - * @param string $table - * @return array - */ - public function field_data($table) - { - if (($query = $this->query('PRAGMA TABLE_INFO('.$this->protect_identifiers($table, TRUE, NULL, FALSE).')')) === FALSE) - { - return FALSE; - } - - $query = $query->result_array(); - if (empty($query)) - { - return FALSE; - } - - $retval = array(); - for ($i = 0, $c = count($query); $i < $c; $i++) - { - $retval[$i] = new stdClass(); - $retval[$i]->name = $query[$i]['name']; - $retval[$i]->type = $query[$i]['type']; - $retval[$i]->max_length = NULL; - $retval[$i]->default = $query[$i]['dflt_value']; - $retval[$i]->primary_key = isset($query[$i]['pk']) ? (int) $query[$i]['pk'] : 0; - } - - return $retval; - } - - // -------------------------------------------------------------------- - - /** - * Error - * - * Returns an array containing code and message of the last - * database error that has occured. - * - * @return array - */ - public function error() - { - return array('code' => $this->conn_id->lastErrorCode(), 'message' => $this->conn_id->lastErrorMsg()); - } - - // -------------------------------------------------------------------- - - /** - * Replace statement - * - * Generates a platform-specific replace string from the supplied data - * - * @param string $table Table name - * @param array $keys INSERT keys - * @param array $values INSERT values - * @return string - */ - protected function _replace($table, $keys, $values) - { - return 'INSERT OR '.parent::_replace($table, $keys, $values); - } - - // -------------------------------------------------------------------- - - /** - * Truncate statement - * - * Generates a platform-specific truncate string from the supplied data - * - * If the database does not support the TRUNCATE statement, - * then this method maps to 'DELETE FROM table' - * - * @param string $table - * @return string - */ - protected function _truncate($table) - { - return 'DELETE FROM '.$table; - } - - // -------------------------------------------------------------------- - - /** - * Close DB Connection - * - * @return void - */ - protected function _close() - { - $this->conn_id->close(); - } - -} diff --git a/src/Database/drivers/sqlite3/sqlite3_forge.php b/src/Database/drivers/sqlite3/sqlite3_forge.php deleted file mode 100644 index 33e7a0d..0000000 --- a/src/Database/drivers/sqlite3/sqlite3_forge.php +++ /dev/null @@ -1,226 +0,0 @@ -db->version(), '3.3', '<')) - { - $this->_create_table_if = FALSE; - $this->_drop_table_if = FALSE; - } - } - - // -------------------------------------------------------------------- - - /** - * Create database - * - * @param string $db_name - * @return bool - */ - public function create_database($db_name = '') - { - // In SQLite, a database is created when you connect to the database. - // We'll return TRUE so that an error isn't generated - return TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Drop database - * - * @param string $db_name (ignored) - * @return bool - */ - public function drop_database($db_name = '') - { - // In SQLite, a database is dropped when we delete a file - if (file_exists($this->db->database)) - { - // We need to close the pseudo-connection first - $this->db->close(); - if ( ! @unlink($this->db->database)) - { - return $this->db->db_debug ? $this->db->display_error('db_unable_to_drop') : FALSE; - } - elseif ( ! empty($this->db->data_cache['db_names'])) - { - $key = array_search(strtolower($this->db->database), array_map('strtolower', $this->db->data_cache['db_names']), TRUE); - if ($key !== FALSE) - { - unset($this->db->data_cache['db_names'][$key]); - } - } - - return TRUE; - } - - return $this->db->db_debug ? $this->db->display_error('db_unable_to_drop') : FALSE; - } - - // -------------------------------------------------------------------- - - /** - * ALTER TABLE - * - * @todo implement drop_column(), modify_column() - * @param string $alter_type ALTER type - * @param string $table Table name - * @param mixed $field Column definition - * @return string|string[] - */ - protected function _alter_table($alter_type, $table, $field) - { - if ($alter_type === 'DROP' OR $alter_type === 'CHANGE') - { - // drop_column(): - // BEGIN TRANSACTION; - // CREATE TEMPORARY TABLE t1_backup(a,b); - // INSERT INTO t1_backup SELECT a,b FROM t1; - // DROP TABLE t1; - // CREATE TABLE t1(a,b); - // INSERT INTO t1 SELECT a,b FROM t1_backup; - // DROP TABLE t1_backup; - // COMMIT; - - return FALSE; - } - - return parent::_alter_table($alter_type, $table, $field); - } - - // -------------------------------------------------------------------- - - /** - * Process column - * - * @param array $field - * @return string - */ - protected function _process_column($field) - { - return $this->db->escape_identifiers($field['name']) - .' '.$field['type'] - .$field['auto_increment'] - .$field['null'] - .$field['unique'] - .$field['default']; - } - - // -------------------------------------------------------------------- - - /** - * Field attribute TYPE - * - * Performs a data type mapping between different databases. - * - * @param array &$attributes - * @return void - */ - protected function _attr_type(&$attributes) - { - switch (strtoupper($attributes['TYPE'])) - { - case 'ENUM': - case 'SET': - $attributes['TYPE'] = 'TEXT'; - return; - default: return; - } - } - - // -------------------------------------------------------------------- - - /** - * Field attribute AUTO_INCREMENT - * - * @param array &$attributes - * @param array &$field - * @return void - */ - protected function _attr_auto_increment(&$attributes, &$field) - { - if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE && stripos($field['type'], 'int') !== FALSE) - { - $field['type'] = 'INTEGER PRIMARY KEY'; - $field['default'] = ''; - $field['null'] = ''; - $field['unique'] = ''; - $field['auto_increment'] = ' AUTOINCREMENT'; - - $this->primary_keys = array(); - } - } - -} diff --git a/src/Database/drivers/sqlite3/sqlite3_result.php b/src/Database/drivers/sqlite3/sqlite3_result.php deleted file mode 100644 index 46688d1..0000000 --- a/src/Database/drivers/sqlite3/sqlite3_result.php +++ /dev/null @@ -1,195 +0,0 @@ -result_id->numColumns(); - } - - // -------------------------------------------------------------------- - - /** - * Fetch Field Names - * - * Generates an array of column names - * - * @return array - */ - public function list_fields() - { - $field_names = array(); - for ($i = 0, $c = $this->num_fields(); $i < $c; $i++) - { - $field_names[] = $this->result_id->columnName($i); - } - - return $field_names; - } - - // -------------------------------------------------------------------- - - /** - * Field data - * - * Generates an array of objects containing field meta-data - * - * @return array - */ - public function field_data() - { - static $data_types = array( - SQLITE3_INTEGER => 'integer', - SQLITE3_FLOAT => 'float', - SQLITE3_TEXT => 'text', - SQLITE3_BLOB => 'blob', - SQLITE3_NULL => 'null' - ); - - $retval = array(); - for ($i = 0, $c = $this->num_fields(); $i < $c; $i++) - { - $retval[$i] = new stdClass(); - $retval[$i]->name = $this->result_id->columnName($i); - - $type = $this->result_id->columnType($i); - $retval[$i]->type = isset($data_types[$type]) ? $data_types[$type] : $type; - - $retval[$i]->max_length = NULL; - } - - return $retval; - } - - // -------------------------------------------------------------------- - - /** - * Free the result - * - * @return void - */ - public function free_result() - { - if (is_object($this->result_id)) - { - $this->result_id->finalize(); - $this->result_id = NULL; - } - } - - // -------------------------------------------------------------------- - - /** - * Result - associative array - * - * Returns the result set as an array - * - * @return array - */ - protected function _fetch_assoc() - { - return $this->result_id->fetchArray(SQLITE3_ASSOC); - } - - // -------------------------------------------------------------------- - - /** - * Result - object - * - * Returns the result set as an object - * - * @param string $class_name - * @return object - */ - protected function _fetch_object($class_name = 'stdClass') - { - // No native support for fetching rows as objects - if (($row = $this->result_id->fetchArray(SQLITE3_ASSOC)) === FALSE) - { - return FALSE; - } - elseif ($class_name === 'stdClass') - { - return (object) $row; - } - - $class_name = new $class_name(); - foreach (array_keys($row) as $key) - { - $class_name->$key = $row[$key]; - } - - return $class_name; - } - - // -------------------------------------------------------------------- - - /** - * Data Seek - * - * Moves the internal pointer to the desired offset. We call - * this internally before fetching results to make sure the - * result set starts at zero. - * - * @param int $n (ignored) - * @return array - */ - public function data_seek($n = 0) - { - // Only resetting to the start of the result set is supported - return ($n > 0) ? FALSE : $this->result_id->reset(); - } - -} diff --git a/src/Database/drivers/sqlsrv/sqlsrv_driver.php b/src/Database/drivers/sqlsrv/sqlsrv_driver.php deleted file mode 100644 index 7849812..0000000 --- a/src/Database/drivers/sqlsrv/sqlsrv_driver.php +++ /dev/null @@ -1,542 +0,0 @@ -scrollable === NULL) - { - $this->scrollable = defined('SQLSRV_CURSOR_CLIENT_BUFFERED') - ? SQLSRV_CURSOR_CLIENT_BUFFERED - : FALSE; - } - } - - // -------------------------------------------------------------------- - - /** - * Database connection - * - * @param bool $pooling - * @return resource - */ - public function db_connect($pooling = FALSE) - { - $charset = in_array(strtolower($this->char_set), array('utf-8', 'utf8'), TRUE) - ? 'UTF-8' : SQLSRV_ENC_CHAR; - - $connection = array( - 'UID' => empty($this->username) ? '' : $this->username, - 'PWD' => empty($this->password) ? '' : $this->password, - 'Database' => $this->database, - 'ConnectionPooling' => ($pooling === TRUE) ? 1 : 0, - 'CharacterSet' => $charset, - 'Encrypt' => ($this->encrypt === TRUE) ? 1 : 0, - 'ReturnDatesAsStrings' => 1 - ); - - // If the username and password are both empty, assume this is a - // 'Windows Authentication Mode' connection. - if (empty($connection['UID']) && empty($connection['PWD'])) - { - unset($connection['UID'], $connection['PWD']); - } - - if (FALSE !== ($this->conn_id = sqlsrv_connect($this->hostname, $connection))) - { - // Determine how identifiers are escaped - $query = $this->query('SELECT CASE WHEN (@@OPTIONS | 256) = @@OPTIONS THEN 1 ELSE 0 END AS qi'); - $query = $query->row_array(); - $this->_quoted_identifier = empty($query) ? FALSE : (bool) $query['qi']; - $this->_escape_char = ($this->_quoted_identifier) ? '"' : array('[', ']'); - } - - return $this->conn_id; - } - - // -------------------------------------------------------------------- - - /** - * Select the database - * - * @param string $database - * @return bool - */ - public function db_select($database = '') - { - if ($database === '') - { - $database = $this->database; - } - - if ($this->_execute('USE '.$this->escape_identifiers($database))) - { - $this->database = $database; - return TRUE; - } - - return FALSE; - } - - // -------------------------------------------------------------------- - - /** - * Execute the query - * - * @param string $sql an SQL query - * @return resource - */ - protected function _execute($sql) - { - return ($this->scrollable === FALSE OR $this->is_write_type($sql)) - ? sqlsrv_query($this->conn_id, $sql) - : sqlsrv_query($this->conn_id, $sql, NULL, array('Scrollable' => $this->scrollable)); - } - - // -------------------------------------------------------------------- - - /** - * Begin Transaction - * - * @return bool - */ - protected function _trans_begin() - { - return sqlsrv_begin_transaction($this->conn_id); - } - - // -------------------------------------------------------------------- - - /** - * Commit Transaction - * - * @return bool - */ - protected function _trans_commit() - { - return sqlsrv_commit($this->conn_id); - } - - // -------------------------------------------------------------------- - - /** - * Rollback Transaction - * - * @return bool - */ - protected function _trans_rollback() - { - return sqlsrv_rollback($this->conn_id); - } - - // -------------------------------------------------------------------- - - /** - * Affected Rows - * - * @return int - */ - public function affected_rows() - { - return sqlsrv_rows_affected($this->result_id); - } - - // -------------------------------------------------------------------- - - /** - * Insert ID - * - * Returns the last id created in the Identity column. - * - * @return string - */ - public function insert_id() - { - return $this->query('SELECT SCOPE_IDENTITY() AS insert_id')->row()->insert_id; - } - - // -------------------------------------------------------------------- - - /** - * Database version number - * - * @return string - */ - public function version() - { - if (isset($this->data_cache['version'])) - { - return $this->data_cache['version']; - } - - if ( ! $this->conn_id OR ($info = sqlsrv_server_info($this->conn_id)) === FALSE) - { - return FALSE; - } - - return $this->data_cache['version'] = $info['SQLServerVersion']; - } - - // -------------------------------------------------------------------- - - /** - * List table query - * - * Generates a platform-specific query string so that the table names can be fetched - * - * @param bool - * @return string $prefix_limit - */ - protected function _list_tables($prefix_limit = FALSE) - { - $sql = 'SELECT '.$this->escape_identifiers('name') - .' FROM '.$this->escape_identifiers('sysobjects') - .' WHERE '.$this->escape_identifiers('type')." = 'U'"; - - if ($prefix_limit === TRUE && $this->dbprefix !== '') - { - $sql .= ' AND '.$this->escape_identifiers('name')." LIKE '".$this->escape_like_str($this->dbprefix)."%' " - .sprintf($this->_escape_like_str, $this->_escape_like_chr); - } - - return $sql.' ORDER BY '.$this->escape_identifiers('name'); - } - - // -------------------------------------------------------------------- - - /** - * List column query - * - * Generates a platform-specific query string so that the column names can be fetched - * - * @param string $table - * @return string - */ - protected function _list_columns($table = '') - { - return 'SELECT COLUMN_NAME - FROM INFORMATION_SCHEMA.Columns - WHERE UPPER(TABLE_NAME) = '.$this->escape(strtoupper($table)); - } - - // -------------------------------------------------------------------- - - /** - * Returns an object with field data - * - * @param string $table - * @return array - */ - public function field_data($table) - { - $sql = 'SELECT COLUMN_NAME, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH, NUMERIC_PRECISION, COLUMN_DEFAULT - FROM INFORMATION_SCHEMA.Columns - WHERE UPPER(TABLE_NAME) = '.$this->escape(strtoupper($table)); - - if (($query = $this->query($sql)) === FALSE) - { - return FALSE; - } - $query = $query->result_object(); - - $retval = array(); - for ($i = 0, $c = count($query); $i < $c; $i++) - { - $retval[$i] = new stdClass(); - $retval[$i]->name = $query[$i]->COLUMN_NAME; - $retval[$i]->type = $query[$i]->DATA_TYPE; - $retval[$i]->max_length = ($query[$i]->CHARACTER_MAXIMUM_LENGTH > 0) ? $query[$i]->CHARACTER_MAXIMUM_LENGTH : $query[$i]->NUMERIC_PRECISION; - $retval[$i]->default = $query[$i]->COLUMN_DEFAULT; - } - - return $retval; - } - - // -------------------------------------------------------------------- - - /** - * Error - * - * Returns an array containing code and message of the last - * database error that has occured. - * - * @return array - */ - public function error() - { - $error = array('code' => '00000', 'message' => ''); - $sqlsrv_errors = sqlsrv_errors(SQLSRV_ERR_ERRORS); - - if ( ! is_array($sqlsrv_errors)) - { - return $error; - } - - $sqlsrv_error = array_shift($sqlsrv_errors); - if (isset($sqlsrv_error['SQLSTATE'])) - { - $error['code'] = isset($sqlsrv_error['code']) ? $sqlsrv_error['SQLSTATE'].'/'.$sqlsrv_error['code'] : $sqlsrv_error['SQLSTATE']; - } - elseif (isset($sqlsrv_error['code'])) - { - $error['code'] = $sqlsrv_error['code']; - } - - if (isset($sqlsrv_error['message'])) - { - $error['message'] = $sqlsrv_error['message']; - } - - return $error; - } - - // -------------------------------------------------------------------- - - /** - * Update statement - * - * Generates a platform-specific update string from the supplied data - * - * @param string $table - * @param array $values - * @return string - */ - protected function _update($table, $values) - { - $this->qb_limit = FALSE; - $this->qb_orderby = array(); - return parent::_update($table, $values); - } - - // -------------------------------------------------------------------- - - /** - * Truncate statement - * - * Generates a platform-specific truncate string from the supplied data - * - * If the database does not support the TRUNCATE statement, - * then this method maps to 'DELETE FROM table' - * - * @param string $table - * @return string - */ - protected function _truncate($table) - { - return 'TRUNCATE TABLE '.$table; - } - - // -------------------------------------------------------------------- - - /** - * Delete statement - * - * Generates a platform-specific delete string from the supplied data - * - * @param string $table - * @return string - */ - protected function _delete($table) - { - if ($this->qb_limit) - { - return 'WITH fw_delete AS (SELECT TOP '.$this->qb_limit.' * FROM '.$table.$this->_compile_wh('qb_where').') DELETE FROM fw_delete'; - } - - return parent::_delete($table); - } - - // -------------------------------------------------------------------- - - /** - * LIMIT - * - * Generates a platform-specific LIMIT clause - * - * @param string $sql SQL Query - * @return string - */ - protected function _limit($sql) - { - // As of SQL Server 2012 (11.0.*) OFFSET is supported - if (version_compare($this->version(), '11', '>=')) - { - // SQL Server OFFSET-FETCH can be used only with the ORDER BY clause - empty($this->qb_orderby) && $sql .= ' ORDER BY 1'; - - return $sql.' OFFSET '.(int) $this->qb_offset.' ROWS FETCH NEXT '.$this->qb_limit.' ROWS ONLY'; - } - - $limit = $this->qb_offset + $this->qb_limit; - - // An ORDER BY clause is required for ROW_NUMBER() to work - if ($this->qb_offset && ! empty($this->qb_orderby)) - { - $orderby = $this->_compile_order_by(); - - // We have to strip the ORDER BY clause - $sql = trim(substr($sql, 0, strrpos($sql, $orderby))); - - // Get the fields to select from our subquery, so that we can avoid FW_rownum appearing in the actual results - if (count($this->qb_select) === 0) - { - $select = '*'; // Inevitable - } - else - { - // Use only field names and their aliases, everything else is out of our scope. - $select = array(); - $field_regexp = ($this->_quoted_identifier) - ? '("[^\"]+")' : '(\[[^\]]+\])'; - for ($i = 0, $c = count($this->qb_select); $i < $c; $i++) - { - $select[] = preg_match('/(?:\s|\.)'.$field_regexp.'$/i', $this->qb_select[$i], $m) - ? $m[1] : $this->qb_select[$i]; - } - $select = implode(', ', $select); - } - - return 'SELECT '.$select." FROM (\n\n" - .preg_replace('/^(SELECT( DISTINCT)?)/i', '\\1 ROW_NUMBER() OVER('.trim($orderby).') AS '.$this->escape_identifiers('FW_rownum').', ', $sql) - ."\n\n) ".$this->escape_identifiers('FW_subquery') - ."\nWHERE ".$this->escape_identifiers('FW_rownum').' BETWEEN '.($this->qb_offset + 1).' AND '.$limit; - } - - return preg_replace('/(^\SELECT (DISTINCT)?)/i','\\1 TOP '.$limit.' ', $sql); - } - - // -------------------------------------------------------------------- - - /** - * Insert batch statement - * - * Generates a platform-specific insert string from the supplied data. - * - * @param string $table Table name - * @param array $keys INSERT keys - * @param array $values INSERT values - * @return string|bool - */ - protected function _insert_batch($table, $keys, $values) - { - // Multiple-value inserts are only supported as of SQL Server 2008 - if (version_compare($this->version(), '10', '>=')) - { - return parent::_insert_batch($table, $keys, $values); - } - - return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE; - } - - // -------------------------------------------------------------------- - - /** - * Close DB Connection - * - * @return void - */ - protected function _close() - { - sqlsrv_close($this->conn_id); - } - -} diff --git a/src/Database/drivers/sqlsrv/sqlsrv_forge.php b/src/Database/drivers/sqlsrv/sqlsrv_forge.php deleted file mode 100644 index 66e580e..0000000 --- a/src/Database/drivers/sqlsrv/sqlsrv_forge.php +++ /dev/null @@ -1,145 +0,0 @@ - 'SMALLINT', - 'SMALLINT' => 'INT', - 'INT' => 'BIGINT', - 'REAL' => 'FLOAT' - ); - - // -------------------------------------------------------------------- - - /** - * ALTER TABLE - * - * @param string $alter_type ALTER type - * @param string $table Table name - * @param mixed $field Column definition - * @return string|string[] - */ - protected function _alter_table($alter_type, $table, $field) - { - if (in_array($alter_type, array('ADD', 'DROP'), TRUE)) - { - return parent::_alter_table($alter_type, $table, $field); - } - - $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table).' ALTER COLUMN '; - $sqls = array(); - for ($i = 0, $c = count($field); $i < $c; $i++) - { - $sqls[] = $sql.$this->_process_column($field[$i]); - } - - return $sqls; - } - - // -------------------------------------------------------------------- - - /** - * Field attribute TYPE - * - * Performs a data type mapping between different databases. - * - * @param array &$attributes - * @return void - */ - protected function _attr_type(&$attributes) - { - switch (strtoupper($attributes['TYPE'])) - { - case 'MEDIUMINT': - $attributes['TYPE'] = 'INTEGER'; - $attributes['UNSIGNED'] = FALSE; - return; - case 'INTEGER': - $attributes['TYPE'] = 'INT'; - return; - default: return; - } - } - - // -------------------------------------------------------------------- - - /** - * Field attribute AUTO_INCREMENT - * - * @param array &$attributes - * @param array &$field - * @return void - */ - protected function _attr_auto_increment(&$attributes, &$field) - { - if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE && stripos($field['type'], 'int') !== FALSE) - { - $field['auto_increment'] = ' IDENTITY(1,1)'; - } - } - -} diff --git a/src/Database/drivers/sqlsrv/sqlsrv_result.php b/src/Database/drivers/sqlsrv/sqlsrv_result.php deleted file mode 100644 index 4bbef3c..0000000 --- a/src/Database/drivers/sqlsrv/sqlsrv_result.php +++ /dev/null @@ -1,194 +0,0 @@ -scrollable = $driver_object->scrollable; - } - - // -------------------------------------------------------------------- - - /** - * Number of rows in the result set - * - * @return int - */ - public function num_rows() - { - // sqlsrv_num_rows() doesn't work with the FORWARD and DYNAMIC cursors (FALSE is the same as FORWARD) - if ( ! in_array($this->scrollable, array(FALSE, SQLSRV_CURSOR_FORWARD, SQLSRV_CURSOR_DYNAMIC), TRUE)) - { - return parent::num_rows(); - } - - return is_int($this->num_rows) - ? $this->num_rows - : $this->num_rows = sqlsrv_num_rows($this->result_id); - } - - // -------------------------------------------------------------------- - - /** - * Number of fields in the result set - * - * @return int - */ - public function num_fields() - { - return @sqlsrv_num_fields($this->result_id); - } - - // -------------------------------------------------------------------- - - /** - * Fetch Field Names - * - * Generates an array of column names - * - * @return array - */ - public function list_fields() - { - $field_names = array(); - foreach (sqlsrv_field_metadata($this->result_id) as $offset => $field) - { - $field_names[] = $field['Name']; - } - - return $field_names; - } - - // -------------------------------------------------------------------- - - /** - * Field data - * - * Generates an array of objects containing field meta-data - * - * @return array - */ - public function field_data() - { - $retval = array(); - foreach (sqlsrv_field_metadata($this->result_id) as $i => $field) - { - $retval[$i] = new stdClass(); - $retval[$i]->name = $field['Name']; - $retval[$i]->type = $field['Type']; - $retval[$i]->max_length = $field['Size']; - } - - return $retval; - } - - // -------------------------------------------------------------------- - - /** - * Free the result - * - * @return void - */ - public function free_result() - { - if (is_resource($this->result_id)) - { - sqlsrv_free_stmt($this->result_id); - $this->result_id = FALSE; - } - } - - // -------------------------------------------------------------------- - - /** - * Result - associative array - * - * Returns the result set as an array - * - * @return array - */ - protected function _fetch_assoc() - { - return sqlsrv_fetch_array($this->result_id, SQLSRV_FETCH_ASSOC); - } - - // -------------------------------------------------------------------- - - /** - * Result - object - * - * Returns the result set as an object - * - * @param string $class_name - * @return object - */ - protected function _fetch_object($class_name = 'stdClass') - { - return sqlsrv_fetch_object($this->result_id, $class_name); - } - -} diff --git a/src/Database/drivers/sqlsrv/sqlsrv_utility.php b/src/Database/drivers/sqlsrv/sqlsrv_utility.php deleted file mode 100644 index 998c424..0000000 --- a/src/Database/drivers/sqlsrv/sqlsrv_utility.php +++ /dev/null @@ -1,78 +0,0 @@ -db->display_error('db_unsupported_feature'); - } - -} diff --git a/src/FuzeWorks/Database.php b/src/FuzeWorks/Database.php index 988817a..ca1a478 100644 --- a/src/FuzeWorks/Database.php +++ b/src/FuzeWorks/Database.php @@ -35,10 +35,11 @@ */ namespace FuzeWorks; +use FuzeWorks\DatabaseEngine\iDatabaseEngine; +use FuzeWorks\DatabaseEngine\PDOEngine; +use FuzeWorks\Event\DatabaseLoadDriverEvent; use FuzeWorks\Exception\DatabaseException; -use FW_DB; -use FW_DB_forge; -use FW_DB_utility; +use FuzeWorks\Exception\EventException; /** * Database loading class @@ -51,238 +52,189 @@ use FW_DB_utility; */ class Database { - + /** - * The default database forge. - * @var FW_DB|null + * Current database config as found the database config file with highest priority + * + * @var array */ - protected static $defaultDB = null; + protected $dbConfig; + + /** + * All engines that can be used for databases + * + * @var iDatabaseEngine[] + */ + protected $engines = []; + + /** + * Whether all DatabaseEngines have been loaded yet + * + * @var bool + */ + protected $enginesLoaded = false; /** * Array of all the non-default databases - * @var array FW_DB|null + * + * @var iDatabaseEngine[] */ - protected static $databases = array(); - - /** - * The default database forge. - * @var FW_DB_forge|null - */ - protected static $defaultForge = null; - - /** - * Array of all the non-default databases forges. - * @var array FW_DB_forge|null - */ - protected static $forges = array(); - - /** - * The default database utility. - * @var FW_DB_utility|null - */ - protected static $defaultUtil = null; + protected $connections = []; /** * Register with the TracyBridge upon startup */ - public function __construct() + public function init() { + $this->dbConfig = Factory::getInstance()->config->get('database')->toArray(); + if (class_exists('Tracy\Debugger', true)) - { DatabaseTracyBridge::register(); - } } /** - * Retrieve a database using a DSN or the default configuration. - * - * If a string is provided like this: 'dbdriver://username:password@hostname/database', - * the string will be interpreted and converted into a database connection parameter array. - * - * If a string is provided with a name, like this: 'default' the 'default' connection from the - * configuration file will be loaded. If no string is provided the default database will be loaded. - * - * If the $newInstance is a true boolean, a new instance will be loaded instead of loading the - * default one. $newInstance will also make sure that the loaded database is not default one. - * This behaviour will be changed in the future. - * - * - * If $queryBuilder = false is provided, the database will load without a queryBuilder. - * By default the queryBuilder will load. - * - * @param string $parameters - * @param bool $newInstance - * @param bool $queryBuilder - * @return FW_DB|bool - * @throws DatabaseException - * @throws Exception\EventException + * Close connections when shutting down FuzeWorks */ - public static function get($parameters = '', $newInstance = false, $queryBuilder = null) + public function __destruct() + { + foreach ($this->connections as $connection) + $connection->tearDown(); + } + + /** + * + * When providing a database using the databaseLoadDriverEvent, parameters and connectionName + * will be ignored. + * + * @param string $connectionName + * @param string $engineName + * @param array $parameters + * @return iDatabaseEngine + * @throws DatabaseException + * @throws EventException + */ + public function get(string $connectionName = 'default', string $engineName = '', array $parameters = []): iDatabaseEngine { // Fire the event to allow settings to be changed - $event = Events::fireEvent('databaseLoadDriverEvent', $parameters, $newInstance, $queryBuilder); + /** @var DatabaseLoadDriverEvent $event */ + $event = Events::fireEvent('databaseLoadDriverEvent', strtolower($engineName), $parameters, $connectionName); if ($event->isCancelled()) - { - return false; - } + throw new DatabaseException("Could not get database. Cancelled by databaseLoadDriverEvent."); - // If an instance already exists and is requested, return it - if (isset($event->database) && empty($event->parameters)) + /** @var iDatabaseEngine $engine */ + // If a databaseEngine is provided by the event, use that. Otherwise search in the list of engines + if (is_object($event->databaseEngine) && $event->databaseEngine instanceof iDatabaseEngine) { - return self::$defaultDB = $event->database; + // Do intervention first + $engine = $this->connections[$event->connectionName] = $event->databaseEngine; + if (!$engine->isSetup()) + $engine->setUp($event->parameters); } - elseif (isset($event->database) && !empty($event->parameters)) + elseif (isset($this->connections[$event->connectionName])) { - return self::$databases[$event->parameters] = $event->database; + // Do already exists second + $engine = $this->connections[$event->connectionName]; } - elseif (empty($event->parameters) && !$event->newInstance && is_object(self::$defaultDB) && ! empty(self::$defaultDB->conn_id)) + elseif (!empty($event->engineName) && !empty($event->parameters)) { - return $reference = self::$defaultDB; - } - elseif (!empty($event->parameters) && !$event->newInstance && isset(self::$databases[$event->parameters])) - { - return $reference = self::$databases[$event->parameters]; - } - - // If a new instance is required, load it - require_once (dirname(__DIR__) . DS . 'Database'.DS.'DB.php'); - - if ($event->newInstance === TRUE) - { - $database = DB($event->parameters, $event->queryBuilder); - } - elseif (empty($event->parameters) && $event->newInstance === FALSE) - { - $database = self::$defaultDB = DB($event->parameters, $event->queryBuilder); + // Do provided config third + $engineClass = get_class($this->getEngine($event->engineName)); + $engine = $this->connections[$event->connectionName] = new $engineClass(); + $engine->setUp($event->parameters); } else { - $database = self::$databases[$event->parameters] = DB($event->parameters, $event->queryBuilder); + // Do external config fourth + if (!isset($this->dbConfig['connections'][$event->connectionName])) + throw new DatabaseException("Could not get database. Database not found in config."); + + $engineName = $this->dbConfig['connections'][$event->connectionName]['engineName']; + $engineClass = get_class($this->getEngine($engineName)); + $engine = $this->connections[$event->connectionName] = new $engineClass(); + $engine->setUp($this->dbConfig['connections'][$event->connectionName]); } // Tie it into the Tracy Bar if available if (class_exists('\Tracy\Debugger', true)) - { - DatabaseTracyBridge::registerDatabase($database); - } + DatabaseTracyBridge::registerDatabase($engine); - return $database; + return $engine; } /** - * Retrieves a database forge from the provided or default database. + * Get a loaded database engine. * - * If no database is provided, the default database will be used. - * - * @param FW_DB|null $database - * @param bool $newInstance - * @return FW_DB_forge + * @param string $engineName + * @return iDatabaseEngine * @throws DatabaseException - * @throws Exception\EventException */ - public static function getForge($database = null, $newInstance = false) + public function getEngine(string $engineName): iDatabaseEngine { - // Fire the event to allow settings to be changed - $event = Events::fireEvent('databaseLoadForgeEvent', $database, $newInstance); - if ($event->isCancelled()) - { - return false; - } + // First retrieve the name + $engineName = strtolower($engineName); - // First check if we're talking about the default forge and that one is already set - if (is_object($event->forge) && ($event->forge instanceof FW_DB_forge) ) - { - return $event->forge; - } - elseif (is_object($event->database) && $event->database === self::$defaultDB && is_object(self::$defaultForge)) - { - return $reference = self::$defaultForge; - } - elseif ( ! is_object($event->database) OR ! ($event->database instanceof FW_DB)) - { - isset(self::$defaultDB) OR self::get('', false); - $database =& self::$defaultDB; - } + // Then load all engines + $this->loadDatabaseEngines(); - require_once (dirname(__DIR__) . DS . 'Database'.DS.'DB_forge.php'); - require_once(dirname(__DIR__) . DS . 'Database'.DS.'drivers'.DS.$database->dbdriver.DS.$database->dbdriver.'_forge.php'); + // If the engine exists, return it + if (isset($this->engines[$engineName])) + return $this->engines[$engineName]; - if ( ! empty($database->subdriver)) - { - $driver_path = dirname(__DIR__) . DS . 'Database'.DS.'drivers'.DS.$database->dbdriver.DS.'subdrivers'.DS.$database->dbdriver.'_'.$database->subdriver.'_forge.php'; - if (file_exists($driver_path)) - { - require_once($driver_path); - $class = 'FW_DB_'.$database->dbdriver.'_'.$database->subdriver.'_forge'; - } - else - { - throw new DatabaseException("Could not load forge. Driver file does not exist.", 1); - } - } - else - { - $class = 'FW_DB_'.$database->dbdriver.'_forge'; - } - - // Create a new instance of set the default database - if ($event->newInstance) - { - return new $class($database); - } - else - { - return self::$defaultForge = new $class($database); - } + // Otherwise throw exception + throw new DatabaseException("Could not get engine. Engine does not exist."); } /** - * Retrieves a database utility from the provided or default database. + * Register a new database engine * - * If no database is provided, the default database will be used. - * - * @param FW_DB|null $database - * @param bool $newInstance - * @return FW_DB_utility + * @param iDatabaseEngine $databaseEngine + * @return bool * @throws DatabaseException - * @throws Exception\EventException */ - public static function getUtil($database = null, $newInstance = false) + public function registerEngine(iDatabaseEngine $databaseEngine): bool { - // Fire the event to allow settings to be changed - $event = Events::fireEvent('databaseLoadUtilEvent', $database, $newInstance); - if ($event->isCancelled()) - { - return false; - } + // First retrieve the name + $engineName = strtolower($databaseEngine->getName()); - // First check if we're talking about the default util and that one is already set - if (is_object($event->util) && ($event->util instanceof FW_DB_utility)) - { - return $event->util; - } - elseif (is_object($event->database) && $event->database === self::$defaultDB && is_object(self::$defaultUtil)) - { - return $reference = self::$defaultUtil; - } + // Check if the engine is already set + if (isset($this->engines[$engineName])) + throw new DatabaseException("Could not register engine. Engine '".$engineName."' already registered."); - if ( ! is_object($event->database) OR ! ($event->database instanceof FW_DB)) - { - isset(self::$defaultDB) OR self::get('', false); - $database = & self::$defaultDB; - } - require_once (dirname(__DIR__) . DS . 'Database'.DS.'DB_utility.php'); - require_once(dirname(__DIR__) . DS . 'Database'.DS.'drivers'.DS.$database->dbdriver.DS.$database->dbdriver.'_utility.php'); - $class = 'FW_DB_'.$database->dbdriver.'_utility'; + // Install it + $this->engines[$engineName] = $databaseEngine; + Logger::log("Registered Database Engine: '" . $engineName . "'"); - if ($event->newInstance) - { - return new $class($database); - } - else - { - return self::$defaultUtil = new $class($database); - } + return true; } + + /** + * Load all databaseEngines by firing a databaseLoadEngineEvent and by loading all the default engines + * + * @return bool + * @throws DatabaseException + */ + protected function loadDatabaseEngines(): bool + { + // If already loaded, skip + if ($this->enginesLoaded) + return false; + + // Fire engine event + try { + Events::fireEvent('databaseLoadEngineEvent'); + } catch (EventException $e) { + throw new DatabaseException("Could not load database engines. databaseLoadEngineEvent threw exception: '" . $e->getMessage() . "'"); + } + + // Load the engines provided by the DatabaseComponent + $this->registerEngine(new PDOEngine()); + + // And save results + $this->enginesLoaded = true; + return true; + } + + + } \ No newline at end of file diff --git a/src/FuzeWorks/DatabaseComponent.php b/src/FuzeWorks/DatabaseComponent.php index 14b8977..53ac865 100644 --- a/src/FuzeWorks/DatabaseComponent.php +++ b/src/FuzeWorks/DatabaseComponent.php @@ -47,10 +47,29 @@ namespace FuzeWorks; class DatabaseComponent implements iComponent { + public function getName(): string + { + return "DatabaseComponent"; + } + public function getClasses(): array { return [ - 'database' => '\FuzeWorks\Database' + 'databases' => '\FuzeWorks\Database' ]; } + + public function onAddComponent(Configurator $configurator) + { + // Add fallback database config + $configurator->addDirectory( + dirname(__DIR__) . DIRECTORY_SEPARATOR . 'Config', + 'config', + Priority::LOWEST + ); + } + + public function onCreateContainer(Factory $container) + { + } } \ No newline at end of file diff --git a/src/Database/drivers/odbc/odbc_forge.php b/src/FuzeWorks/DatabaseEngine/DatabaseDriver.php similarity index 50% rename from src/Database/drivers/odbc/odbc_forge.php rename to src/FuzeWorks/DatabaseEngine/DatabaseDriver.php index a7e89f0..5cc1047 100644 --- a/src/Database/drivers/odbc/odbc_forge.php +++ b/src/FuzeWorks/DatabaseEngine/DatabaseDriver.php @@ -1,10 +1,10 @@ queries[] = [ + 'queryString' => $queryString, + 'queryData' => $queryData, + 'queryTimings' => $queryTimings, + 'queryError' => $queryError + ]; + } + + /** + * Get all performed queries and logged data + * + * @return array + */ + public function getQueries() + { + return $this->queries; + } + + // -------------------------------------------------------------------- - // -------------------------------------------------------------------- - /** - * Field attribute AUTO_INCREMENT - * - * @param array &$attributes - * @param array &$field - * @return void - */ - protected function _attr_auto_increment(&$attributes, &$field) - { - // Not supported (in most databases at least) - } } diff --git a/src/FuzeWorks/DatabaseEngine/PDOEngine.php b/src/FuzeWorks/DatabaseEngine/PDOEngine.php new file mode 100644 index 0000000..17a2fbb --- /dev/null +++ b/src/FuzeWorks/DatabaseEngine/PDOEngine.php @@ -0,0 +1,329 @@ +setUp; + } + + /** + * Method called by \FuzeWorks\Database to setUp the database connection + * + * @param array $parameters + * @return bool + * @throws DatabaseException + */ + public function setUp(array $parameters): bool + { + // Prepare variables for connection + $dsn = isset($parameters['dsn']) ? $parameters['dsn'] : null; + $username = isset($parameters['username']) ? $parameters['username'] : ''; + $password = isset($parameters['password']) ? $parameters['password'] : ''; + + // Don't attempt connection without DSN + if (is_null($dsn)) + throw new DatabaseException("Could not setUp PDOEngine. No DSN provided"); + + // Attempt to connect. Throw exception on failure + try { + $this->pdoConnection = new PDO($dsn, $username, $password, $parameters); + } catch (PDOException $e) { + throw new DatabaseException("Could not setUp PDOEngine. PDO threw PDOException: '" . $e->getMessage() . "'"); + } + + // Set this engine as set up + $this->setUp = true; + + // And return true upon success + return true; + } + + /** + * Method called by \FuzeWorks\Database to tear down the database connection upon shutdown + * + * @return bool + */ + public function tearDown(): bool + { + // Commit or rollback all changes to the database + $this->transactionEnd(); + + // + $this->pdoConnection = null; + return true; + } + + /** + * Call methods on the PDO Connection + * + * @param $name + * @param $arguments + * @return mixed + */ + public function __call($name, $arguments) + { + return $this->pdoConnection->{$name}(...$arguments); + } + + /** + * Get properties from the PDO Connection + * + * @param $name + * @return mixed + */ + public function __get($name) + { + return $this->pdoConnection->$name; + } + + /** + * Set properties on the PDO Connection + * + * @param $name + * @param $value + * @return mixed + */ + public function __set($name, $value) + { + return $this->pdoConnection->$name = $value; + } + + /** + * Internal method used to report queries by the \FuzeWorks\DatabaseEngine\PDOStatement + * + * @internal + * @param string $queryString + * @param array $queryData + * @param float $queryTimings + */ + public function logPDOQuery(string $queryString, array $queryData, float $queryTimings) + { + $this->logQuery($queryString, $queryData, $queryTimings, $this->error()); + } + + /** + * Perform a query with the database. Only supports queries. + * + * Should only be used for reading data without dynamic statements. + * + * @param string $sql + * @return PDOStatement + * @throws DatabaseException + */ + public function query(string $sql): PDOStatement + { + if (empty($sql)) + throw new DatabaseException("Could not run query. Provided query is empty."); + + // Run the query and benchmark the time + $benchmarkStart = microtime(true); + $result = $this->pdoConnection->query($sql); + $benchmarkEnd = microtime(true) - $benchmarkStart; + + // Log the query + $this->logPDOQuery($sql, [], $benchmarkEnd); + + // If the query failed, handle the error + if ($result === false) + { + // Mark the transaction as failed + $this->transactionFailed = true; + + // And throw an exception + throw new DatabaseException("Could not run query. Database returned an error. Error code: " . $this->error()['code']); + } + + return $result; + } + + /** + * Create a PDOStatement to alter data on the database. + * + * @param string $statement + * @param array $driver_options + * @return PDOStatementWrapper + */ + public function prepare(string $statement, array $driver_options = []): PDOStatementWrapper + { + return new PDOStatementWrapper( + $this->pdoConnection->prepare($statement, $driver_options), + array($this, 'logPDOQuery') + ); + } + + /** + * Generates an error message for the last failure in PDO + * + * @return array + */ + protected function error(): array + { + $error = ['code' => '00000', 'message' => '']; + $pdoError = $this->pdoConnection->errorInfo(); + if (empty($pdoError[0])) + return $error; + + $error['code'] = isset($pdoError[1]) ? $pdoError[0] . '/' . $pdoError[1] : $pdoError[0]; + if (isset($pdoError[2])) + $error['message'] = $pdoError[2]; + + return $error; + } + + /** + * Start a transaction + * + * @return bool + */ + public function transactionStart(): bool + { + return $this->pdoConnection->beginTransaction(); + } + + /** + * End a transaction. + * + * Only runs of autocommit is enabled; and a transaction is running. + * Automatically rolls back changes if an error occurs with a query + * + * @return bool + */ + public function transactionEnd(): bool + { + // If autocommit is disabled, don't do anything + if (!$this->transactionAutocommit) + return false; + + // If there is no transaction, there is nothing to rollback + if (!$this->pdoConnection->inTransaction()) + return false; + + // If a transaction has failed, it should be rolled back + if ($this->transactionFailed === true) + { + $this->transactionRollback(); + Logger::logError("PDOEngine transaction failed. Transaction has been rolled back."); + } + + return $this->transactionCommit(); + } + + /** + * Commit a transaction + * + * @return bool + */ + public function transactionCommit(): bool + { + return $this->pdoConnection->commit(); + } + + /** + * Roll back a transaction + * + * @return bool + */ + public function transactionRollback(): bool + { + return $this->pdoConnection->rollBack(); + } +} \ No newline at end of file diff --git a/src/FuzeWorks/DatabaseEngine/PDOStatementWrapper.php b/src/FuzeWorks/DatabaseEngine/PDOStatementWrapper.php new file mode 100644 index 0000000..25827aa --- /dev/null +++ b/src/FuzeWorks/DatabaseEngine/PDOStatementWrapper.php @@ -0,0 +1,110 @@ +statement = $statement; + $this->logQueryCallable = $logQueryCallable; + } + + public function execute(array $input_parameters = null) + { + // Run the query and benchmark the time + $benchmarkStart = microtime(true); + $result = $this->statement->execute($input_parameters); + $benchmarkEnd = microtime(true) - $benchmarkStart; + call_user_func_array($this->logQueryCallable, [$this->statement->queryString, $input_parameters, $benchmarkEnd]); + + // If the query failed, throw an error + if ($result === false) + { + // And throw an exception + throw new DatabaseException("Could not run query. Database returned an error. Error code: " . $this->error()['code']); + } + + return $result; + } + + /** + * Generates an error message for the last failure in PDO + * + * @return array + */ + private function error(): array + { + $error = ['code' => '00000', 'message' => '']; + $pdoError = $this->statement->errorInfo(); + if (empty($pdoError[0])) + return $error; + + $error['code'] = isset($pdoError[1]) ? $pdoError[0] . '/' . $pdoError[1] : $pdoError[0]; + if (isset($pdoError[2])) + $error['message'] = $pdoError[2]; + + return $error; + } + + public function __call($method, $parameters) + { + return call_user_func_array([$this->statement, $method], $parameters); + } + + public function __get($name) + { + return $this->statement->$name; + } + +} \ No newline at end of file diff --git a/src/Database/drivers/pdo/pdo_forge.php b/src/FuzeWorks/DatabaseEngine/iDatabaseEngine.php similarity index 64% rename from src/Database/drivers/pdo/pdo_forge.php rename to src/FuzeWorks/DatabaseEngine/iDatabaseEngine.php index bb1bb4e..48fd110 100644 --- a/src/Database/drivers/pdo/pdo_forge.php +++ b/src/FuzeWorks/DatabaseEngine/iDatabaseEngine.php @@ -1,10 +1,10 @@ query_data[$key]['error']['code'] != 0) - { $results['errorsFound'] = true; - } } } diff --git a/src/FuzeWorks/Event/DatabaseLoadDriverEvent.php b/src/FuzeWorks/Event/DatabaseLoadDriverEvent.php index d1eb348..9ee106e 100644 --- a/src/FuzeWorks/Event/DatabaseLoadDriverEvent.php +++ b/src/FuzeWorks/Event/DatabaseLoadDriverEvent.php @@ -32,6 +32,7 @@ namespace FuzeWorks\Event; +use FuzeWorks\DatabaseEngine\iDatabaseEngine; use FuzeWorks\Event; /** @@ -51,35 +52,35 @@ class DatabaseLoadDriverEvent extends Event * the parameters variable is empty. If there is a string in parameters this database shall be identified as * such. * - * @var FW_DB|null + * @var iDatabaseEngine|null */ - public $database = null; + public $databaseEngine = null; + + /** + * The name of the engine to be loaded + * + * @var string + */ + public $engineName; /** * Parameters of the database to be loaded * - * @var string + * @var array */ public $parameters; /** - * Whether a database instance shall be cloned if existing + * Database group to load * * @var bool */ - public $newInstance; + public $connectionName; - /** - * Whether to attach the queryBuilder to the database driver - * - * @var null|bool - */ - public $queryBuilder; - - public function init($parameters = '', $newInstance = false, $queryBuilder = null) + public function init(string $engineName, array $parameters, string $connectionName) { + $this->engineName = $engineName; $this->parameters = $parameters; - $this->newInstance = $newInstance; - $this->queryBuilder = $queryBuilder; + $this->connectionName = $connectionName; } } diff --git a/src/FuzeWorks/Event/DatabaseLoadForgeEvent.php b/src/FuzeWorks/Event/DatabaseLoadForgeEvent.php deleted file mode 100644 index ed22ef6..0000000 --- a/src/FuzeWorks/Event/DatabaseLoadForgeEvent.php +++ /dev/null @@ -1,77 +0,0 @@ -. - * - * @author TechFuze - * @copyright Copyright (c) 2013 - 2017, TechFuze. (http://techfuze.net) - * @copyright Copyright (c) 1996 - 2015, Free Software Foundation, Inc. (http://www.fsf.org/) - * @license http://opensource.org/licenses/GPL-3.0 GPLv3 License - * - * @link http://techfuze.net/fuzeworks - * @since Version 1.0.4 - * - * @version Version 1.0.4 - */ - -namespace FuzeWorks\Event; - -use FuzeWorks\Event; - -/** - * Event that gets loaded when a database forge is loaded - * - * Use this to cancel the loading of a forge, or change the provided database - * - * @author Abel Hoogeveen - * @copyright Copyright (c) 2013 - 2017, TechFuze. (http://techfuze.net) - */ -class DatabaseLoadForgeEvent extends Event -{ - /** - * A possible forge that can be loaded. - * - * Provide a forge in this variable and it will be loaded. - * - * @var FW_DB_forge|null - */ - public $forge = null; - - /** - * Database to be used by the forge. - * - * If no database is provided, FuzeWorks\Database shall provide the default database - * - * @var FW_DB|null - */ - public $database = null; - - /** - * Whether a database instance shall be cloned if existing - * - * @var bool - */ - public $newInstance; - - public function init($database = null, $newInstance = false) - { - $this->database = $database; - $this->newInstance = $newInstance; - } -} diff --git a/src/FuzeWorks/Event/DatabaseLoadUtilEvent.php b/src/FuzeWorks/Event/DatabaseLoadUtilEvent.php deleted file mode 100644 index 174f2e4..0000000 --- a/src/FuzeWorks/Event/DatabaseLoadUtilEvent.php +++ /dev/null @@ -1,77 +0,0 @@ -. - * - * @author TechFuze - * @copyright Copyright (c) 2013 - 2017, TechFuze. (http://techfuze.net) - * @copyright Copyright (c) 1996 - 2015, Free Software Foundation, Inc. (http://www.fsf.org/) - * @license http://opensource.org/licenses/GPL-3.0 GPLv3 License - * - * @link http://techfuze.net/fuzeworks - * @since Version 1.0.4 - * - * @version Version 1.0.4 - */ - -namespace FuzeWorks\Event; - -use FuzeWorks\Event; - -/** - * Event that gets loaded when a database utility is loaded - * - * Use this to cancel the loading of a util, or change the provided database - * - * @author Abel Hoogeveen - * @copyright Copyright (c) 2013 - 2017, TechFuze. (http://techfuze.net) - */ -class DatabaseLoadUtilEvent extends Event -{ - /** - * A possible util that can be loaded. - * - * Provide a util in this variable and it will be loaded. - * - * @var FW_DB_util|null - */ - public $util = null; - - /** - * Database to be used by the util. - * - * If no database is provided, FuzeWorks\Database shall provide the default database - * - * @var FW_DB_utility|null - */ - public $database = null; - - /** - * Whether a database instance shall be cloned if existing - * - * @var bool - */ - public $newInstance; - - public function init($database = null, $newInstance = false) - { - $this->database = $database; - $this->newInstance = $newInstance; - } -} diff --git a/src/FuzeWorks/Model/PDOTableModel.php b/src/FuzeWorks/Model/PDOTableModel.php new file mode 100644 index 0000000..2a7b9dc --- /dev/null +++ b/src/FuzeWorks/Model/PDOTableModel.php @@ -0,0 +1,290 @@ +databases)) + $this->databases = Factory::getInstance()->databases; + + $this->dbEngine = $this->databases->get($connectionName, 'pdo', $parameters); + $this->tableName = $tableName; + } + + public function create(array $data, array $options = []): bool + { + // If no data is provided, stop now + if (empty($data)) + throw new DatabaseException("Could not create data. No data provided."); + + // Determine which fields will be inserted + $fieldsArr = $this->createFields($data); + $fields = $fieldsArr['fields']; + $values = $fieldsArr['values']; + + // Generate the sql and create a PDOStatement + $sql = "INSERT INTO {$this->tableName} ({$fields}) VALUES ({$values})"; + + /** @var PDOStatement $statement */ + $this->lastStatement = $this->dbEngine->prepare($sql); + + // And execute the query + if ($this->arrIsAssoc($data)) + $this->lastStatement->execute($data); + else + foreach ($data as $record) + $this->lastStatement->execute($record); + + // And return true for success + return true; + } + + public function read(array $filter = [], array $options = []): array + { + // Determine which fields to select. If none provided, select all + $fields = (isset($options['fields']) && is_array($options['fields']) ? implode(',', $options['fields']) : '*'); + + // Apply the filter. If none provided, don't condition it + $where = $this->filter($filter); + + // Generate the sql and create a PDOStatement + $sql = "SELECT " . $fields . " FROM {$this->tableName} " . $where; + + /** @var PDOStatement $statement */ + $this->lastStatement = $this->dbEngine->prepare($sql); + + // And execute the query + $this->lastStatement->execute($filter); + + // And return the result + return $this->lastStatement->fetchAll(PDO::FETCH_ASSOC); + } + + public function update(array $data, array $filter, array $options = []): bool + { + // If no data is provided, stop now + if (empty($data)) + throw new DatabaseException("Could not update data. No data provided."); + + // Apply the filter + $where = $this->filter($filter); + + // Determine fields and values + foreach ($data as $key => $val) + $fields[] = $key."=:".$key; + + $fields = implode(', ', $fields); + + // Generate the sql and create a PDOStatement + $sql = "UPDATE {$this->tableName} SET {$fields} {$where}"; + + /** @var PDOStatement $statement */ + $this->lastStatement = $this->dbEngine->prepare($sql); + + // Merge data and filter, since both are needed by the statement + $parameters = array_merge($data, $filter); + + // And execute the query + $this->lastStatement->execute($parameters); + + // And return true for success + return true; + } + + public function delete(array $filter, array $options = []): bool + { + // Apply the filter + $where = $this->filter($filter); + + // Generate the sql and create a PDOStatement + $sql = "DELETE FROM {$this->tableName} " . $where; + + /** @var PDOStatement $statement */ + $this->lastStatement = $this->dbEngine->prepare($sql); + + // And execute the query + $this->lastStatement->execute($filter); + + // And return true for success + return true; + } + + public function getLastStatement(): PDOStatementWrapper + { + return $this->lastStatement; + } + + /** + * Call methods on the PDO Engine, which calls methods on the PDO Connection + * + * @param $name + * @param $arguments + * @return PDOEngine + */ + public function __call($name, $arguments) + { + return $this->dbEngine->{$name}(...$arguments); + } + + /** + * Get properties from the PDO Engine, which gets properties from the PDO connection + * + * @param $name + * @return mixed + */ + public function __get($name) + { + return $this->dbEngine->$name; + } + + /** + * Set properties on the PDO Connection, which sets properties on the PDO Connection + * + * @param $name + * @param $value + * @return mixed + */ + public function __set($name, $value) + { + return $this->dbEngine->$name = $value; + } + + private function filter(array $filter = []): string + { + if (empty($filter)) + return ''; + + $whereKeys = []; + foreach ($filter as $filterKey => $filterVal) + $whereKeys[] = $filterKey . '=:' . $filterKey; + + return 'WHERE ' . implode(' AND ', $whereKeys); + } + + private function createFields(array $record): array + { + // If multiple data is inserted at once, search the fields in the first entry + if (!$this->arrIsAssoc($record)) + $record = $record[0]; + + // Determine the fields and values + foreach ($record as $key => $val) + { + $fields[] = $key; + $values[] = ':'.$key; + } + + // And merge them again + $fields = implode(', ', $fields); + $values = implode(', ', $values); + + return ['fields' => $fields, 'values' => $values]; + } + + private function arrIsAssoc(array $arr): bool + { + if (array() === $arr) return false; + return array_keys($arr) !== range(0, count($arr) - 1); + } +} \ No newline at end of file diff --git a/src/Database/drivers/sqlite3/sqlite3_utility.php b/src/FuzeWorks/Model/iDatabaseTableModel.php similarity index 64% rename from src/Database/drivers/sqlite3/sqlite3_utility.php rename to src/FuzeWorks/Model/iDatabaseTableModel.php index cfa6a64..fd28605 100644 --- a/src/Database/drivers/sqlite3/sqlite3_utility.php +++ b/src/FuzeWorks/Model/iDatabaseTableModel.php @@ -1,10 +1,10 @@ db->display_error('db_unsupported_feature'); - } -} +interface iDatabaseTableModel +{ + public function create(array $data, array $options = []): bool; + public function read(array $filter = [], array $options = []): array; + public function update(array $data, array $filter, array $options = []): bool; + public function delete(array $filter, array $options = []): bool; +} \ No newline at end of file diff --git a/test/bootstrap.php b/test/bootstrap.php index fe6e286..1451ba7 100644 --- a/test/bootstrap.php +++ b/test/bootstrap.php @@ -44,14 +44,14 @@ $configurator->setLogDirectory(dirname(__FILE__) . '/temp'); // Other values $configurator->setTimeZone('Europe/Amsterdam'); -$configurator->enableDebugMode(true); +$configurator->enableDebugMode(true)->setDebugAddress('ALL'); // Implement the Layout Component $configurator->addComponent(new \FuzeWorks\DatabaseComponent()); +$configurator->addComponent(new \FuzeWorks\TracyComponent()); // Create container $container = $configurator->createContainer(); -$container->init(); // And return the result return $container; diff --git a/test/database/DatabaseTestAbstract.php b/test/database/DatabaseTestAbstract.php index cf42ddc..9fbd26b 100644 --- a/test/database/DatabaseTestAbstract.php +++ b/test/database/DatabaseTestAbstract.php @@ -61,8 +61,5 @@ abstract class DatabaseTestAbstract extends TestCase // Re-enable events, in case they have been disabled Events::enable(); - - // Reset the HTTP status code - Core::$http_status_code = 200; } }