1<?php 2/** 3 * CodeIgniter 4 * 5 * An open source application development framework for PHP 6 * 7 * This content is released under the MIT License (MIT) 8 * 9 * Copyright (c) 2014 - 2018, British Columbia Institute of Technology 10 * 11 * Permission is hereby granted, free of charge, to any person obtaining a copy 12 * of this software and associated documentation files (the "Software"), to deal 13 * in the Software without restriction, including without limitation the rights 14 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 * copies of the Software, and to permit persons to whom the Software is 16 * furnished to do so, subject to the following conditions: 17 * 18 * The above copyright notice and this permission notice shall be included in 19 * all copies or substantial portions of the Software. 20 * 21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 * THE SOFTWARE. 28 * 29 * @package CodeIgniter 30 * @author EllisLab Dev Team 31 * @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/) 32 * @copyright Copyright (c) 2014 - 2018, British Columbia Institute of Technology (http://bcit.ca/) 33 * @license http://opensource.org/licenses/MIT MIT License 34 * @link https://codeigniter.com 35 * @since Version 3.0.0 36 * @filesource 37 */ 38defined('BASEPATH') OR exit('No direct script access allowed'); 39 40/** 41 * Firebird/Interbase Database Adapter Class 42 * 43 * Note: _DB is an extender class that the app controller 44 * creates dynamically based on whether the query builder 45 * class is being used or not. 46 * 47 * @package CodeIgniter 48 * @subpackage Drivers 49 * @category Database 50 * @author EllisLab Dev Team 51 * @link https://codeigniter.com/user_guide/database/ 52 */ 53class CI_DB_ibase_driver extends CI_DB { 54 55 /** 56 * Database driver 57 * 58 * @var string 59 */ 60 public $dbdriver = 'ibase'; 61 62 // -------------------------------------------------------------------- 63 64 /** 65 * ORDER BY random keyword 66 * 67 * @var array 68 */ 69 protected $_random_keyword = array('RAND()', 'RAND()'); 70 71 /** 72 * IBase Transaction status flag 73 * 74 * @var resource 75 */ 76 protected $_ibase_trans; 77 78 // -------------------------------------------------------------------- 79 80 /** 81 * Non-persistent database connection 82 * 83 * @param bool $persistent 84 * @return resource 85 */ 86 public function db_connect($persistent = FALSE) 87 { 88 return ($persistent === TRUE) 89 ? ibase_pconnect($this->hostname.':'.$this->database, $this->username, $this->password, $this->char_set) 90 : ibase_connect($this->hostname.':'.$this->database, $this->username, $this->password, $this->char_set); 91 } 92 93 // -------------------------------------------------------------------- 94 95 /** 96 * Database version number 97 * 98 * @return string 99 */ 100 public function version() 101 { 102 if (isset($this->data_cache['version'])) 103 { 104 return $this->data_cache['version']; 105 } 106 107 if (($service = ibase_service_attach($this->hostname, $this->username, $this->password))) 108 { 109 $this->data_cache['version'] = ibase_server_info($service, IBASE_SVC_SERVER_VERSION); 110 111 // Don't keep the service open 112 ibase_service_detach($service); 113 return $this->data_cache['version']; 114 } 115 116 return FALSE; 117 } 118 119 // -------------------------------------------------------------------- 120 121 /** 122 * Execute the query 123 * 124 * @param string $sql an SQL query 125 * @return resource 126 */ 127 protected function _execute($sql) 128 { 129 return ibase_query(isset($this->_ibase_trans) ? $this->_ibase_trans : $this->conn_id, $sql); 130 } 131 132 // -------------------------------------------------------------------- 133 134 /** 135 * Begin Transaction 136 * 137 * @return bool 138 */ 139 protected function _trans_begin() 140 { 141 if (($trans_handle = ibase_trans($this->conn_id)) === FALSE) 142 { 143 return FALSE; 144 } 145 146 $this->_ibase_trans = $trans_handle; 147 return TRUE; 148 } 149 150 // -------------------------------------------------------------------- 151 152 /** 153 * Commit Transaction 154 * 155 * @return bool 156 */ 157 protected function _trans_commit() 158 { 159 if (ibase_commit($this->_ibase_trans)) 160 { 161 $this->_ibase_trans = NULL; 162 return TRUE; 163 } 164 165 return FALSE; 166 } 167 168 // -------------------------------------------------------------------- 169 170 /** 171 * Rollback Transaction 172 * 173 * @return bool 174 */ 175 protected function _trans_rollback() 176 { 177 if (ibase_rollback($this->_ibase_trans)) 178 { 179 $this->_ibase_trans = NULL; 180 return TRUE; 181 } 182 183 return FALSE; 184 } 185 186 // -------------------------------------------------------------------- 187 188 /** 189 * Affected Rows 190 * 191 * @return int 192 */ 193 public function affected_rows() 194 { 195 return ibase_affected_rows($this->conn_id); 196 } 197 198 // -------------------------------------------------------------------- 199 200 /** 201 * Insert ID 202 * 203 * @param string $generator_name 204 * @param int $inc_by 205 * @return int 206 */ 207 public function insert_id($generator_name, $inc_by = 0) 208 { 209 //If a generator hasn't been used before it will return 0 210 return ibase_gen_id('"'.$generator_name.'"', $inc_by); 211 } 212 213 // -------------------------------------------------------------------- 214 215 /** 216 * List table query 217 * 218 * Generates a platform-specific query string so that the table names can be fetched 219 * 220 * @param bool $prefix_limit 221 * @return string 222 */ 223 protected function _list_tables($prefix_limit = FALSE) 224 { 225 $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$%\''; 226 227 if ($prefix_limit !== FALSE && $this->dbprefix !== '') 228 { 229 return $sql.' AND TRIM("RDB$RELATION_NAME") AS TABLE_NAME LIKE \''.$this->escape_like_str($this->dbprefix)."%' " 230 .sprintf($this->_like_escape_str, $this->_like_escape_chr); 231 } 232 233 return $sql; 234 } 235 236 // -------------------------------------------------------------------- 237 238 /** 239 * Show column query 240 * 241 * Generates a platform-specific query string so that the column names can be fetched 242 * 243 * @param string $table 244 * @return string 245 */ 246 protected function _list_columns($table = '') 247 { 248 return 'SELECT TRIM("RDB$FIELD_NAME") AS COLUMN_NAME FROM "RDB$RELATION_FIELDS" WHERE "RDB$RELATION_NAME" = '.$this->escape($table); 249 } 250 251 // -------------------------------------------------------------------- 252 253 /** 254 * Returns an object with field data 255 * 256 * @param string $table 257 * @return array 258 */ 259 public function field_data($table) 260 { 261 $sql = 'SELECT "rfields"."RDB$FIELD_NAME" AS "name", 262 CASE "fields"."RDB$FIELD_TYPE" 263 WHEN 7 THEN \'SMALLINT\' 264 WHEN 8 THEN \'INTEGER\' 265 WHEN 9 THEN \'QUAD\' 266 WHEN 10 THEN \'FLOAT\' 267 WHEN 11 THEN \'DFLOAT\' 268 WHEN 12 THEN \'DATE\' 269 WHEN 13 THEN \'TIME\' 270 WHEN 14 THEN \'CHAR\' 271 WHEN 16 THEN \'INT64\' 272 WHEN 27 THEN \'DOUBLE\' 273 WHEN 35 THEN \'TIMESTAMP\' 274 WHEN 37 THEN \'VARCHAR\' 275 WHEN 40 THEN \'CSTRING\' 276 WHEN 261 THEN \'BLOB\' 277 ELSE NULL 278 END AS "type", 279 "fields"."RDB$FIELD_LENGTH" AS "max_length", 280 "rfields"."RDB$DEFAULT_VALUE" AS "default" 281 FROM "RDB$RELATION_FIELDS" "rfields" 282 JOIN "RDB$FIELDS" "fields" ON "rfields"."RDB$FIELD_SOURCE" = "fields"."RDB$FIELD_NAME" 283 WHERE "rfields"."RDB$RELATION_NAME" = '.$this->escape($table).' 284 ORDER BY "rfields"."RDB$FIELD_POSITION"'; 285 286 return (($query = $this->query($sql)) !== FALSE) 287 ? $query->result_object() 288 : FALSE; 289 } 290 291 // -------------------------------------------------------------------- 292 293 /** 294 * Error 295 * 296 * Returns an array containing code and message of the last 297 * database error that has occurred. 298 * 299 * @return array 300 */ 301 public function error() 302 { 303 return array('code' => ibase_errcode(), 'message' => ibase_errmsg()); 304 } 305 306 // -------------------------------------------------------------------- 307 308 /** 309 * Update statement 310 * 311 * Generates a platform-specific update string from the supplied data 312 * 313 * @param string $table 314 * @param array $values 315 * @return string 316 */ 317 protected function _update($table, $values) 318 { 319 $this->qb_limit = FALSE; 320 return parent::_update($table, $values); 321 } 322 323 // -------------------------------------------------------------------- 324 325 /** 326 * Truncate statement 327 * 328 * Generates a platform-specific truncate string from the supplied data 329 * 330 * If the database does not support the TRUNCATE statement, 331 * then this method maps to 'DELETE FROM table' 332 * 333 * @param string $table 334 * @return string 335 */ 336 protected function _truncate($table) 337 { 338 return 'DELETE FROM '.$table; 339 } 340 341 // -------------------------------------------------------------------- 342 343 /** 344 * Delete statement 345 * 346 * Generates a platform-specific delete string from the supplied data 347 * 348 * @param string $table 349 * @return string 350 */ 351 protected function _delete($table) 352 { 353 $this->qb_limit = FALSE; 354 return parent::_delete($table); 355 } 356 357 // -------------------------------------------------------------------- 358 359 /** 360 * LIMIT 361 * 362 * Generates a platform-specific LIMIT clause 363 * 364 * @param string $sql SQL Query 365 * @return string 366 */ 367 protected function _limit($sql) 368 { 369 // Limit clause depends on if Interbase or Firebird 370 if (stripos($this->version(), 'firebird') !== FALSE) 371 { 372 $select = 'FIRST '.$this->qb_limit 373 .($this->qb_offset ? ' SKIP '.$this->qb_offset : ''); 374 } 375 else 376 { 377 $select = 'ROWS ' 378 .($this->qb_offset ? $this->qb_offset.' TO '.($this->qb_limit + $this->qb_offset) : $this->qb_limit); 379 } 380 381 return preg_replace('`SELECT`i', 'SELECT '.$select, $sql, 1); 382 } 383 384 // -------------------------------------------------------------------- 385 386 /** 387 * Insert batch statement 388 * 389 * Generates a platform-specific insert string from the supplied data. 390 * 391 * @param string $table Table name 392 * @param array $keys INSERT keys 393 * @param array $values INSERT values 394 * @return string|bool 395 */ 396 protected function _insert_batch($table, $keys, $values) 397 { 398 return ($this->db_debug) ? $this->display_error('db_unsupported_feature') : FALSE; 399 } 400 401 // -------------------------------------------------------------------- 402 403 /** 404 * Close DB Connection 405 * 406 * @return void 407 */ 408 protected function _close() 409 { 410 ibase_close($this->conn_id); 411 } 412 413} 414