Automatically exported from code.google.com/p/planningalerts
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

426 lines
16 KiB

  1. <?php
  2. // vim: set et ts=4 sw=4 fdm=marker:
  3. // +----------------------------------------------------------------------+
  4. // | PHP versions 4 and 5 |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, |
  7. // | Stig. S. Bakken, Lukas Smith |
  8. // | All rights reserved. |
  9. // +----------------------------------------------------------------------+
  10. // | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB |
  11. // | API as well as database abstraction for PHP applications. |
  12. // | This LICENSE is in the BSD license style. |
  13. // | |
  14. // | Redistribution and use in source and binary forms, with or without |
  15. // | modification, are permitted provided that the following conditions |
  16. // | are met: |
  17. // | |
  18. // | Redistributions of source code must retain the above copyright |
  19. // | notice, this list of conditions and the following disclaimer. |
  20. // | |
  21. // | Redistributions in binary form must reproduce the above copyright |
  22. // | notice, this list of conditions and the following disclaimer in the |
  23. // | documentation and/or other materials provided with the distribution. |
  24. // | |
  25. // | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, |
  26. // | Lukas Smith nor the names of his contributors may be used to endorse |
  27. // | or promote products derived from this software without specific prior|
  28. // | written permission. |
  29. // | |
  30. // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
  31. // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
  32. // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
  33. // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
  34. // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
  35. // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
  36. // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
  37. // | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
  38. // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
  39. // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
  40. // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
  41. // | POSSIBILITY OF SUCH DAMAGE. |
  42. // +----------------------------------------------------------------------+
  43. // | Author: Lukas Smith <smith@pooteeweet.org> |
  44. // +----------------------------------------------------------------------+
  45. //
  46. // $Id: mysql.php,v 1.51 2006/08/12 15:58:19 lsmith Exp $
  47. //
  48. require_once 'MDB2/Driver/Datatype/Common.php';
  49. /**
  50. * MDB2 MySQL driver
  51. *
  52. * @package MDB2
  53. * @category Database
  54. * @author Lukas Smith <smith@pooteeweet.org>
  55. */
  56. class MDB2_Driver_Datatype_mysql extends MDB2_Driver_Datatype_Common
  57. {
  58. // }}}
  59. // {{{ getTypeDeclaration()
  60. /**
  61. * Obtain DBMS specific SQL code portion needed to declare an text type
  62. * field to be used in statements like CREATE TABLE.
  63. *
  64. * @param array $field associative array with the name of the properties
  65. * of the field being declared as array indexes. Currently, the types
  66. * of supported field properties are as follows:
  67. *
  68. * length
  69. * Integer value that determines the maximum length of the text
  70. * field. If this argument is missing the field should be
  71. * declared to have the longest length allowed by the DBMS.
  72. *
  73. * default
  74. * Text value to be used as default for this field.
  75. *
  76. * notnull
  77. * Boolean flag that indicates whether this field is constrained
  78. * to not be set to null.
  79. * @return string DBMS specific SQL code portion that should be used to
  80. * declare the specified field.
  81. * @access public
  82. */
  83. function getTypeDeclaration($field)
  84. {
  85. $db =& $this->getDBInstance();
  86. if (PEAR::isError($db)) {
  87. return $db;
  88. }
  89. switch ($field['type']) {
  90. case 'text':
  91. if (empty($field['length']) && array_key_exists('default', $field)) {
  92. $field['length'] = $db->varchar_max_length;
  93. }
  94. $length = !empty($field['length']) ? $field['length'] : false;
  95. $fixed = !empty($field['fixed']) ? $field['fixed'] : false;
  96. return $fixed ? ($length ? 'CHAR('.$length.')' : 'CHAR(255)')
  97. : ($length ? 'VARCHAR('.$length.')' : 'TEXT');
  98. case 'clob':
  99. if (!empty($field['length'])) {
  100. $length = $field['length'];
  101. if ($length <= 255) {
  102. return 'TINYTEXT';
  103. } elseif ($length <= 65535) {
  104. return 'TEXT';
  105. } elseif ($length <= 16777215) {
  106. return 'MEDIUMTEXT';
  107. }
  108. }
  109. return 'LONGTEXT';
  110. case 'blob':
  111. if (!empty($field['length'])) {
  112. $length = $field['length'];
  113. if ($length <= 255) {
  114. return 'TINYBLOB';
  115. } elseif ($length <= 65535) {
  116. return 'BLOB';
  117. } elseif ($length <= 16777215) {
  118. return 'MEDIUMBLOB';
  119. }
  120. }
  121. return 'LONGBLOB';
  122. case 'integer':
  123. if (!empty($field['length'])) {
  124. $length = $field['length'];
  125. if ($length <= 1) {
  126. return 'TINYINT';
  127. } elseif ($length == 2) {
  128. return 'SMALLINT';
  129. } elseif ($length == 3) {
  130. return 'MEDIUMINT';
  131. } elseif ($length == 4) {
  132. return 'INT';
  133. } elseif ($length > 4) {
  134. return 'BIGINT';
  135. }
  136. }
  137. return 'INT';
  138. case 'boolean':
  139. return 'TINYINT(1)';
  140. case 'date':
  141. return 'DATE';
  142. case 'time':
  143. return 'TIME';
  144. case 'timestamp':
  145. return 'DATETIME';
  146. case 'float':
  147. return 'DOUBLE';
  148. case 'decimal':
  149. $length = !empty($field['length']) ? $field['length'] : 18;
  150. return 'DECIMAL('.$length.','.$db->options['decimal_places'].')';
  151. }
  152. return '';
  153. }
  154. // }}}
  155. // {{{ _getIntegerDeclaration()
  156. /**
  157. * Obtain DBMS specific SQL code portion needed to declare an integer type
  158. * field to be used in statements like CREATE TABLE.
  159. *
  160. * @param string $name name the field to be declared.
  161. * @param string $field associative array with the name of the properties
  162. * of the field being declared as array indexes.
  163. * Currently, the types of supported field
  164. * properties are as follows:
  165. *
  166. * unsigned
  167. * Boolean flag that indicates whether the field
  168. * should be declared as unsigned integer if
  169. * possible.
  170. *
  171. * default
  172. * Integer value to be used as default for this
  173. * field.
  174. *
  175. * notnull
  176. * Boolean flag that indicates whether this field is
  177. * constrained to not be set to null.
  178. * @return string DBMS specific SQL code portion that should be used to
  179. * declare the specified field.
  180. * @access protected
  181. */
  182. function _getIntegerDeclaration($name, $field)
  183. {
  184. $db =& $this->getDBInstance();
  185. if (PEAR::isError($db)) {
  186. return $db;
  187. }
  188. $default = $autoinc = '';;
  189. if (!empty($field['autoincrement'])) {
  190. $autoinc = ' AUTO_INCREMENT PRIMARY KEY';
  191. } elseif (array_key_exists('default', $field)) {
  192. if ($field['default'] === '') {
  193. $field['default'] = empty($field['notnull']) ? null : 0;
  194. }
  195. $default = ' DEFAULT '.$this->quote($field['default'], 'integer');
  196. } elseif (empty($field['notnull'])) {
  197. $default = ' DEFAULT NULL';
  198. }
  199. $notnull = empty($field['notnull']) ? '' : ' NOT NULL';
  200. $unsigned = empty($field['unsigned']) ? '' : ' UNSIGNED';
  201. $name = $db->quoteIdentifier($name, true);
  202. return $name.' '.$this->getTypeDeclaration($field).$unsigned.$default.$notnull.$autoinc;
  203. }
  204. // }}}
  205. // {{{ matchPattern()
  206. /**
  207. * build a pattern matching string
  208. *
  209. * EXPERIMENTAL
  210. *
  211. * WARNING: this function is experimental and may change signature at
  212. * any time until labelled as non-experimental
  213. *
  214. * @access public
  215. *
  216. * @param array $pattern even keys are strings, odd are patterns (% and _)
  217. * @param string $operator optional pattern operator (LIKE, ILIKE and maybe others in the future)
  218. * @param string $field optional field name that is being matched against
  219. * (might be required when emulating ILIKE)
  220. *
  221. * @return string SQL pattern
  222. */
  223. function matchPattern($pattern, $operator = null, $field = null)
  224. {
  225. $db =& $this->getDBInstance();
  226. if (PEAR::isError($db)) {
  227. return $db;
  228. }
  229. $match = '';
  230. if (!is_null($operator)) {
  231. $field = is_null($field) ? '' : $field.' ';
  232. $operator = strtoupper($operator);
  233. switch ($operator) {
  234. // case insensitive
  235. case 'ILIKE':
  236. $match = $field.'LIKE ';
  237. break;
  238. // case sensitive
  239. case 'LIKE':
  240. $match = $field.'LIKE BINARY ';
  241. break;
  242. default:
  243. return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
  244. 'not a supported operator type:'. $operator, __FUNCTION__);
  245. }
  246. }
  247. $match.= "'";
  248. foreach ($pattern as $key => $value) {
  249. if ($key % 2) {
  250. $match.= $value;
  251. } else {
  252. $match.= $db->escapePattern($db->escape($value));
  253. }
  254. }
  255. $match.= "'";
  256. $match.= $this->patternEscapeString();
  257. return $match;
  258. }
  259. // }}}
  260. // {{{ mapNativeDatatype()
  261. /**
  262. * Maps a native array description of a field to a MDB2 datatype and length
  263. *
  264. * @param array $field native field description
  265. * @return array containing the various possible types, length, sign, fixed
  266. * @access public
  267. */
  268. function mapNativeDatatype($field)
  269. {
  270. $db_type = strtolower($field['type']);
  271. $db_type = strtok($db_type, '(), ');
  272. if ($db_type == 'national') {
  273. $db_type = strtok('(), ');
  274. }
  275. if (!empty($field['length'])) {
  276. $length = $field['length'];
  277. $decimal = '';
  278. } else {
  279. $length = strtok('(), ');
  280. $decimal = strtok('(), ');
  281. }
  282. $type = array();
  283. $unsigned = $fixed = null;
  284. switch ($db_type) {
  285. case 'tinyint':
  286. $type[] = 'integer';
  287. $type[] = 'boolean';
  288. if (preg_match('/^(is|has)/', $field['name'])) {
  289. $type = array_reverse($type);
  290. }
  291. $unsigned = preg_match('/ unsigned/i', $field['type']);
  292. $length = 1;
  293. break;
  294. case 'smallint':
  295. $type[] = 'integer';
  296. $unsigned = preg_match('/ unsigned/i', $field['type']);
  297. $length = 2;
  298. break;
  299. case 'mediumint':
  300. $type[] = 'integer';
  301. $unsigned = preg_match('/ unsigned/i', $field['type']);
  302. $length = 3;
  303. break;
  304. case 'int':
  305. case 'integer':
  306. $type[] = 'integer';
  307. $unsigned = preg_match('/ unsigned/i', $field['type']);
  308. $length = 4;
  309. break;
  310. case 'bigint':
  311. $type[] = 'integer';
  312. $unsigned = preg_match('/ unsigned/i', $field['type']);
  313. $length = 8;
  314. break;
  315. case 'tinytext':
  316. case 'mediumtext':
  317. case 'longtext':
  318. case 'text':
  319. case 'text':
  320. case 'varchar':
  321. $fixed = false;
  322. case 'string':
  323. case 'char':
  324. $type[] = 'text';
  325. if ($length == '1') {
  326. $type[] = 'boolean';
  327. if (preg_match('/^(is|has)/', $field['name'])) {
  328. $type = array_reverse($type);
  329. }
  330. } elseif (strstr($db_type, 'text')) {
  331. $type[] = 'clob';
  332. if ($decimal == 'binary') {
  333. $type[] = 'blob';
  334. }
  335. }
  336. if ($fixed !== false) {
  337. $fixed = true;
  338. }
  339. break;
  340. case 'enum':
  341. $type[] = 'text';
  342. preg_match_all('/\'.+\'/U', $field['type'], $matches);
  343. $length = 0;
  344. $fixed = false;
  345. if (is_array($matches)) {
  346. foreach ($matches[0] as $value) {
  347. $length = max($length, strlen($value)-2);
  348. }
  349. if ($length == '1' && count($matches[0]) == 2) {
  350. $type[] = 'boolean';
  351. if (preg_match('/^(is|has)/', $field['name'])) {
  352. $type = array_reverse($type);
  353. }
  354. }
  355. }
  356. $type[] = 'integer';
  357. case 'set':
  358. $fixed = false;
  359. $type[] = 'text';
  360. $type[] = 'integer';
  361. break;
  362. case 'date':
  363. $type[] = 'date';
  364. $length = null;
  365. break;
  366. case 'datetime':
  367. case 'timestamp':
  368. $type[] = 'timestamp';
  369. $length = null;
  370. break;
  371. case 'time':
  372. $type[] = 'time';
  373. $length = null;
  374. break;
  375. case 'float':
  376. case 'double':
  377. case 'real':
  378. $type[] = 'float';
  379. $unsigned = preg_match('/ unsigned/i', $field['type']);
  380. break;
  381. case 'unknown':
  382. case 'decimal':
  383. case 'numeric':
  384. $type[] = 'decimal';
  385. $unsigned = preg_match('/ unsigned/i', $field['type']);
  386. break;
  387. case 'tinyblob':
  388. case 'mediumblob':
  389. case 'longblob':
  390. case 'blob':
  391. $type[] = 'blob';
  392. $length = null;
  393. break;
  394. case 'year':
  395. $type[] = 'integer';
  396. $type[] = 'date';
  397. $length = null;
  398. break;
  399. default:
  400. $db =& $this->getDBInstance();
  401. if (PEAR::isError($db)) {
  402. return $db;
  403. }
  404. return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
  405. 'unknown database attribute type: '.$db_type, __FUNCTION__);
  406. }
  407. return array($type, $length, $unsigned, $fixed);
  408. }
  409. }
  410. ?>