PageRenderTime 41ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/libs/dibi/drivers/oracle.php

https://github.com/vohnicky/treeview
PHP | 420 lines | 291 code | 45 blank | 84 comment | 11 complexity | 14fc8c1aa9029be3b8ca0e15b854d554 MD5 | raw file
  1. <?php
  2. /**
  3. * dibi - tiny'n'smart database abstraction layer
  4. * ----------------------------------------------
  5. *
  6. * @copyright Copyright (c) 2005, 2010 David Grudl
  7. * @license http://dibiphp.com/license dibi license
  8. * @link http://dibiphp.com
  9. * @package dibi
  10. */
  11. /**
  12. * The dibi driver for Oracle database.
  13. *
  14. * Connection options:
  15. * - 'database' (or 'db') - the name of the local Oracle instance or the name of the entry in tnsnames.ora
  16. * - 'username' (or 'user')
  17. * - 'password' (or 'pass')
  18. * - 'lazy' - if TRUE, connection will be established only when required
  19. * - 'formatDate' - how to format date in SQL (@see date)
  20. * - 'formatDateTime' - how to format datetime in SQL (@see date)
  21. * - 'charset' - character encoding to set
  22. * - 'resource' - connection resource (optional)
  23. *
  24. * @copyright Copyright (c) 2005, 2010 David Grudl
  25. * @package dibi
  26. */
  27. class DibiOracleDriver extends DibiObject implements IDibiDriver
  28. {
  29. /** @var resource Connection resource */
  30. private $connection;
  31. /** @var resource Resultset resource */
  32. private $resultSet;
  33. /** @var bool */
  34. private $autocommit = TRUE;
  35. /** @var string Date and datetime format */
  36. private $fmtDate, $fmtDateTime;
  37. /**
  38. * @throws DibiException
  39. */
  40. public function __construct()
  41. {
  42. if (!extension_loaded('oci8')) {
  43. throw new DibiDriverException("PHP extension 'oci8' is not loaded.");
  44. }
  45. }
  46. /**
  47. * Connects to a database.
  48. * @return void
  49. * @throws DibiException
  50. */
  51. public function connect(array &$config)
  52. {
  53. DibiConnection::alias($config, 'charset');
  54. $this->fmtDate = isset($config['formatDate']) ? $config['formatDate'] : 'U';
  55. $this->fmtDateTime = isset($config['formatDateTime']) ? $config['formatDateTime'] : 'U';
  56. if (isset($config['resource'])) {
  57. $this->connection = $config['resource'];
  58. } else {
  59. $this->connection = @oci_new_connect($config['username'], $config['password'], $config['database'], $config['charset']); // intentionally @
  60. }
  61. if (!$this->connection) {
  62. $err = oci_error();
  63. throw new DibiDriverException($err['message'], $err['code']);
  64. }
  65. }
  66. /**
  67. * Disconnects from a database.
  68. * @return void
  69. */
  70. public function disconnect()
  71. {
  72. oci_close($this->connection);
  73. }
  74. /**
  75. * Executes the SQL query.
  76. * @param string SQL statement.
  77. * @return IDibiDriver|NULL
  78. * @throws DibiDriverException
  79. */
  80. public function query($sql)
  81. {
  82. $this->resultSet = oci_parse($this->connection, $sql);
  83. if ($this->resultSet) {
  84. oci_execute($this->resultSet, $this->autocommit ? OCI_COMMIT_ON_SUCCESS : OCI_DEFAULT);
  85. $err = oci_error($this->resultSet);
  86. if ($err) {
  87. throw new DibiDriverException($err['message'], $err['code'], $sql);
  88. }
  89. } else {
  90. $err = oci_error($this->connection);
  91. throw new DibiDriverException($err['message'], $err['code'], $sql);
  92. }
  93. return is_resource($this->resultSet) ? clone $this : NULL;
  94. }
  95. /**
  96. * Gets the number of affected rows by the last INSERT, UPDATE or DELETE query.
  97. * @return int|FALSE number of rows or FALSE on error
  98. */
  99. public function getAffectedRows()
  100. {
  101. throw new NotImplementedException;
  102. }
  103. /**
  104. * Retrieves the ID generated for an AUTO_INCREMENT column by the previous INSERT query.
  105. * @return int|FALSE int on success or FALSE on failure
  106. */
  107. public function getInsertId($sequence)
  108. {
  109. $this->query("SELECT $sequence.CURRVAL AS ID FROM DUAL");
  110. $row = $this->fetch(TRUE);
  111. return isset($row['ID']) : (int) $row['ID'] : FALSE;
  112. }
  113. /**
  114. * Begins a transaction (if supported).
  115. * @param string optional savepoint name
  116. * @return void
  117. */
  118. public function begin($savepoint = NULL)
  119. {
  120. $this->autocommit = FALSE;
  121. }
  122. /**
  123. * Commits statements in a transaction.
  124. * @param string optional savepoint name
  125. * @return void
  126. * @throws DibiDriverException
  127. */
  128. public function commit($savepoint = NULL)
  129. {
  130. if (!oci_commit($this->connection)) {
  131. $err = oci_error($this->connection);
  132. throw new DibiDriverException($err['message'], $err['code']);
  133. }
  134. $this->autocommit = TRUE;
  135. }
  136. /**
  137. * Rollback changes in a transaction.
  138. * @param string optional savepoint name
  139. * @return void
  140. * @throws DibiDriverException
  141. */
  142. public function rollback($savepoint = NULL)
  143. {
  144. if (!oci_rollback($this->connection)) {
  145. $err = oci_error($this->connection);
  146. throw new DibiDriverException($err['message'], $err['code']);
  147. }
  148. $this->autocommit = TRUE;
  149. }
  150. /**
  151. * Returns the connection resource.
  152. * @return mixed
  153. */
  154. public function getResource()
  155. {
  156. return $this->connection;
  157. }
  158. /********************* SQL ****************d*g**/
  159. /**
  160. * Encodes data for use in a SQL statement.
  161. * @param mixed value
  162. * @param string type (dibi::TEXT, dibi::BOOL, ...)
  163. * @return string encoded value
  164. * @throws InvalidArgumentException
  165. */
  166. public function escape($value, $type)
  167. {
  168. switch ($type) {
  169. case dibi::TEXT:
  170. case dibi::BINARY:
  171. return "'" . str_replace("'", "''", $value) . "'"; // TODO: not tested
  172. case dibi::IDENTIFIER:
  173. // @see http://download.oracle.com/docs/cd/B10500_01/server.920/a96540/sql_elements9a.htm
  174. $value = str_replace('"', '""', $value);
  175. return '"' . str_replace('.', '"."', $value) . '"';
  176. case dibi::BOOL:
  177. return $value ? 1 : 0;
  178. case dibi::DATE:
  179. return $value instanceof DateTime ? $value->format($this->fmtDate) : date($this->fmtDate, $value);
  180. case dibi::DATETIME:
  181. return $value instanceof DateTime ? $value->format($this->fmtDateTime) : date($this->fmtDateTime, $value);
  182. default:
  183. throw new InvalidArgumentException('Unsupported type.');
  184. }
  185. }
  186. /**
  187. * Decodes data from result set.
  188. * @param string value
  189. * @param string type (dibi::BINARY)
  190. * @return string decoded value
  191. * @throws InvalidArgumentException
  192. */
  193. public function unescape($value, $type)
  194. {
  195. if ($type === dibi::BINARY) {
  196. return $value;
  197. }
  198. throw new InvalidArgumentException('Unsupported type.');
  199. }
  200. /**
  201. * Injects LIMIT/OFFSET to the SQL query.
  202. * @param string &$sql The SQL query that will be modified.
  203. * @param int $limit
  204. * @param int $offset
  205. * @return void
  206. */
  207. public function applyLimit(&$sql, $limit, $offset)
  208. {
  209. if ($offset > 0) {
  210. // see http://www.oracle.com/technology/oramag/oracle/06-sep/o56asktom.html
  211. $sql = 'SELECT * FROM (SELECT t.*, ROWNUM AS "__rnum" FROM (' . $sql . ') t ' . ($limit >= 0 ? 'WHERE ROWNUM <= ' . ((int) $offset + (int) $limit) : '') . ') WHERE "__rnum" > '. (int) $offset;
  212. } elseif ($limit >= 0) {
  213. $sql = 'SELECT * FROM (' . $sql . ') WHERE ROWNUM <= ' . (int) $limit;
  214. }
  215. }
  216. /********************* result set ****************d*g**/
  217. /**
  218. * Returns the number of rows in a result set.
  219. * @return int
  220. */
  221. public function getRowCount()
  222. {
  223. throw new NotSupportedException('Row count is not available for unbuffered queries.');
  224. }
  225. /**
  226. * Fetches the row at current position and moves the internal cursor to the next position.
  227. * @param bool TRUE for associative array, FALSE for numeric
  228. * @return array array on success, nonarray if no next record
  229. * @internal
  230. */
  231. public function fetch($assoc)
  232. {
  233. return oci_fetch_array($this->resultSet, ($assoc ? OCI_ASSOC : OCI_NUM) | OCI_RETURN_NULLS);
  234. }
  235. /**
  236. * Moves cursor position without fetching row.
  237. * @param int the 0-based cursor pos to seek to
  238. * @return boolean TRUE on success, FALSE if unable to seek to specified record
  239. */
  240. public function seek($row)
  241. {
  242. throw new NotImplementedException;
  243. }
  244. /**
  245. * Frees the resources allocated for this result set.
  246. * @return void
  247. */
  248. public function free()
  249. {
  250. oci_free_statement($this->resultSet);
  251. $this->resultSet = NULL;
  252. }
  253. /**
  254. * Returns metadata for all columns in a result set.
  255. * @return array
  256. */
  257. public function getColumnsMeta()
  258. {
  259. $count = oci_num_fields($this->resultSet);
  260. $res = array();
  261. for ($i = 1; $i <= $count; $i++) {
  262. $res[] = array(
  263. 'name' => oci_field_name($this->resultSet, $i),
  264. 'table' => NULL,
  265. 'fullname' => oci_field_name($this->resultSet, $i),
  266. 'nativetype'=> oci_field_type($this->resultSet, $i),
  267. );
  268. }
  269. return $res;
  270. }
  271. /**
  272. * Returns the result set resource.
  273. * @return mixed
  274. */
  275. public function getResultResource()
  276. {
  277. return $this->resultSet;
  278. }
  279. /********************* reflection ****************d*g**/
  280. /**
  281. * Returns list of tables.
  282. * @return array
  283. */
  284. public function getTables()
  285. {
  286. $this->query('SELECT * FROM cat');
  287. $res = array();
  288. while ($row = $this->fetch(FALSE)) {
  289. if ($row[1] === 'TABLE' || $row[1] === 'VIEW') {
  290. $res[] = array(
  291. 'name' => $row[0],
  292. 'view' => $row[1] === 'VIEW',
  293. );
  294. }
  295. }
  296. $this->free();
  297. return $res;
  298. }
  299. /**
  300. * Returns metadata for all columns in a table.
  301. * @param string
  302. * @return array
  303. */
  304. public function getColumns($table)
  305. {
  306. throw new NotImplementedException;
  307. }
  308. /**
  309. * Returns metadata for all indexes in a table.
  310. * @param string
  311. * @return array
  312. */
  313. public function getIndexes($table)
  314. {
  315. throw new NotImplementedException;
  316. }
  317. /**
  318. * Returns metadata for all foreign keys in a table.
  319. * @param string
  320. * @return array
  321. */
  322. public function getForeignKeys($table)
  323. {
  324. throw new NotImplementedException;
  325. }
  326. }