00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 require_once 'creole/Connection.php';
00023 require_once 'creole/common/ConnectionCommon.php';
00024 require_once 'creole/drivers/odbc/adapters/ODBCAdapter.php';
00025
00033 class ODBCConnection extends ConnectionCommon implements Connection {
00034
00039 protected $adapter = null;
00040
00045 protected $odbcresult = null;
00046
00050 public function connect($dsninfo, $flags = 0)
00051 {
00052 if (!function_exists('odbc_connect'))
00053 throw new SQLException('odbc extension not loaded');
00054
00055 $adapterclass = isset($dsninfo['adapter']) ? $dsninfo['adapter'] : null;
00056
00057 if (!$adapterclass)
00058 $adapterclass = 'ODBCAdapter';
00059 else
00060 $adapterclass .= 'Adapter';
00061
00062 Creole::import('creole.drivers.odbc.adapters.' . $adapterclass);
00063 $this->adapter = new $adapterclass();
00064
00065 $this->dsn = $dsninfo;
00066 $this->flags = $flags;
00067
00068 if ( !($this->flags & Creole::COMPAT_ASSOC_LOWER) && !$this->adapter->preservesColumnCase())
00069 {
00070 trigger_error('Connection created without Creole::COMPAT_ASSOC_LOWER, ' .
00071 'but driver does not support case preservation.',
00072 E_USER_WARNING);
00073 $this->flags != Creole::COMPAT_ASSOC_LOWER;
00074 }
00075
00076 $persistent = ($flags & Creole::PERSISTENT) === Creole::PERSISTENT;
00077
00078 if ($dsninfo['database'])
00079 $odbcdsn = $dsninfo['database'];
00080 elseif ($dsninfo['hostspec'])
00081 $odbcdsn = $dsninfo['hostspec'];
00082 else
00083 $odbcdsn = 'localhost';
00084
00085 $user = @$dsninfo['username'];
00086 $pw = @$dsninfo['password'];
00087
00088 $connect_function = $persistent ? 'odbc_pconnect' : 'odbc_connect';
00089
00090 $conn = @$connect_function($odbcdsn, $user, $pw, SQL_CUR_USE_IF_NEEDED);
00091
00092 if (!is_resource($conn))
00093 throw new SQLException('connect failed', $this->nativeError(), $odbcdsn);
00094
00095 $this->dblink = $conn;
00096
00103 @odbc_binmode(0, ODBC_BINMODE_PASSTHRU);
00104 @odbc_longreadlen(0, ini_get('odbc.defaultlrl'));
00105 }
00106
00110 public function close()
00111 {
00112 $ret = true;
00113
00114 $this->adapter = null;
00115 $this->odbcresult = null;
00116
00117 if ($this->dblink !== null)
00118 {
00119 $ret = @odbc_close($this->dblink);
00120 $this->dblink = null;
00121 }
00122
00123 return $ret;
00124 }
00125
00129 public function __destruct()
00130 {
00131 $this->close();
00132 }
00133
00138 public function nativeError()
00139 {
00140 if ($this->dblink && is_resource($this->dblink))
00141 $errstr = '[' . @odbc_error($this->dblink) . '] ' . @odbc_errormsg($this->dblink);
00142 else
00143 $errstr = '[' . @odbc_error() . '] ' . @odbc_errormsg();
00144
00145 return $errstr;
00146 }
00147
00152 public function getAdapter()
00153 {
00154 return $this->adapter;
00155 }
00156
00160 public function getDatabaseInfo()
00161 {
00162 require_once 'creole/drivers/odbc/metadata/ODBCDatabaseInfo.php';
00163 return new ODBCDatabaseInfo($this);
00164 }
00165
00169 public function getIdGenerator()
00170 {
00171 return $this->adapter->getIdGenerator($this);
00172 }
00173
00178 public function createResultSet($odbcresult, $fetchmode)
00179 {
00180 return $this->adapter->createResultSet($this, $odbcresult, $fetchmode);
00181 }
00182
00186 public function prepareStatement($sql)
00187 {
00188 require_once 'creole/drivers/odbc/ODBCPreparedStatement.php';
00189 return new ODBCPreparedStatement($this, $sql);
00190 }
00191
00195 public function createStatement()
00196 {
00197 require_once 'creole/drivers/odbc/ODBCStatement.php';
00198 return new ODBCStatement($this);
00199 }
00200
00205 public function prepareCall($sql)
00206 {
00207 throw new SQLException('Stored procedures not currently implemented.');
00208 }
00209
00213 public function applyLimit(&$sql, $offset, $limit)
00214 {
00215 if ($this->adapter->hasLimitOffset())
00216 $this->adapter->applyLimit($sql, $offset, $limit);
00217 }
00218
00222 public function executeQuery($sql, $fetchmode = null)
00223 {
00224 if ($this->odbcresult)
00225 $this->odbcresult = null;
00226
00227 $r = @odbc_exec($this->dblink, $sql);
00228
00229 if ($r === false)
00230 throw new SQLException('Could not execute query', $this->nativeError(), $sql);
00231
00232 $this->odbcresult = new ODBCResultResource($r);
00233
00234 return $this->createResultSet($this->odbcresult, $fetchmode);
00235 }
00236
00240 public function executeUpdate($sql)
00241 {
00242 if ($this->odbcresult)
00243 $this->odbcresult = null;
00244
00245 $r = @odbc_exec($this->dblink, $sql);
00246
00247 if ($r === false)
00248 throw new SQLException('Could not execute update', $this->nativeError(), $sql);
00249
00250 $this->odbcresult = new ODBCResultResource($r);
00251
00252 return $this->getUpdateCount();
00253 }
00254
00260 protected function beginTrans()
00261 {
00262 if ($this->adapter->supportsTransactions()) {
00263 @odbc_autocommit($this->dblink, false);
00264 if (odbc_error($this->dblink) == 'S1C00') {
00265 throw new SQLException('Could not begin transaction', $this->nativeError());
00266 }
00267 }
00268 }
00269
00275 protected function commitTrans()
00276 {
00277 if ($this->adapter->supportsTransactions()) {
00278 $result = @odbc_commit($this->dblink);
00279 if (!$result) {
00280 throw new SQLException('Could not commit transaction', $this->nativeError());
00281 }
00282 @odbc_autocommit($this->dblink, true);
00283 if (odbc_error($this->dblink) == 'S1C00') {
00284 throw new SQLException('Could not commit transaction (autocommit failed)', $this->nativeError());
00285 }
00286 }
00287 }
00288
00294 protected function rollbackTrans()
00295 {
00296 if ($this->adapter->supportsTransactions()) {
00297 $result = @odbc_rollback($this->dblink);
00298 if (!$result) {
00299 throw new SQLException('Could not rollback transaction', $this->nativeError());
00300 }
00301 @odbc_autocommit($this->dblink, true);
00302 if (odbc_error($this->dblink) == 'S1C00') {
00303 throw new SQLException('Could not rollback transaction (autocommit failed)', $this->nativeError());
00304 }
00305 }
00306 }
00307
00311 public function getUpdateCount()
00312 {
00313 if ($this->odbcresult === null)
00314 return 0;
00315
00316 $n = @odbc_num_rows($this->odbcresult->getHandle());
00317
00318 if ($n == -1)
00319 throw new SQLException('Could not retrieve update count', $this->nativeError());
00320
00321 return (int) $n;
00322 }
00323
00324 }
00325
00338 class ODBCResultResource
00339 {
00343 protected $handle = null;
00344
00345 public function __construct($handle)
00346 {
00347 if (is_resource($handle))
00348 $this->handle = $handle;
00349 }
00350
00351 public function __destruct()
00352 {
00353 if ($this->handle !== null)
00354 @odbc_free_result($this->handle);
00355 }
00356
00357 public function getHandle()
00358 {
00359 return $this->handle;
00360 }
00361
00362 }