PageRenderTime 51ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/models/datasources/dbo/dbo_odbc.php

https://github.com/radig/datasources
PHP | 379 lines | 190 code | 39 blank | 150 comment | 40 complexity | c5afaf36c9bd2140c95674661518c9cc MD5 | raw file
  1. <?php
  2. /**
  3. * ODBC for DBO
  4. *
  5. * PHP versions 4 and 5
  6. *
  7. * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
  8. * Copyright 2005-2009, Cake Software Foundation, Inc. (http://cakefoundation.org)
  9. *
  10. * Licensed under The MIT License
  11. * Redistributions of files must retain the above copyright notice.
  12. *
  13. * @copyright Copyright 2005-2009, Cake Software Foundation, Inc. (http://cakefoundation.org)
  14. * @link http://cakephp.org CakePHP(tm) Project
  15. * @package datasources
  16. * @subpackage datasources.models.datasources.dbo
  17. * @since CakePHP Datasources v 0.1
  18. * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
  19. */
  20. App::import('Datasource','DboSource');
  21. /**
  22. * Short description for class.
  23. *
  24. * Long description for class
  25. *
  26. * @package cake
  27. * @subpackage cake.cake.libs.model.datasources.dbo
  28. */
  29. class DboOdbc extends DboSource {
  30. /**
  31. * Driver description
  32. *
  33. * @var string
  34. */
  35. var $description = "ODBC DBO Driver";
  36. /**
  37. * Table/column starting quote
  38. *
  39. * @var string
  40. */
  41. var $startQuote = "`";
  42. /**
  43. * Table/column end quote
  44. *
  45. * @var string
  46. */
  47. var $endQuote = "`";
  48. /**
  49. * Driver base configuration
  50. *
  51. * @var array
  52. */
  53. var $_baseConfig = array(
  54. 'persistent' => true,
  55. 'login' => 'root',
  56. 'password' => '',
  57. 'database' => 'cake',
  58. 'connect' => 'odbc_pconnect'
  59. );
  60. /**
  61. * Columns
  62. *
  63. * @var array
  64. */
  65. var $columns = array();
  66. // var $columns = array('primary_key' => array('name' => 'int(11) DEFAULT NULL auto_increment'),
  67. // 'string' => array('name' => 'varchar', 'limit' => '255'),
  68. // 'text' => array('name' => 'text'),
  69. // 'integer' => array('name' => 'int', 'limit' => '11'),
  70. // 'float' => array('name' => 'float'),
  71. // 'datetime' => array('name' => 'datetime', 'format' => 'Y-m-d h:i:s', 'formatter' => 'date'),
  72. // 'timestamp' => array('name' => 'datetime', 'format' => 'Y-m-d h:i:s', 'formatter' => 'date'),
  73. // 'time' => array('name' => 'time', 'format' => 'h:i:s', 'formatter' => 'date'),
  74. // 'date' => array('name' => 'date', 'format' => 'Y-m-d', 'formatter' => 'date'),
  75. // 'binary' => array('name' => 'blob'),
  76. // 'boolean' => array('name' => 'tinyint', 'limit' => '1'));
  77. /**
  78. * Connects to the database using options in the given configuration array.
  79. *
  80. * @return boolean True if the database could be connected, else false
  81. */
  82. function connect() {
  83. $config = $this->config;
  84. $connect = $config['connect'];
  85. if (!$config['persistent']) {
  86. $connect = 'odbc_connect';
  87. }
  88. if (!function_exists($connect)) {
  89. exit('no odbc?');
  90. }
  91. $this->connected = false;
  92. $this->connection = $connect($config['database'], $config['login'], $config['password'], SQL_CUR_USE_ODBC);
  93. if ($this->connection) {
  94. $this->connected = true;
  95. }
  96. return $this->connected;
  97. }
  98. /**
  99. * Check if the ODBC extension is installed/loaded
  100. *
  101. * @return boolean
  102. */
  103. function enabled() {
  104. return extension_loaded('odbc');
  105. }
  106. /**
  107. * Disconnects from database.
  108. *
  109. * @return boolean True if the database could be disconnected, else false
  110. */
  111. function disconnect() {
  112. return @odbc_close($this->connection);
  113. }
  114. /**
  115. * Executes given SQL statement.
  116. *
  117. * @param string $sql SQL statement
  118. * @return resource Result resource identifier
  119. * @access protected
  120. */
  121. function _execute($sql) {
  122. switch ($sql) {
  123. case 'BEGIN':
  124. return odbc_autocommit($this->connection, false);
  125. case 'COMMIT':
  126. return odbc_commit($this->connection);
  127. case 'ROLLBACK':
  128. return odbc_rollback($this->connection);
  129. }
  130. // TODO: should flags be set? possible requirement: SQL_CURSOR_STATIC
  131. return odbc_exec($this->connection, $sql);
  132. }
  133. /**
  134. * Returns an array of sources (tables) in the database.
  135. *
  136. * @return array Array of tablenames in the database
  137. */
  138. function listSources() {
  139. $cache = parent::listSources();
  140. if ($cache != null) {
  141. return $cache;
  142. }
  143. $result = odbc_tables($this->connection);
  144. $tables = array();
  145. while (odbc_fetch_row($result)) {
  146. array_push($tables, odbc_result($result, 'TABLE_NAME'));
  147. }
  148. parent::listSources($tables);
  149. return $tables;
  150. }
  151. /**
  152. * Returns an array of the fields in given table name.
  153. *
  154. * @param Model $model Model object to describe
  155. * @return array Fields in table. Keys are name and type
  156. */
  157. function &describe(&$model) {
  158. $cache=parent::describe($model);
  159. if ($cache != null) {
  160. return $cache;
  161. }
  162. $fields = array();
  163. $sql = 'SELECT * FROM ' . $this->fullTableName($model);
  164. $result = odbc_exec($this->connection, $sql);
  165. $count = odbc_num_fields($result);
  166. for ($i = 1; $i <= $count; $i++) {
  167. $cols[$i - 1] = odbc_field_name($result, $i);
  168. }
  169. foreach ($cols as $column) {
  170. $type = odbc_field_type(odbc_exec($this->connection, 'SELECT ' . $column . ' FROM ' . $this->fullTableName($model)), 1);
  171. $fields[$column] = array('type' => $type);
  172. }
  173. $this->__cacheDescription($model->tablePrefix . $model->table, $fields);
  174. return $fields;
  175. }
  176. /**
  177. * Returns a quoted and escaped string of $data for use in an SQL statement.
  178. *
  179. * @param string $data String to be prepared for use in an SQL statement
  180. * @param string $column The column into which this data will be inserted
  181. * @return string Quoted and escaped
  182. * @todo Add logic that formats/escapes data based on column type
  183. */
  184. function value($data, $column = null) {
  185. $parent = parent::value($data, $column);
  186. if ($parent != null) {
  187. return $parent;
  188. }
  189. if ($data === null || (is_array($data) && empty($data))) {
  190. return 'NULL';
  191. }
  192. if (!is_numeric($data)) {
  193. return "'" . $data . "'";
  194. }
  195. return $data;
  196. }
  197. /**
  198. * Returns a formatted error message from previous database operation.
  199. *
  200. * @return string Error message with error number
  201. */
  202. function lastError() {
  203. if ($error = odbc_errormsg($this->connection)) {
  204. return odbc_error($this->connection) . ': ' . $error;
  205. }
  206. return null;
  207. }
  208. /**
  209. * Returns number of affected rows in previous database operation. If no previous operation exists,
  210. * this returns false.
  211. *
  212. * @return integer Number of affected rows
  213. */
  214. function lastAffected() {
  215. if ($this->hasResult()) {
  216. return odbc_num_rows($this->_result);
  217. }
  218. return null;
  219. }
  220. /**
  221. * Returns number of rows in previous resultset. If no previous resultset exists,
  222. * this returns false.
  223. *
  224. * @return int Number of rows in resultset
  225. */
  226. function lastNumRows() {
  227. if ($this->hasResult()) {
  228. return odbc_num_rows($this->_result);
  229. }
  230. return null;
  231. }
  232. /**
  233. * Returns the ID generated from the previous INSERT operation.
  234. *
  235. * @param unknown_type $source
  236. * @return int
  237. */
  238. function lastInsertId($source = null) {
  239. $result = $this->fetchRow('SELECT @@IDENTITY');
  240. return $result[0];
  241. }
  242. /**
  243. * Enter description here...
  244. *
  245. * @param string $real Real database-layer column type (i.e. "varchar(255)")
  246. */
  247. function column($real) {
  248. if (is_array($real)) {
  249. $col=$real['name'];
  250. if (isset($real['limit'])) {
  251. $col .= '(' . $real['limit'] . ')';
  252. }
  253. return $col;
  254. }
  255. return $real;
  256. }
  257. /**
  258. * Enter description here...
  259. *
  260. * @param unknown_type $results
  261. */
  262. function resultSet(&$results) {
  263. $this->results =& $results;
  264. $num_fields = odbc_num_fields($results);
  265. $this->map = array();
  266. $index = 0;
  267. $j = 0;
  268. while ($j < $num_fields) {
  269. $column = odbc_field_name($results, $j+1);
  270. if (strpos($column, '_dot_') !== false) {
  271. list($table, $column) = explode('_dot_', $column);
  272. $this->map[$index++] = array($table, $column);
  273. } else {
  274. $this->map[$index++] = array(0, $column);
  275. }
  276. $j++;
  277. }
  278. }
  279. /**
  280. * Generates the fields list of an SQL query.
  281. *
  282. * @param Model $model
  283. * @param string $alias Alias tablename
  284. * @param mixed $fields
  285. * @return array
  286. */
  287. function fields(&$model, $alias = null, $fields = null, $quote = true) {
  288. if (empty($alias)) {
  289. $alias = $model->name;
  290. }
  291. if (!is_array($fields)) {
  292. if ($fields != null) {
  293. $fields = array_map('trim', explode(',', $fields));
  294. } else {
  295. foreach($model->tableToModel as $tableName => $modelName) {
  296. foreach($this->__descriptions[$model->tablePrefix .$tableName] as $field => $type) {
  297. $fields[] = $modelName . '.' . $field;
  298. }
  299. }
  300. }
  301. }
  302. $count = count($fields);
  303. if ($count >= 1 && $fields[0] != '*' && strpos($fields[0], 'COUNT(*)') === false) {
  304. for ($i = 0; $i < $count; $i++) {
  305. if (!preg_match('/^.+\\(.*\\)/', $fields[$i])) {
  306. $prepend = '';
  307. if (strpos($fields[$i], 'DISTINCT') !== false) {
  308. $prepend = 'DISTINCT ';
  309. $fields[$i] = trim(str_replace('DISTINCT', '', $fields[$i]));
  310. }
  311. if (strrpos($fields[$i], '.') === false) {
  312. $fields[$i] = $prepend . $this->name($alias) . '.' . $this->name($fields[$i]) . ' AS ' . $this->name($alias . '_dot_' . $fields[$i]);
  313. } else {
  314. $build = explode('.', $fields[$i]);
  315. $fields[$i] = $prepend . $this->name($build[0]) . '.' . $this->name($build[1]) . ' AS ' . $this->name($build[0] . '_dot_' . $build[1]);
  316. }
  317. }
  318. }
  319. }
  320. return $fields;
  321. }
  322. /**
  323. * Fetches the next row from the current result set
  324. *
  325. * @return unknown
  326. */
  327. function fetchResult() {
  328. if ($row = odbc_fetch_row($this->results)) {
  329. $resultRow = array();
  330. $numFields = odbc_num_fields($this->results);
  331. $i = 0;
  332. for($i = 0; $i < $numFields; $i++) {
  333. list($table, $column) = $this->map[$i];
  334. $resultRow[$table][$column] = odbc_result($this->results, $i + 1);
  335. }
  336. return $resultRow;
  337. }
  338. return false;
  339. }
  340. }