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

/system/Zend/Db/Adapter/Pdo/Oci.php

https://gitlab.com/Ltaimao/wecenter
PHP | 378 lines | 187 code | 27 blank | 164 comment | 20 complexity | 31bcd9666e388a4a5d17a2ba9e7abdf0 MD5 | raw file
  1. <?php
  2. /**
  3. * Zend Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://framework.zend.com/license/new-bsd
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@zend.com so we can send you a copy immediately.
  14. *
  15. * @category Zend
  16. * @package Zend_Db
  17. * @subpackage Adapter
  18. * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
  19. * @license http://framework.zend.com/license/new-bsd New BSD License
  20. * @version $Id$
  21. */
  22. /**
  23. * @see Zend_Db_Adapter_Pdo_Abstract
  24. */
  25. //require_once 'Zend/Db/Adapter/Pdo/Abstract.php';
  26. /**
  27. * Class for connecting to Oracle databases and performing common operations.
  28. *
  29. * @category Zend
  30. * @package Zend_Db
  31. * @subpackage Adapter
  32. * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
  33. * @license http://framework.zend.com/license/new-bsd New BSD License
  34. */
  35. class Zend_Db_Adapter_Pdo_Oci extends Zend_Db_Adapter_Pdo_Abstract
  36. {
  37. /**
  38. * PDO type.
  39. *
  40. * @var string
  41. */
  42. protected $_pdoType = 'oci';
  43. /**
  44. * Default class name for a DB statement.
  45. *
  46. * @var string
  47. */
  48. protected $_defaultStmtClass = 'Zend_Db_Statement_Pdo_Oci';
  49. /**
  50. * Keys are UPPERCASE SQL datatypes or the constants
  51. * Zend_Db::INT_TYPE, Zend_Db::BIGINT_TYPE, or Zend_Db::FLOAT_TYPE.
  52. *
  53. * Values are:
  54. * 0 = 32-bit integer
  55. * 1 = 64-bit integer
  56. * 2 = float or decimal
  57. *
  58. * @var array Associative array of datatypes to values 0, 1, or 2.
  59. */
  60. protected $_numericDataTypes = array(
  61. Zend_Db::INT_TYPE => Zend_Db::INT_TYPE,
  62. Zend_Db::BIGINT_TYPE => Zend_Db::BIGINT_TYPE,
  63. Zend_Db::FLOAT_TYPE => Zend_Db::FLOAT_TYPE,
  64. 'BINARY_DOUBLE' => Zend_Db::FLOAT_TYPE,
  65. 'BINARY_FLOAT' => Zend_Db::FLOAT_TYPE,
  66. 'NUMBER' => Zend_Db::FLOAT_TYPE
  67. );
  68. /**
  69. * Creates a PDO DSN for the adapter from $this->_config settings.
  70. *
  71. * @return string
  72. */
  73. protected function _dsn()
  74. {
  75. // baseline of DSN parts
  76. $dsn = $this->_config;
  77. if (isset($dsn['host'])) {
  78. $tns = 'dbname=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)' .
  79. '(HOST=' . $dsn['host'] . ')';
  80. if (isset($dsn['port'])) {
  81. $tns .= '(PORT=' . $dsn['port'] . ')';
  82. } else {
  83. $tns .= '(PORT=1521)';
  84. }
  85. $tns .= '))(CONNECT_DATA=(SID=' . $dsn['dbname'] . ')))';
  86. } else {
  87. $tns = 'dbname=' . $dsn['dbname'];
  88. }
  89. if (isset($dsn['charset'])) {
  90. $tns .= ';charset=' . $dsn['charset'];
  91. }
  92. return $this->_pdoType . ':' . $tns;
  93. }
  94. /**
  95. * Quote a raw string.
  96. * Most PDO drivers have an implementation for the quote() method,
  97. * but the Oracle OCI driver must use the same implementation as the
  98. * Zend_Db_Adapter_Abstract class.
  99. *
  100. * @param string $value Raw string
  101. * @return string Quoted string
  102. */
  103. protected function _quote($value)
  104. {
  105. if (is_int($value) || is_float($value)) {
  106. return $value;
  107. }
  108. $value = str_replace("'", "''", $value);
  109. return "'" . addcslashes($value, "\000\n\r\\\032") . "'";
  110. }
  111. /**
  112. * Quote a table identifier and alias.
  113. *
  114. * @param string|array|Zend_Db_Expr $ident The identifier or expression.
  115. * @param string $alias An alias for the table.
  116. * @return string The quoted identifier and alias.
  117. */
  118. public function quoteTableAs($ident, $alias = null, $auto = false)
  119. {
  120. // Oracle doesn't allow the 'AS' keyword between the table identifier/expression and alias.
  121. return $this->_quoteIdentifierAs($ident, $alias, $auto, ' ');
  122. }
  123. /**
  124. * Returns a list of the tables in the database.
  125. *
  126. * @return array
  127. */
  128. public function listTables()
  129. {
  130. $data = $this->fetchCol('SELECT table_name FROM all_tables');
  131. return $data;
  132. }
  133. /**
  134. * Returns the column descriptions for a table.
  135. *
  136. * The return value is an associative array keyed by the column name,
  137. * as returned by the RDBMS.
  138. *
  139. * The value of each array element is an associative array
  140. * with the following keys:
  141. *
  142. * SCHEMA_NAME => string; name of schema
  143. * TABLE_NAME => string;
  144. * COLUMN_NAME => string; column name
  145. * COLUMN_POSITION => number; ordinal position of column in table
  146. * DATA_TYPE => string; SQL datatype name of column
  147. * DEFAULT => string; default expression of column, null if none
  148. * NULLABLE => boolean; true if column can have nulls
  149. * LENGTH => number; length of CHAR/VARCHAR
  150. * SCALE => number; scale of NUMERIC/DECIMAL
  151. * PRECISION => number; precision of NUMERIC/DECIMAL
  152. * UNSIGNED => boolean; unsigned property of an integer type
  153. * PRIMARY => boolean; true if column is part of the primary key
  154. * PRIMARY_POSITION => integer; position of column in primary key
  155. * IDENTITY => integer; true if column is auto-generated with unique values
  156. *
  157. * @todo Discover integer unsigned property.
  158. *
  159. * @param string $tableName
  160. * @param string $schemaName OPTIONAL
  161. * @return array
  162. */
  163. public function describeTable($tableName, $schemaName = null)
  164. {
  165. $version = $this->getServerVersion();
  166. if (($version === null) || version_compare($version, '9.0.0', '>=')) {
  167. $sql = "SELECT TC.TABLE_NAME, TC.OWNER, TC.COLUMN_NAME, TC.DATA_TYPE,
  168. TC.DATA_DEFAULT, TC.NULLABLE, TC.COLUMN_ID, TC.DATA_LENGTH,
  169. TC.DATA_SCALE, TC.DATA_PRECISION, C.CONSTRAINT_TYPE, CC.POSITION
  170. FROM ALL_TAB_COLUMNS TC
  171. LEFT JOIN (ALL_CONS_COLUMNS CC JOIN ALL_CONSTRAINTS C
  172. ON (CC.CONSTRAINT_NAME = C.CONSTRAINT_NAME AND CC.TABLE_NAME = C.TABLE_NAME AND CC.OWNER = C.OWNER AND C.CONSTRAINT_TYPE = 'P'))
  173. ON TC.TABLE_NAME = CC.TABLE_NAME AND TC.COLUMN_NAME = CC.COLUMN_NAME
  174. WHERE UPPER(TC.TABLE_NAME) = UPPER(:TBNAME)";
  175. $bind[':TBNAME'] = $tableName;
  176. if ($schemaName) {
  177. $sql .= ' AND UPPER(TC.OWNER) = UPPER(:SCNAME)';
  178. $bind[':SCNAME'] = $schemaName;
  179. }
  180. $sql .= ' ORDER BY TC.COLUMN_ID';
  181. } else {
  182. $subSql="SELECT AC.OWNER, AC.TABLE_NAME, ACC.COLUMN_NAME, AC.CONSTRAINT_TYPE, ACC.POSITION
  183. from ALL_CONSTRAINTS AC, ALL_CONS_COLUMNS ACC
  184. WHERE ACC.CONSTRAINT_NAME = AC.CONSTRAINT_NAME
  185. AND ACC.TABLE_NAME = AC.TABLE_NAME
  186. AND ACC.OWNER = AC.OWNER
  187. AND AC.CONSTRAINT_TYPE = 'P'
  188. AND UPPER(AC.TABLE_NAME) = UPPER(:TBNAME)";
  189. $bind[':TBNAME'] = $tableName;
  190. if ($schemaName) {
  191. $subSql .= ' AND UPPER(ACC.OWNER) = UPPER(:SCNAME)';
  192. $bind[':SCNAME'] = $schemaName;
  193. }
  194. $sql="SELECT TC.TABLE_NAME, TC.OWNER, TC.COLUMN_NAME, TC.DATA_TYPE,
  195. TC.DATA_DEFAULT, TC.NULLABLE, TC.COLUMN_ID, TC.DATA_LENGTH,
  196. TC.DATA_SCALE, TC.DATA_PRECISION, CC.CONSTRAINT_TYPE, CC.POSITION
  197. FROM ALL_TAB_COLUMNS TC, ($subSql) CC
  198. WHERE UPPER(TC.TABLE_NAME) = UPPER(:TBNAME)
  199. AND TC.OWNER = CC.OWNER(+) AND TC.TABLE_NAME = CC.TABLE_NAME(+) AND TC.COLUMN_NAME = CC.COLUMN_NAME(+)";
  200. if ($schemaName) {
  201. $sql .= ' AND UPPER(TC.OWNER) = UPPER(:SCNAME)';
  202. }
  203. $sql .= ' ORDER BY TC.COLUMN_ID';
  204. }
  205. $stmt = $this->query($sql, $bind);
  206. /**
  207. * Use FETCH_NUM so we are not dependent on the CASE attribute of the PDO connection
  208. */
  209. $result = $stmt->fetchAll(Zend_Db::FETCH_NUM);
  210. $table_name = 0;
  211. $owner = 1;
  212. $column_name = 2;
  213. $data_type = 3;
  214. $data_default = 4;
  215. $nullable = 5;
  216. $column_id = 6;
  217. $data_length = 7;
  218. $data_scale = 8;
  219. $data_precision = 9;
  220. $constraint_type = 10;
  221. $position = 11;
  222. $desc = array();
  223. foreach ($result as $key => $row) {
  224. list ($primary, $primaryPosition, $identity) = array(false, null, false);
  225. if ($row[$constraint_type] == 'P') {
  226. $primary = true;
  227. $primaryPosition = $row[$position];
  228. /**
  229. * Oracle does not support auto-increment keys.
  230. */
  231. $identity = false;
  232. }
  233. $desc[$this->foldCase($row[$column_name])] = array(
  234. 'SCHEMA_NAME' => $this->foldCase($row[$owner]),
  235. 'TABLE_NAME' => $this->foldCase($row[$table_name]),
  236. 'COLUMN_NAME' => $this->foldCase($row[$column_name]),
  237. 'COLUMN_POSITION' => $row[$column_id],
  238. 'DATA_TYPE' => $row[$data_type],
  239. 'DEFAULT' => $row[$data_default],
  240. 'NULLABLE' => (bool) ($row[$nullable] == 'Y'),
  241. 'LENGTH' => $row[$data_length],
  242. 'SCALE' => $row[$data_scale],
  243. 'PRECISION' => $row[$data_precision],
  244. 'UNSIGNED' => null, // @todo
  245. 'PRIMARY' => $primary,
  246. 'PRIMARY_POSITION' => $primaryPosition,
  247. 'IDENTITY' => $identity
  248. );
  249. }
  250. return $desc;
  251. }
  252. /**
  253. * Return the most recent value from the specified sequence in the database.
  254. * This is supported only on RDBMS brands that support sequences
  255. * (e.g. Oracle, PostgreSQL, DB2). Other RDBMS brands return null.
  256. *
  257. * @param string $sequenceName
  258. * @return integer
  259. */
  260. public function lastSequenceId($sequenceName)
  261. {
  262. $this->_connect();
  263. $value = $this->fetchOne('SELECT '.$this->quoteIdentifier($sequenceName, true).'.CURRVAL FROM dual');
  264. return $value;
  265. }
  266. /**
  267. * Generate a new value from the specified sequence in the database, and return it.
  268. * This is supported only on RDBMS brands that support sequences
  269. * (e.g. Oracle, PostgreSQL, DB2). Other RDBMS brands return null.
  270. *
  271. * @param string $sequenceName
  272. * @return integer
  273. */
  274. public function nextSequenceId($sequenceName)
  275. {
  276. $this->_connect();
  277. $value = $this->fetchOne('SELECT '.$this->quoteIdentifier($sequenceName, true).'.NEXTVAL FROM dual');
  278. return $value;
  279. }
  280. /**
  281. * Gets the last ID generated automatically by an IDENTITY/AUTOINCREMENT column.
  282. *
  283. * As a convention, on RDBMS brands that support sequences
  284. * (e.g. Oracle, PostgreSQL, DB2), this method forms the name of a sequence
  285. * from the arguments and returns the last id generated by that sequence.
  286. * On RDBMS brands that support IDENTITY/AUTOINCREMENT columns, this method
  287. * returns the last value generated for such a column, and the table name
  288. * argument is disregarded.
  289. *
  290. * Oracle does not support IDENTITY columns, so if the sequence is not
  291. * specified, this method returns null.
  292. *
  293. * @param string $tableName OPTIONAL Name of table.
  294. * @param string $primaryKey OPTIONAL Name of primary key column.
  295. * @return string
  296. * @throws Zend_Db_Adapter_Oracle_Exception
  297. */
  298. public function lastInsertId($tableName = null, $primaryKey = null)
  299. {
  300. if ($tableName !== null) {
  301. $sequenceName = $tableName;
  302. if ($primaryKey) {
  303. $sequenceName .= $this->foldCase("_$primaryKey");
  304. }
  305. $sequenceName .= $this->foldCase('_seq');
  306. return $this->lastSequenceId($sequenceName);
  307. }
  308. // No support for IDENTITY columns; return null
  309. return null;
  310. }
  311. /**
  312. * Adds an adapter-specific LIMIT clause to the SELECT statement.
  313. *
  314. * @param string $sql
  315. * @param integer $count
  316. * @param integer $offset
  317. * @throws Zend_Db_Adapter_Exception
  318. * @return string
  319. */
  320. public function limit($sql, $count, $offset = 0)
  321. {
  322. $count = intval($count);
  323. if ($count <= 0) {
  324. /** @see Zend_Db_Adapter_Exception */
  325. //require_once 'Zend/Db/Adapter/Exception.php';
  326. throw new Zend_Db_Adapter_Exception("LIMIT argument count=$count is not valid");
  327. }
  328. $offset = intval($offset);
  329. if ($offset < 0) {
  330. /** @see Zend_Db_Adapter_Exception */
  331. //require_once 'Zend/Db/Adapter/Exception.php';
  332. throw new Zend_Db_Adapter_Exception("LIMIT argument offset=$offset is not valid");
  333. }
  334. /**
  335. * Oracle does not implement the LIMIT clause as some RDBMS do.
  336. * We have to simulate it with subqueries and ROWNUM.
  337. * Unfortunately because we use the column wildcard "*",
  338. * this puts an extra column into the query result set.
  339. */
  340. $limit_sql = "SELECT z2.*
  341. FROM (
  342. SELECT z1.*, ROWNUM AS \"zend_db_rownum\"
  343. FROM (
  344. " . $sql . "
  345. ) z1
  346. ) z2
  347. WHERE z2.\"zend_db_rownum\" BETWEEN " . ($offset+1) . " AND " . ($offset+$count);
  348. return $limit_sql;
  349. }
  350. }