PageRenderTime 59ms CodeModel.GetById 30ms RepoModel.GetById 1ms app.codeStats 0ms

/acl_auth.local/cake/libs/model/datasources/dbo/dbo_adodb.php

https://github.com/miamiruby/cakestuff
PHP | 527 lines | 292 code | 36 blank | 199 comment | 79 complexity | 2e07f1d616c7252b3a1b487e4b71f6d5 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause, LGPL-2.0, MIT
  1. <?php
  2. /* SVN FILE: $Id: dbo_adodb.php 7690 2008-10-02 04:56:53Z nate $ */
  3. /**
  4. * AdoDB layer for DBO.
  5. *
  6. * Long description for file
  7. *
  8. * PHP versions 4 and 5
  9. *
  10. * CakePHP(tm) : Rapid Development Framework <http://www.cakephp.org/>
  11. * Copyright 2005-2008, Cake Software Foundation, Inc.
  12. * 1785 E. Sahara Avenue, Suite 490-204
  13. * Las Vegas, Nevada 89104
  14. *
  15. * Licensed under The MIT License
  16. * Redistributions of files must retain the above copyright notice.
  17. *
  18. * @filesource
  19. * @copyright Copyright 2005-2008, Cake Software Foundation, Inc.
  20. * @link http://www.cakefoundation.org/projects/info/cakephp CakePHP(tm) Project
  21. * @package cake
  22. * @subpackage cake.cake.libs.model.datasources.dbo
  23. * @since CakePHP(tm) v 0.2.9
  24. * @version $Revision: 7690 $
  25. * @modifiedby $LastChangedBy: nate $
  26. * @lastmodified $Date: 2008-10-02 00:56:53 -0400 (Thu, 02 Oct 2008) $
  27. * @license http://www.opensource.org/licenses/mit-license.php The MIT License
  28. */
  29. /**
  30. * Include AdoDB files.
  31. */
  32. App::import('Vendor', 'NewADOConnection', array('file' => 'adodb' . DS . 'adodb.inc.php'));
  33. /**
  34. * AdoDB DBO implementation.
  35. *
  36. * Database abstraction implementation for the AdoDB library.
  37. *
  38. * @package cake
  39. * @subpackage cake.cake.libs.model.datasources.dbo
  40. */
  41. class DboAdodb extends DboSource {
  42. /**
  43. * Enter description here...
  44. *
  45. * @var string
  46. */
  47. var $description = "ADOdb DBO Driver";
  48. /**
  49. * ADOConnection object with which we connect.
  50. *
  51. * @var ADOConnection The connection object.
  52. * @access private
  53. */
  54. var $_adodb = null;
  55. /**
  56. * Array translating ADOdb column MetaTypes to cake-supported metatypes
  57. *
  58. * @var array
  59. * @access private
  60. */
  61. var $_adodbColumnTypes = array(
  62. 'string' => 'C',
  63. 'text' => 'X',
  64. 'date' => 'D',
  65. 'timestamp' => 'T',
  66. 'time' => 'T',
  67. 'datetime' => 'T',
  68. 'boolean' => 'L',
  69. 'float' => 'N',
  70. 'integer' => 'I',
  71. 'binary' => 'R',
  72. );
  73. /**
  74. * ADOdb column definition
  75. *
  76. * @var array
  77. */
  78. var $columns = array(
  79. 'primary_key' => array('name' => 'R', 'limit' => 11),
  80. 'string' => array('name' => 'C', 'limit' => '255'),
  81. 'text' => array('name' => 'X'),
  82. 'integer' => array('name' => 'I', 'limit' => '11', 'formatter' => 'intval'),
  83. 'float' => array('name' => 'N', 'formatter' => 'floatval'),
  84. 'timestamp' => array('name' => 'T', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
  85. 'time' => array('name' => 'T', 'format' => 'H:i:s', 'formatter' => 'date'),
  86. 'datetime' => array('name' => 'T', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
  87. 'date' => array('name' => 'D', 'format' => 'Y-m-d', 'formatter' => 'date'),
  88. 'binary' => array('name' => 'B'),
  89. 'boolean' => array('name' => 'L', 'limit' => '1')
  90. );
  91. /**
  92. * Connects to the database using options in the given configuration array.
  93. *
  94. * @param array $config Configuration array for connecting
  95. */
  96. function connect() {
  97. $config = $this->config;
  98. $persistent = strrpos($config['connect'], '|p');
  99. if ($persistent === false) {
  100. $adodb_driver = $config['connect'];
  101. $connect = 'Connect';
  102. } else {
  103. $adodb_driver = substr($config['connect'], 0, $persistent);
  104. $connect = 'PConnect';
  105. }
  106. $this->_adodb = NewADOConnection($adodb_driver);
  107. $this->_adodbDataDict = NewDataDictionary($this->_adodb, $adodb_driver);
  108. $this->startQuote = $this->_adodb->nameQuote;
  109. $this->endQuote = $this->_adodb->nameQuote;
  110. $this->connected = $this->_adodb->$connect($config['host'], $config['login'], $config['password'], $config['database']);
  111. $this->_adodbMetatyper = &$this->_adodb->execute('Select 1');
  112. return $this->connected;
  113. }
  114. /**
  115. * Disconnects from database.
  116. *
  117. * @return boolean True if the database could be disconnected, else false
  118. */
  119. function disconnect() {
  120. return $this->_adodb->Close();
  121. }
  122. /**
  123. * Executes given SQL statement.
  124. *
  125. * @param string $sql SQL statement
  126. * @return resource Result resource identifier
  127. */
  128. function _execute($sql) {
  129. global $ADODB_FETCH_MODE;
  130. $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
  131. return $this->_adodb->execute($sql);
  132. }
  133. /**
  134. * Returns a row from given resultset as an array .
  135. *
  136. * @return array The fetched row as an array
  137. */
  138. /**
  139. * Returns a row from current resultset as an array .
  140. *
  141. * @return array The fetched row as an array
  142. */
  143. function fetchRow($sql = null) {
  144. if (!empty($sql) && is_string($sql) && strlen($sql) > 5) {
  145. if (!$this->execute($sql)) {
  146. return null;
  147. }
  148. }
  149. if (!$this->hasResult()) {
  150. return null;
  151. } else {
  152. $resultRow = $this->_result->FetchRow();
  153. $this->resultSet($resultRow);
  154. return $this->fetchResult();
  155. }
  156. }
  157. /**
  158. * Begin a transaction
  159. *
  160. * @param unknown_type $model
  161. * @return boolean True on success, false on fail
  162. * (i.e. if the database/model does not support transactions).
  163. */
  164. function begin(&$model) {
  165. if (parent::begin($model)) {
  166. if ($this->_adodb->BeginTrans()) {
  167. $this->_transactionStarted = true;
  168. return true;
  169. }
  170. }
  171. return false;
  172. }
  173. /**
  174. * Commit a transaction
  175. *
  176. * @param unknown_type $model
  177. * @return boolean True on success, false on fail
  178. * (i.e. if the database/model does not support transactions,
  179. * or a transaction has not started).
  180. */
  181. function commit(&$model) {
  182. if (parent::commit($model)) {
  183. $this->_transactionStarted = false;
  184. return $this->_adodb->CommitTrans();
  185. }
  186. return false;
  187. }
  188. /**
  189. * Rollback a transaction
  190. *
  191. * @param unknown_type $model
  192. * @return boolean True on success, false on fail
  193. * (i.e. if the database/model does not support transactions,
  194. * or a transaction has not started).
  195. */
  196. function rollback(&$model) {
  197. if (parent::rollback($model)) {
  198. return $this->_adodb->RollbackTrans();
  199. }
  200. return false;
  201. }
  202. /**
  203. * Returns an array of tables in the database. If there are no tables, an error is raised and the application exits.
  204. *
  205. * @return array Array of tablenames in the database
  206. */
  207. function listSources() {
  208. $tables = $this->_adodb->MetaTables('TABLES');
  209. if (!sizeof($tables) > 0) {
  210. trigger_error(ERROR_NO_TABLE_LIST, E_USER_NOTICE);
  211. exit;
  212. }
  213. return $tables;
  214. }
  215. /**
  216. * Returns an array of the fields in the table used by the given model.
  217. *
  218. * @param AppModel $model Model object
  219. * @return array Fields in table. Keys are name and type
  220. */
  221. function describe(&$model) {
  222. $cache = parent::describe($model);
  223. if ($cache != null) {
  224. return $cache;
  225. }
  226. $fields = false;
  227. $cols = $this->_adodb->MetaColumns($this->fullTableName($model, false));
  228. foreach ($cols as $column) {
  229. $fields[$column->name] = array(
  230. 'type' => $this->column($column->type),
  231. 'null' => !$column->not_null,
  232. 'length' => $column->max_length,
  233. );
  234. if ($column->has_default) {
  235. $fields[$column->name]['default'] = $column->default_value;
  236. }
  237. if ($column->primary_key == 1) {
  238. $fields[$column->name]['key'] = 'primary';
  239. }
  240. }
  241. $this->__cacheDescription($this->fullTableName($model, false), $fields);
  242. return $fields;
  243. }
  244. /**
  245. * Returns a formatted error message from previous database operation.
  246. *
  247. * @return string Error message
  248. */
  249. function lastError() {
  250. return $this->_adodb->ErrorMsg();
  251. }
  252. /**
  253. * Returns number of affected rows in previous database operation, or false if no previous operation exists.
  254. *
  255. * @return integer Number of affected rows
  256. */
  257. function lastAffected() {
  258. return $this->_adodb->Affected_Rows();
  259. }
  260. /**
  261. * Returns number of rows in previous resultset, or false if no previous resultset exists.
  262. *
  263. * @return integer Number of rows in resultset
  264. */
  265. function lastNumRows() {
  266. return $this->_result ? $this->_result->RecordCount() : false;
  267. }
  268. /**
  269. * Returns the ID generated from the previous INSERT operation.
  270. *
  271. * @return int
  272. *
  273. * @Returns the last autonumbering ID inserted. Returns false if function not supported.
  274. */
  275. function lastInsertId() {
  276. return $this->_adodb->Insert_ID();
  277. }
  278. /**
  279. * Returns a LIMIT statement in the correct format for the particular database.
  280. *
  281. * @param integer $limit Limit of results returned
  282. * @param integer $offset Offset from which to start results
  283. * @return string SQL limit/offset statement
  284. * @todo Please change output string to whatever select your database accepts. adodb doesn't allow us to get the correct limit string out of it.
  285. */
  286. function limit($limit, $offset = null) {
  287. if ($limit) {
  288. $rt = '';
  289. if (!strpos(strtolower($limit), 'limit') || strpos(strtolower($limit), 'limit') === 0) {
  290. $rt = ' LIMIT';
  291. }
  292. if ($offset) {
  293. $rt .= ' ' . $offset . ',';
  294. }
  295. $rt .= ' ' . $limit;
  296. return $rt;
  297. }
  298. return null;
  299. // please change to whatever select your database accepts
  300. // adodb doesn't allow us to get the correct limit string out of it
  301. }
  302. /**
  303. * Converts database-layer column types to basic types
  304. *
  305. * @param string $real Real database-layer column type (i.e. "varchar(255)")
  306. * @return string Abstract column type (i.e. "string")
  307. */
  308. function column($real) {
  309. $metaTypes = array_flip($this->_adodbColumnTypes);
  310. $interpreted_type = $this->_adodbMetatyper->MetaType($real);
  311. if (!isset($metaTypes[$interpreted_type])) {
  312. return 'text';
  313. }
  314. return $metaTypes[$interpreted_type];
  315. }
  316. /**
  317. * Returns a quoted and escaped string of $data for use in an SQL statement.
  318. *
  319. * @param string $data String to be prepared for use in an SQL statement
  320. * @param string $column_type The type of the column into which this data will be inserted
  321. * @param boolean $safe Whether or not numeric data should be handled automagically if no column data is provided
  322. * @return string Quoted and escaped data
  323. */
  324. function value($data, $column = null, $safe = false) {
  325. $parent = parent::value($data, $column, $safe);
  326. if ($parent != null) {
  327. return $parent;
  328. }
  329. if ($data === null) {
  330. return 'NULL';
  331. }
  332. if ($data === '') {
  333. return "''";
  334. }
  335. return $this->_adodb->qstr($data);
  336. }
  337. /**
  338. * Generates the fields list of an SQL query.
  339. *
  340. * @param Model $model
  341. * @param string $alias Alias tablename
  342. * @param mixed $fields
  343. * @return array
  344. */
  345. function fields(&$model, $alias = null, $fields = array(), $quote = true) {
  346. if (empty($alias)) {
  347. $alias = $model->alias;
  348. }
  349. $fields = parent::fields($model, $alias, $fields, false);
  350. if (!$quote) {
  351. return $fields;
  352. }
  353. $count = count($fields);
  354. if ($count >= 1 && $fields[0] != '*' && strpos($fields[0], 'COUNT(*)') === false) {
  355. for ($i = 0; $i < $count; $i++) {
  356. if (!preg_match('/^.+\\(.*\\)/', $fields[$i]) && !preg_match('/\s+AS\s+/', $fields[$i])) {
  357. $prepend = '';
  358. if (strpos($fields[$i], 'DISTINCT') !== false) {
  359. $prepend = 'DISTINCT ';
  360. $fields[$i] = trim(str_replace('DISTINCT', '', $fields[$i]));
  361. }
  362. if (strrpos($fields[$i], '.') === false) {
  363. $fields[$i] = $prepend . $this->name($alias) . '.' . $this->name($fields[$i]) . ' AS ' . $this->name($alias . '__' . $fields[$i]);
  364. } else {
  365. $build = explode('.', $fields[$i]);
  366. $fields[$i] = $prepend . $this->name($build[0]) . '.' . $this->name($build[1]) . ' AS ' . $this->name($build[0] . '__' . $build[1]);
  367. }
  368. }
  369. }
  370. }
  371. return $fields;
  372. }
  373. /**
  374. * Build ResultSets and map data
  375. *
  376. * @param array $results
  377. */
  378. function resultSet(&$results) {
  379. $num_fields = count($results);
  380. $fields = array_keys($results);
  381. $this->results =& $results;
  382. $this->map = array();
  383. $index = 0;
  384. $j = 0;
  385. while ($j < $num_fields) {
  386. $columnName = $fields[$j];
  387. if (strpos($columnName, '__')) {
  388. $parts = explode('__', $columnName);
  389. $this->map[$index++] = array($parts[0], $parts[1]);
  390. } else {
  391. $this->map[$index++] = array(0, $columnName);
  392. }
  393. $j++;
  394. }
  395. }
  396. /**
  397. * Fetches the next row from the current result set
  398. *
  399. * @return unknown
  400. */
  401. function fetchResult() {
  402. if (!empty($this->results)) {
  403. $row = $this->results;
  404. } else {
  405. $row = $this->_result->FetchRow();
  406. }
  407. if (empty($row)) {
  408. return false;
  409. }
  410. $resultRow = array();
  411. $fields = array_keys($row);
  412. $count = count($fields);
  413. $i = 0;
  414. for ($i = 0; $i < $count; $i++) { //$row as $index => $field) {
  415. list($table, $column) = $this->map[$i];
  416. $resultRow[$table][$column] = $row[$fields[$i]];
  417. }
  418. return $resultRow;
  419. }
  420. /**
  421. * Generate a database-native column schema string
  422. *
  423. * @param array $column An array structured like the following: array('name'=>'value', 'type'=>'value'[, options]),
  424. * where options can be 'default', 'length', or 'key'.
  425. * @return string
  426. */
  427. function buildColumn($column) {
  428. $name = $type = null;
  429. extract(array_merge(array('null' => true), $column));
  430. if (empty($name) || empty($type)) {
  431. trigger_error('Column name or type not defined in schema', E_USER_WARNING);
  432. return null;
  433. }
  434. //$metaTypes = array_flip($this->_adodbColumnTypes);
  435. if (!isset($this->_adodbColumnTypes[$type])) {
  436. trigger_error("Column type {$type} does not exist", E_USER_WARNING);
  437. return null;
  438. }
  439. $metaType = $this->_adodbColumnTypes[$type];
  440. $concreteType = $this->_adodbDataDict->ActualType($metaType);
  441. $real = $this->columns[$type];
  442. //UUIDs are broken so fix them.
  443. if ($type == 'string' && isset($real['length']) && $real['length'] == 36) {
  444. $concreteType = 'CHAR';
  445. }
  446. $out = $this->name($name) . ' ' . $concreteType;
  447. if (isset($real['limit']) || isset($real['length']) || isset($column['limit']) || isset($column['length'])) {
  448. if (isset($column['length'])) {
  449. $length = $column['length'];
  450. } elseif (isset($column['limit'])) {
  451. $length = $column['limit'];
  452. } elseif (isset($real['length'])) {
  453. $length = $real['length'];
  454. } else {
  455. $length = $real['limit'];
  456. }
  457. $out .= '(' . $length . ')';
  458. }
  459. $_notNull = $_default = $_autoInc = $_constraint = $_unsigned = false;
  460. if (isset($column['key']) && $column['key'] == 'primary' && $type == 'integer') {
  461. $_constraint = '';
  462. $_autoInc = true;
  463. } elseif (isset($column['key']) && $column['key'] == 'primary') {
  464. $_notNull = '';
  465. } elseif (isset($column['default']) && isset($column['null']) && $column['null'] == false) {
  466. $_notNull = true;
  467. $_default = $column['default'];
  468. } elseif ( isset($column['null']) && $column['null'] == true) {
  469. $_notNull = false;
  470. $_default = 'NULL';
  471. }
  472. if (isset($column['default']) && $_default == false) {
  473. $_default = $this->value($column['default']);
  474. }
  475. if (isset($column['null']) && $column['null'] == false) {
  476. $_notNull = true;
  477. }
  478. //use concrete instance of DataDict to make the suffixes for us.
  479. $out .= $this->_adodbDataDict->_CreateSuffix($out, $metaType, $_notNull, $_default, $_autoInc, $_constraint, $_unsigned);
  480. return $out;
  481. }
  482. /**
  483. * Checks if the result is valid
  484. *
  485. * @return boolean True if the result is valid, else false
  486. */
  487. function hasResult() {
  488. return is_object($this->_result) && !$this->_result->EOF;
  489. }
  490. }
  491. ?>