00001 <?php
00026 require_once 'Zend/Db/Adapter/Abstract.php';
00027
00031 require_once 'Zend/Db/Profiler.php';
00032
00036 require_once 'Zend/Db/Select.php';
00037
00041 require_once 'ZendX/Db/Statement/Firebird.php';
00042
00043
00051 class ZendX_Db_Adapter_Firebird extends Zend_Db_Adapter_Abstract
00052 {
00062 protected $_autoQuoteIdentifiers = true;
00063
00069 protected $_transResource = null;
00070
00076 public function getTransaction()
00077 {
00078 return (is_resource($this->_transResource) ? $this->_transResource : null);
00079 }
00080
00092 protected $_numericDataTypes = array(
00093 Zend_Db::INT_TYPE => Zend_Db::INT_TYPE,
00094 Zend_Db::BIGINT_TYPE => Zend_Db::BIGINT_TYPE,
00095 Zend_Db::FLOAT_TYPE => Zend_Db::FLOAT_TYPE,
00096 'SMALLINT' => Zend_Db::INT_TYPE,
00097 'INT' => Zend_Db::INT_TYPE,
00098 'INTEGER' => Zend_Db::INT_TYPE,
00099 'BIGINT' => Zend_Db::BIGINT_TYPE,
00100 'INT64' => Zend_Db::BIGINT_TYPE,
00101 'DECIMAL' => Zend_Db::FLOAT_TYPE,
00102 'DOUBLE PRECISION' => Zend_Db::FLOAT_TYPE,
00103 'DOUBLE' => Zend_Db::FLOAT_TYPE,
00104 'NUMERIC' => Zend_Db::FLOAT_TYPE,
00105 'FLOAT' => Zend_Db::FLOAT_TYPE
00106 );
00107
00114 protected function _quote($value)
00115 {
00116 if (is_int($value) || is_float($value)) {
00117 return $value;
00118 }
00119 $value = str_replace("'", "''", $value);
00120 return "'" . $value . "'";
00121 }
00122
00128 public function listTables()
00129 {
00130 $data = $this->fetchCol('SELECT RDB$RELATION_NAME FROM RDB$RELATIONS WHERE RDB$SYSTEM_FLAG = 0');
00131 foreach($data as &$v)
00132 $v = trim($v);
00133 return $data;
00134 }
00135
00164 public function describeTable($tableName, $schemaName = null)
00165 {
00166 $fieldMaps = array(
00167 'TEXT' => 'CHAR',
00168 'VARYING' => 'VARCHAR',
00169 'SHORT' => 'SMALLINT',
00170 'LONG' => 'INTEGER',
00171 'FLOAT' => 'FLOAT',
00172 'INT64' => array(0 => 'BIGINT', 'NUMERIC', 'DECIMAL'),
00173 'DATE' => 'DATE',
00174 'TIME' => 'TIME',
00175 'BLOB' => 'BLOB',
00176 'DOUBLE' => 'DOUBLE PRECISION',
00177 'TIMESTAMP' => 'TIMESTAMP'
00178 );
00179
00180 $sql = 'select
00181 RF.RDB$RELATION_NAME, \'\', RF.RDB$FIELD_NAME, T.RDB$TYPE_NAME,
00182 RF.RDB$DEFAULT_VALUE, RF.RDB$NULL_FLAG, RF.RDB$FIELD_POSITION,
00183 F.RDB$CHARACTER_LENGTH, F.RDB$FIELD_SCALE, F.RDB$FIELD_PRECISION,
00184 IXS.RDB$FIELD_POSITION, IXS.RDB$FIELD_POSITION, F.RDB$FIELD_SUB_TYPE
00185 from RDB$RELATION_FIELDS RF
00186 left join RDB$RELATION_CONSTRAINTS RC
00187 on (RF.RDB$RELATION_NAME = RC.RDB$RELATION_NAME and RC.RDB$CONSTRAINT_TYPE = \'PRIMARY KEY\')
00188 left join RDB$INDEX_SEGMENTS IXS
00189 on (IXS.RDB$FIELD_NAME = RF.RDB$FIELD_NAME and RC.RDB$INDEX_NAME = IXS.RDB$INDEX_NAME)
00190 inner join RDB$FIELDS F on (RF.RDB$FIELD_SOURCE = F.RDB$FIELD_NAME)
00191 inner join RDB$TYPES T on (T.RDB$TYPE = F.RDB$FIELD_TYPE and T.RDB$FIELD_NAME = \'RDB$FIELD_TYPE\')
00192 where ' . $this->quoteInto('(UPPER(RF.RDB$RELATION_NAME) = UPPER(?)) ', $tableName) . '
00193 order by RF.RDB$FIELD_POSITION';
00194
00195 $stmt = $this->query($sql);
00196
00200 $result = $stmt->fetchAll(Zend_Db::FETCH_NUM);
00201
00202 $table_name = 0;
00203 $owner = 1;
00204 $column_name = 2;
00205 $data_type = 3;
00206 $data_default = 4;
00207 $nullable = 5;
00208 $column_id = 6;
00209 $data_length = 7;
00210 $data_scale = 8;
00211 $data_precision = 9;
00212 $constraint_type = 10;
00213 $position = 11;
00214 $sub_type = 12;
00215
00216 $desc = array();
00217 foreach ($result as $key => $row) {
00218 list ($primary, $primaryPosition, $identity) = array(false, null, false);
00219 if (strlen($row[$constraint_type])) {
00220 $primary = true;
00221 $primaryPosition = $row[$position];
00225 $identity = false;
00226 }
00227
00228 $dataType = trim($row[$data_type]);
00229 $newType = $fieldMaps[$dataType];
00230 if (is_array($newType) && $dataType == 'INT64')
00231 $newType = $newType[$row[$sub_type]];
00232 $row[$data_type] = $newType;
00233
00234 $desc[trim($row[$column_name])] = array(
00235 'SCHEMA_NAME' => '',
00236 'TABLE_NAME' => trim($row[$table_name]),
00237 'COLUMN_NAME' => trim($row[$column_name]),
00238 'COLUMN_POSITION' => $row[$column_id] +1,
00239 'DATA_TYPE' => $row[$data_type],
00240 'DEFAULT' => $row[$data_default],
00241 'NULLABLE' => (bool) ($row[$nullable] != '1'),
00242 'LENGTH' => $row[$data_length],
00243 'SCALE' => ($row[$data_scale] == 0 ? null : $row[$data_scale]),
00244 'PRECISION' => ($row[$data_precision] == 0 ? null : $row[$data_precision]),
00245 'UNSIGNED' => false,
00246 'PRIMARY' => $primary,
00247 'PRIMARY_POSITION' => ($primary ? $primaryPosition+1 : null),
00248 'IDENTITY' => $identity
00249 );
00250 }
00251 return $desc;
00252 }
00253
00254
00260 protected function _formatDbConnString($host, $port, $dbname)
00261 {
00262 if (is_numeric($port))
00263 $port = '/' . (integer) $port;
00264 if ($dbname)
00265 $dbname = ':' . $dbname;
00266
00267 return $host . $port . $dbname;
00268
00269 }
00270
00277 protected function _connect()
00278 {
00279 if (isset($this->_connection) && is_resource($this->_connection)) {
00280 return;
00281 }
00282
00283 if (!extension_loaded('interbase')) {
00287 require_once 'ZendX/Db/Adapter/Firebird/Exception.php';
00288 throw new ZendX_Db_Adapter_Firebird_Exception('The Interbase extension is required for this adapter but the extension is not loaded');
00289 }
00290
00291
00292
00293
00294 $this->_connection = @ibase_connect(
00295 $this->_formatDbConnString($this->_config['host'],$this->_config['port'] ,$this->_config['dbname']),
00296 $this->_config['username'],
00297 $this->_config['password'],
00298 $this->_config['charset'],
00299 $this->_config['buffers'],
00300 $this->_config['dialect'],
00301 $this->_config['role']
00302 );
00303
00304 if ($this->_connection === false) {
00308 require_once 'ZendX/Db/Adapter/Firebird/Exception.php';
00309 throw new ZendX_Db_Adapter_Firebird_Exception(ibase_errmsg());
00310 }
00311 }
00312
00318 public function closeConnection()
00319 {
00320 if (is_resource($this->_transResource)) {
00321 ibase_rollback($this->_transResource);
00322 }
00323 $this->_transResource = null;
00324
00325 if (is_resource($this->_connection)) {
00326 unset($this->_connection);
00327 }
00328
00329 }
00330
00337 public function prepare($sql)
00338 {
00339 $this->_connect();
00340
00341 $stmt = new ZendX_Db_Statement_Firebird($this, $sql);
00342 if ($stmt === false) {
00343 return false;
00344 }
00345 $stmt->setFetchMode($this->_fetchMode);
00346 return $stmt;
00347 }
00348
00367 public function lastInsertId($tableName = null, $primaryKey = null)
00368 {
00369 if ($tableName !== null) {
00370 $sequenceName = $tableName;
00371 if ($primaryKey) {
00372 $sequenceName .= "_$primaryKey";
00373 }
00374 $sequenceName .= '_seq';
00375 return $this->lastSequenceId($sequenceName);
00376 }
00377
00378
00379 return null;
00380 }
00381
00387 protected function _beginTransaction()
00388 {
00389 $this->_connect();
00390 if (is_resource($this->_transResource)){
00391 return;
00392 }
00393
00394 $this->_transResource = ibase_trans(IBASE_DEFAULT, $this->_connection);
00395 }
00396
00402 protected function _commit()
00403 {
00404 if (false === ibase_commit(is_resource($this->_transResource) ? $this->_transResource : $this->_connection)) {
00408 require_once 'ZendX/Db/Adapter/Firebird/Exception.php';
00409 throw new ZendX_Db_Adapter_Firebird_Exception(ibase_errmsg());
00410 }
00411 $this->_transResource = null;
00412 }
00413
00419 protected function _rollBack()
00420 {
00421 if (false === ibase_rollback(is_resource($this->_transResource) ? $this->_transResource : $this->_connection)) {
00425 require_once 'ZendX/Db/Adapter/Firebird/Exception.php';
00426 throw new ZendX_Db_Adapter_Firebird_Exception(ibase_errmsg());
00427 }
00428 $this->_transResource = null;
00429 }
00430
00437 public function setFetchMode($mode)
00438 {
00439 switch ($mode) {
00440 case Zend_Db::FETCH_LAZY:
00441 case Zend_Db::FETCH_ASSOC:
00442 case Zend_Db::FETCH_NUM:
00443 case Zend_Db::FETCH_BOTH:
00444 case Zend_Db::FETCH_NAMED:
00445 case Zend_Db::FETCH_OBJ:
00446 case Zend_Db::FETCH_BOUND:
00447 $this->_fetchMode = $mode;
00448 break;
00449 default:
00453 require_once 'ZendX/Db/Adapter/Firebird/Exception.php';
00454 throw new ZendX_Db_Adapter_Firebird_Exception("Invalid fetch mode '$mode' specified");
00455 }
00456 }
00457
00467 public function limit($sql, $count, $offset = 0)
00468 {
00469 $count = intval($count);
00470 if ($count <= 0) {
00474 require_once 'ZendX/Db/Adapter/Firebird/Exception.php';
00475 throw new ZendX_Db_Adapter_Firebird_Exception("LIMIT argument count=$count is not valid");
00476 }
00477
00478 $offset = intval($offset);
00479 if ($offset < 0) {
00483 require_once 'ZendX/Db/Adapter/Firebird/Exception.php';
00484 throw new ZendX_Db_Adapter_Firebird_Exception("LIMIT argument offset=$offset is not valid");
00485 }
00486
00487 if (trim($sql) == ''){
00488
00489
00490 $sql .= " rows $count";
00491 if ($offset > 0)
00492 $sql .= " to $offset";
00493 }
00494 else
00495 $sql = substr_replace($sql, "select first $count skip $offset ", stripos($sql, 'select'), 6);
00496
00497 return $sql;
00498 }
00499
00508 public function quoteTableAs($ident, $alias = null, $auto=false)
00509 {
00510
00511 return $this->_quoteIdentifierAs($ident, $alias, $auto, ' ');
00512 }
00513
00522 public function lastSequenceId($sequenceName)
00523 {
00524 $this->_connect();
00525 $sql = 'SELECT GEN_ID('.$this->quoteIdentifier($sequenceName).', 0) FROM RDB$DATABASE';
00526 $value = $this->fetchOne($sql);
00527 return $value;
00528 }
00529
00538 public function nextSequenceId($sequenceName)
00539 {
00540 $this->_connect();
00541 $sql = 'SELECT GEN_ID('.$this->quoteIdentifier($sequenceName).', 1) FROM RDB$DATABASE';
00542 $value = $this->fetchOne($sql);
00543 return $value;
00544 }
00545
00552 public function supportsParameters($type)
00553 {
00554 switch ($type) {
00555 case 'positional':
00556 return true;
00557 case 'named':
00558 default:
00559 return false;
00560 }
00561 }
00562
00568 public function isConnected()
00569 {
00570 return ((bool) (is_resource($this->_connection)
00571 && get_resource_type($this->_connection) == 'Firebird/InterBase link'));
00572 }
00573
00579 public function getServerVersion()
00580 {
00581 $this->_connect();
00582 $service = ibase_service_attach($this->_formatDbConnString($this->_config['host'], $this->_config['port'], ''), $this->_config['username'], $this->_config['password']);
00583
00584 if ($service != FALSE) {
00585 $server_info = ibase_server_info($service, IBASE_SVC_SERVER_VERSION);
00586 ibase_service_detach($service);
00587 $matches = null;
00588 if (preg_match('/((?:[0-9]{1,2}\.){1,3}[0-9]{1,2})/', $server_info, $matches)) {
00589 return $matches[1];
00590 } else {
00591 return null;
00592 }
00593 } else {
00594 return null;
00595 }
00596 }
00597 }