PageRenderTime 48ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/cakephp/vendors/cake/libs/model/datasources/dbo/dbo_adodb.php

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