From 68cbb74506b0aeebfdcead4d92d6073711ad8769 Mon Sep 17 00:00:00 2001 From: Deon George Date: Wed, 12 Aug 2015 16:30:46 +1000 Subject: [PATCH] Initial Release --- classes/Database/DB2.php | 4 + classes/Database/DB2/Result.php | 3 + classes/Kohana/Database/DB2.php | 305 +++++++++++++++++++++++++ classes/Kohana/Database/DB2/Result.php | 74 ++++++ config/database.php | 33 +++ 5 files changed, 419 insertions(+) create mode 100644 classes/Database/DB2.php create mode 100644 classes/Database/DB2/Result.php create mode 100644 classes/Kohana/Database/DB2.php create mode 100644 classes/Kohana/Database/DB2/Result.php create mode 100644 config/database.php diff --git a/classes/Database/DB2.php b/classes/Database/DB2.php new file mode 100644 index 0000000..deb4828 --- /dev/null +++ b/classes/Database/DB2.php @@ -0,0 +1,4 @@ + diff --git a/classes/Database/DB2/Result.php b/classes/Database/DB2/Result.php new file mode 100644 index 0000000..9b71b37 --- /dev/null +++ b/classes/Database/DB2/Result.php @@ -0,0 +1,3 @@ +_connection) + return; + + // Extract the connection parameters, adding required variabels + extract($this->_config['connection'] + array( + 'database' => '', + 'hostname' => '', + 'username' => '', + 'port' => '', + 'password' => '', + 'persistent' => FALSE, + 'schema' => '', + )); + + // Get user login details from user session - these are set by login + if (! $username) + $username = Session::instance()->get_once(Kohana::$config->load('auth')->session_key); + if (! $password) + $password = Session::instance()->get_once('password'); + + // Prevent this information from showing up in traces + unset($this->_config['connection']['username'], $this->_config['connection']['password']); + + if (! $username OR ! $password) + HTTP::redirect('login'); + + try { + if ($persistent) { + // Create a persistent connection + throw new Kohana_Exception('Cant do persistant connections'); + + } else { + // Create a connection and force it to be a new link + $constring = sprintf('DATABASE=%s;HOSTNAME=%s;PORT=%s;PROTOCOL=%s;UID=%s;PWD=%s', + $database,$hostname,$port,'TCPIP',$username,$password); + + $this->_connection = db2_connect($constring,NULL,NULL); + } + + } catch (ErrorException $e) { + // No connection exists + $this->_connection = NULL; + + throw new Database_Exception(':error', array( + ':error' => sprintf('%s error in %s (%s)',$e->getMessage(),$e->getFile(),$e->getLine()), + ), + $e->getCode()); + } + + // \xFF is a better delimiter, but the PHP driver uses underscore + $this->_connection_id = sha1($hostname.'_'.$username.'_'.$password); + + if ( ! empty($this->_config['charset'])) { + // Set the character set + $this->set_charset($this->_config['charset']); + } + } + + // @todo + public function disconnect() {} + + public function escape($value) + { + // SQL standard is to use single-quotes for all values + return "'$value'"; + } + + public function set_charset($charset) {} + + public function query($type, $sql, $as_object = FALSE, array $params = NULL) + { + // Make sure the database is connected + $this->_connection OR $this->connect(); + + if (Kohana::$profiling) + { + // Benchmark this query for the current instance + $benchmark = Profiler::start("Database ({$this->_instance})", $sql); + } + + if ( ! empty($this->_config['connection']['persistent']) AND $this->_config['connection']['database'] !== Database_DB2::$_current_databases[$this->_connection_id]) + { + // Select database on persistent connections + $this->_select_db($this->_config['connection']['database']); + } + + // Execute the query + try + { + $result = db2_exec($this->_connection,$sql,array('cursor'=>DB2_SCROLLABLE)); + } + catch (Exception $e) + { + if (isset($benchmark)) + { + // This benchmark is worthless + Profiler::delete($benchmark); + } + + throw new Database_Exception(':error [ :query ]', + array(':error' => db2_conn_errormsg($this->_connection), ':query' => $sql), + db2_conn_error($this->_connection)); + } + + if (isset($benchmark)) + Profiler::stop($benchmark); + + // Set the last query + $this->last_query = $sql; + + if ($type === Database::SELECT) + { + // Return an iterator of results + return new Database_DB2_Result($result, $sql, $as_object, $params); + } + elseif ($type === Database::INSERT) + { + throw new Kohana_Exception('Not Implemented (:type).',array(':type'=>$type)); + } + else + { + throw new Kohana_Exception('Not Implemented (:type).',array(':type'=>$type)); + } + } + + public function list_columns($table, $like = NULL, $add_prefix = FALSE) { + // Make sure the database is connected + $this->_connection or $this->connect(); + + // Quote the table name + $table = ($add_prefix === TRUE) ? $this->quote_table($table) : $table; + + if (is_string($like)) + { + // Search for column names + throw new Kohana_Exception('Like queries not implemented'); + } + else + { + // Find all column names + $result = db2_columns($this->_connection,NULL,'%',$table); + } + + $count = 0; + $columns = array(); + while ($row = db2_fetch_assoc($result)) + { + list($type, $length) = $this->_parse_type($row['TYPE_NAME']); + + $column = $this->datatype($type); + + $column['column_name'] = $row['COLUMN_NAME']; + $column['data_type'] = $type; + $column['is_nullable'] = ($row['IS_NULLABLE'] == 'YES'); + $column['ordinal_position'] = ++$count; + + switch (strtolower($column['data_type'])) { + case 'float': + if (isset($length)) + list($column['numeric_precision'], $column['numeric_scale']) = explode(',', $length); + break; + + case 'int': + if (isset($length)) + // MySQL attribute + $column['display'] = $length; + break; + + case 'string': + switch ($column['data_type']) { + case 'binary': + case 'varbinary': + $column['character_maximum_length'] = $length; + break; + + case 'char': + case 'varchar': + $column['character_maximum_length'] = $length; + case 'text': + case 'tinytext': + case 'mediumtext': + case 'longtext': + $column['collation_name'] = $row['Collation']; + break; + + case 'enum': + case 'set': + $column['collation_name'] = $row['Collation']; + $column['options'] = explode('\',\'', substr($length, 1, -1)); + break; + } + + break; + } + + $columns[$row['COLUMN_NAME']] = $column; + } + + return $columns; + } + + public function quote_column($column) + { + return $column; + } + + public function quote_table($table) + { + // Identifiers are escaped by repeating them + $escaped_identifier = $this->_identifier.$this->_identifier; + + if (is_array($table)) + { + list($table, $alias) = $table; + $alias = str_replace($this->_identifier, $escaped_identifier, $alias); + } + + if ($table instanceof Database_Query) + { + // Create a sub-query + $table = '('.$table->compile($this).')'; + } + elseif ($table instanceof Database_Expression) + { + // Compile the expression + $table = $table->compile($this); + } + else + { + // Convert to a string + $table = (string) $table; + + $table = str_replace($this->_identifier, $escaped_identifier, $table); + + if (strpos($table, '.') !== FALSE) + { + $parts = explode('.', $table); + + if ($prefix = $this->table_prefix()) + { + // Get the offset of the table name, last part + $offset = count($parts) - 1; + + // Add the table prefix to the table name + $parts[$offset] = $prefix.$parts[$offset]; + } + + foreach ($parts as & $part) + { + // Quote each of the parts + $part = $this->_identifier.$part.$this->_identifier; + } + + $table = implode('.', $parts); + } + else + { + // Add the table prefix + $table = $this->table_prefix(TRUE).$table; + } + } + + if (isset($alias)) + { + // Attach table prefix to alias + $table .= ' AS '.$this->table_prefix().$alias; + } + + return $table; + } + + public function table_prefix($schema=FALSE) + { + return ($schema === TRUE ? $this->_config['connection']['database'].'.' : '').$this->_config['table_prefix']; + } +} +?> diff --git a/classes/Kohana/Database/DB2/Result.php b/classes/Kohana/Database/DB2/Result.php new file mode 100644 index 0000000..32c9aef --- /dev/null +++ b/classes/Kohana/Database/DB2/Result.php @@ -0,0 +1,74 @@ +_total_rows = db2_num_rows($result); + } + + public function __destruct() + { + if (is_resource($this->_result)) + { + db2_free_result($this->_result); + } + } + + public function seek($offset) + { + if ($this->offsetExists($offset) AND db2_next_result($this->_result)) + { + // Set the current row to the offset + $this->_current_row = $this->_internal_row = $offset; + + return TRUE; + } + else + { + return FALSE; + } + } + + public function current() + { + if ($this->_current_row !== $this->_internal_row AND ! $this->seek($this->_current_row)) + return NULL; + + // Increment internal row for optimization assuming rows are fetched in order + $this->_internal_row++; + + if ($this->_as_object === TRUE) + { + // Return an stdClass + return db2_fetch_object($this->_result); + } + elseif (is_string($this->_as_object)) + { + $o = new $this->_as_object; + + // Return an object of given class name + // @todo This doesnt have $this->_loaded = $this->_valid = TRUE; + return $o->values(db2_fetch_assoc($this->_result)); + } + else + { + // Return an array of the row + return db2_fetch_assoc($this->_result); + } + } + +} // End Database_DB2L_Result diff --git a/config/database.php b/config/database.php new file mode 100644 index 0000000..aeb4ed4 --- /dev/null +++ b/config/database.php @@ -0,0 +1,33 @@ + array + ( + 'type' => 'DB2', + 'connection' => array( + /** + * The following options are available for DB2: + * + * string hostname server hostname, or socket + * string database database name + * string username database username + * string password database password + * boolean persistent use persistent connections? + * + * Ports and sockets may be appended to the hostname. + */ + 'hostname' => '', + 'port' => '', + 'username' => '', + 'password' => '', + 'persistent' => FALSE, + 'database' => '', + ), + 'table_prefix' => '', + 'charset' => 'utf8', + 'caching' => TRUE, + 'profiling' => TRUE, + ), +); +?>