PageRenderTime 48ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/adodb/adodb-datadict.inc.php

https://bitbucket.org/yousef_fadila/vtiger
PHP | 820 lines | 800 code | 4 blank | 16 comment | 1 complexity | 9f92198e7e1f39073ca187305f19bf40 MD5 | raw file
Possible License(s): LGPL-2.1, GPL-2.0
  1. <?php
  2. /**
  3. V4.90 8 June 2006 (c) 2000-2006 John Lim (jlim#natsoft.com.my). All rights reserved.
  4. Released under both BSD license and Lesser GPL library license.
  5. Whenever there is any discrepancy between the two licenses,
  6. the BSD license will take precedence.
  7. Set tabs to 4 for best viewing.
  8. DOCUMENTATION:
  9. See adodb/tests/test-datadict.php for docs and examples.
  10. */
  11. /*
  12. Test script for parser
  13. */
  14. // security - hide paths
  15. if (!defined('ADODB_DIR')) die();
  16. function Lens_ParseTest()
  17. {
  18. $str = "`zcol ACOL` NUMBER(32,2) DEFAULT 'The \"cow\" (and Jim''s dog) jumps over the moon' PRIMARY, INTI INT AUTO DEFAULT 0, zcol2\"afs ds";
  19. print "<p>$str</p>";
  20. $a= Lens_ParseArgs($str);
  21. print "<pre>";
  22. print_r($a);
  23. print "</pre>";
  24. }
  25. if (!function_exists('ctype_alnum')) {
  26. function ctype_alnum($text) {
  27. return preg_match('/^[a-z0-9]*$/i', $text);
  28. }
  29. }
  30. //Lens_ParseTest();
  31. /**
  32. Parse arguments, treat "text" (text) and 'text' as quotation marks.
  33. To escape, use "" or '' or ))
  34. Will read in "abc def" sans quotes, as: abc def
  35. Same with 'abc def'.
  36. However if `abc def`, then will read in as `abc def`
  37. @param endstmtchar Character that indicates end of statement
  38. @param tokenchars Include the following characters in tokens apart from A-Z and 0-9
  39. @returns 2 dimensional array containing parsed tokens.
  40. */
  41. function Lens_ParseArgs($args,$endstmtchar=',',$tokenchars='_.-')
  42. {
  43. $pos = 0;
  44. $intoken = false;
  45. $stmtno = 0;
  46. $endquote = false;
  47. $tokens = array();
  48. $tokens[$stmtno] = array();
  49. $max = strlen($args);
  50. $quoted = false;
  51. $tokarr = array();
  52. while ($pos < $max) {
  53. $ch = substr($args,$pos,1);
  54. switch($ch) {
  55. case ' ':
  56. case "\t":
  57. case "\n":
  58. case "\r":
  59. if (!$quoted) {
  60. if ($intoken) {
  61. $intoken = false;
  62. $tokens[$stmtno][] = implode('',$tokarr);
  63. }
  64. break;
  65. }
  66. $tokarr[] = $ch;
  67. break;
  68. case '`':
  69. if ($intoken) $tokarr[] = $ch;
  70. case '(':
  71. case ')':
  72. case '"':
  73. case "'":
  74. if ($intoken) {
  75. if (empty($endquote)) {
  76. $tokens[$stmtno][] = implode('',$tokarr);
  77. if ($ch == '(') $endquote = ')';
  78. else $endquote = $ch;
  79. $quoted = true;
  80. $intoken = true;
  81. $tokarr = array();
  82. } else if ($endquote == $ch) {
  83. $ch2 = substr($args,$pos+1,1);
  84. if ($ch2 == $endquote) {
  85. $pos += 1;
  86. $tokarr[] = $ch2;
  87. } else {
  88. $quoted = false;
  89. $intoken = false;
  90. $tokens[$stmtno][] = implode('',$tokarr);
  91. $endquote = '';
  92. }
  93. } else
  94. $tokarr[] = $ch;
  95. }else {
  96. if ($ch == '(') $endquote = ')';
  97. else $endquote = $ch;
  98. $quoted = true;
  99. $intoken = true;
  100. $tokarr = array();
  101. if ($ch == '`') $tokarr[] = '`';
  102. }
  103. break;
  104. default:
  105. if (!$intoken) {
  106. if ($ch == $endstmtchar) {
  107. $stmtno += 1;
  108. $tokens[$stmtno] = array();
  109. break;
  110. }
  111. $intoken = true;
  112. $quoted = false;
  113. $endquote = false;
  114. $tokarr = array();
  115. }
  116. if ($quoted) $tokarr[] = $ch;
  117. else if (ctype_alnum($ch) || strpos($tokenchars,$ch) !== false) $tokarr[] = $ch;
  118. else {
  119. if ($ch == $endstmtchar) {
  120. $tokens[$stmtno][] = implode('',$tokarr);
  121. $stmtno += 1;
  122. $tokens[$stmtno] = array();
  123. $intoken = false;
  124. $tokarr = array();
  125. break;
  126. }
  127. $tokens[$stmtno][] = implode('',$tokarr);
  128. $tokens[$stmtno][] = $ch;
  129. $intoken = false;
  130. }
  131. }
  132. $pos += 1;
  133. }
  134. if ($intoken) $tokens[$stmtno][] = implode('',$tokarr);
  135. return $tokens;
  136. }
  137. class ADODB_DataDict {
  138. var $connection;
  139. var $debug = false;
  140. var $dropTable = 'DROP TABLE %s';
  141. var $renameTable = 'RENAME TABLE %s TO %s';
  142. var $dropIndex = 'DROP INDEX %s';
  143. var $addCol = ' ADD';
  144. var $alterCol = ' ALTER COLUMN';
  145. var $dropCol = ' DROP COLUMN';
  146. var $renameColumn = 'ALTER TABLE %s RENAME COLUMN %s TO %s'; // table, old-column, new-column, column-definitions (not used by default)
  147. var $nameRegex = '\w';
  148. var $nameRegexBrackets = 'a-zA-Z0-9_\(\)';
  149. var $schema = false;
  150. var $serverInfo = array();
  151. var $autoIncrement = false;
  152. var $dataProvider;
  153. var $invalidResizeTypes4 = array('CLOB','BLOB','TEXT','DATE','TIME'); // for changetablesql
  154. var $blobSize = 100; /// any varchar/char field this size or greater is treated as a blob
  155. /// in other words, we use a text area for editting.
  156. function GetCommentSQL($table,$col)
  157. {
  158. return false;
  159. }
  160. function SetCommentSQL($table,$col,$cmt)
  161. {
  162. return false;
  163. }
  164. function MetaTables()
  165. {
  166. if (!$this->connection->IsConnected()) return array();
  167. return $this->connection->MetaTables();
  168. }
  169. function MetaColumns($tab, $upper=true, $schema=false)
  170. {
  171. if (!$this->connection->IsConnected()) return array();
  172. return $this->connection->MetaColumns($this->TableName($tab), $upper, $schema);
  173. }
  174. function MetaPrimaryKeys($tab,$owner=false,$intkey=false)
  175. {
  176. if (!$this->connection->IsConnected()) return array();
  177. return $this->connection->MetaPrimaryKeys($this->TableName($tab), $owner, $intkey);
  178. }
  179. function MetaIndexes($table, $primary = false, $owner = false)
  180. {
  181. if (!$this->connection->IsConnected()) return array();
  182. return $this->connection->MetaIndexes($this->TableName($table), $primary, $owner);
  183. }
  184. function MetaType($t,$len=-1,$fieldobj=false)
  185. {
  186. return ADORecordSet::MetaType($t,$len,$fieldobj);
  187. }
  188. function NameQuote($name = NULL,$allowBrackets=false)
  189. {
  190. if (!is_string($name)) {
  191. return FALSE;
  192. }
  193. $name = trim($name);
  194. if ( !is_object($this->connection) ) {
  195. return $name;
  196. }
  197. $quote = $this->connection->nameQuote;
  198. // if name is of the form `name`, quote it
  199. if ( preg_match('/^`(.+)`$/', $name, $matches) ) {
  200. return $quote . $matches[1] . $quote;
  201. }
  202. // if name contains special characters, quote it
  203. $regex = ($allowBrackets) ? $this->nameRegexBrackets : $this->nameRegex;
  204. if ( !preg_match('/^[' . $regex . ']+$/', $name) ) {
  205. return $quote . $name . $quote;
  206. }
  207. return $name;
  208. }
  209. function TableName($name)
  210. {
  211. if ( $this->schema ) {
  212. return $this->NameQuote($this->schema) .'.'. $this->NameQuote($name);
  213. }
  214. return $this->NameQuote($name);
  215. }
  216. // Executes the sql array returned by GetTableSQL and GetIndexSQL
  217. function ExecuteSQLArray($sql, $continueOnError = true)
  218. {
  219. global $log;
  220. $rez = 2;
  221. $conn = &$this->connection;
  222. $saved = $conn->debug;
  223. foreach($sql as $line) {
  224. if ($this->debug) $conn->debug = true;
  225. $log->debug($line);
  226. $ok = $conn->Execute($line);
  227. $conn->debug = $saved;
  228. if (!$ok) {
  229. $log->fatal("Table Creation Error: Query Failed");
  230. $log->fatal(" ");
  231. if ($this->debug)
  232. {
  233. $log->fatal("InstallError: ".$conn->ErrorMsg());
  234. ADOConnection::outp($conn->ErrorMsg());
  235. }
  236. if (!$continueOnError) return 0;
  237. $rez = 1;
  238. }
  239. }
  240. return $rez;
  241. }
  242. /*
  243. Returns the actual type given a character code.
  244. C: varchar
  245. X: CLOB (character large object) or largest varchar size if CLOB is not supported
  246. C2: Multibyte varchar
  247. X2: Multibyte CLOB
  248. B: BLOB (binary large object)
  249. D: Date
  250. T: Date-time
  251. L: Integer field suitable for storing booleans (0 or 1)
  252. I: Integer
  253. F: Floating point number
  254. N: Numeric or decimal number
  255. */
  256. function ActualType($meta)
  257. {
  258. return $meta;
  259. }
  260. function CreateDatabase($dbname,$options=false)
  261. {
  262. $options = $this->_Options($options);
  263. $sql = array();
  264. $s = 'CREATE DATABASE ' . $this->NameQuote($dbname);
  265. if (isset($options[$this->upperName]))
  266. $s .= ' '.$options[$this->upperName];
  267. $sql[] = $s;
  268. return $sql;
  269. }
  270. /*
  271. Generates the SQL to create index. Returns an array of sql strings.
  272. */
  273. function CreateIndexSQL($idxname, $tabname, $flds, $idxoptions = false)
  274. {
  275. if (!is_array($flds)) {
  276. $flds = explode(',',$flds);
  277. }
  278. foreach($flds as $key => $fld) {
  279. # some indexes can use partial fields, eg. index first 32 chars of "name" with NAME(32)
  280. $flds[$key] = $this->NameQuote($fld,$allowBrackets=true);
  281. }
  282. return $this->_IndexSQL($this->NameQuote($idxname), $this->TableName($tabname), $flds, $this->_Options($idxoptions));
  283. }
  284. function DropIndexSQL ($idxname, $tabname = NULL)
  285. {
  286. return array(sprintf($this->dropIndex, $this->NameQuote($idxname), $this->TableName($tabname)));
  287. }
  288. function SetSchema($schema)
  289. {
  290. $this->schema = $schema;
  291. }
  292. function AddColumnSQL($tabname, $flds)
  293. {
  294. $tabname = $this->TableName ($tabname);
  295. $sql = array();
  296. list($lines,$pkey) = $this->_GenFields($flds);
  297. $alter = 'ALTER TABLE ' . $tabname . $this->addCol . ' ';
  298. foreach($lines as $v) {
  299. $sql[] = $alter . $v;
  300. }
  301. return $sql;
  302. }
  303. /**
  304. * Change the definition of one column
  305. *
  306. * As some DBM's can't do that on there own, you need to supply the complete defintion of the new table,
  307. * to allow, recreating the table and copying the content over to the new table
  308. * @param string $tabname table-name
  309. * @param string $flds column-name and type for the changed column
  310. * @param string $tableflds='' complete defintion of the new table, eg. for postgres, default ''
  311. * @param array/string $tableoptions='' options for the new table see CreateTableSQL, default ''
  312. * @return array with SQL strings
  313. */
  314. function AlterColumnSQL($tabname, $flds, $tableflds='',$tableoptions='')
  315. {
  316. $tabname = $this->TableName ($tabname);
  317. $sql = array();
  318. list($lines,$pkey) = $this->_GenFields($flds);
  319. $alter = 'ALTER TABLE ' . $tabname . $this->alterCol . ' ';
  320. foreach($lines as $v) {
  321. $sql[] = $alter . $v;
  322. }
  323. return $sql;
  324. }
  325. /**
  326. * Rename one column
  327. *
  328. * Some DBM's can only do this together with changeing the type of the column (even if that stays the same, eg. mysql)
  329. * @param string $tabname table-name
  330. * @param string $oldcolumn column-name to be renamed
  331. * @param string $newcolumn new column-name
  332. * @param string $flds='' complete column-defintion-string like for AddColumnSQL, only used by mysql atm., default=''
  333. * @return array with SQL strings
  334. */
  335. function RenameColumnSQL($tabname,$oldcolumn,$newcolumn,$flds='')
  336. {
  337. $tabname = $this->TableName ($tabname);
  338. if ($flds) {
  339. list($lines,$pkey) = $this->_GenFields($flds);
  340. list(,$first) = each($lines);
  341. list(,$column_def) = split("[\t ]+",$first,2);
  342. }
  343. return array(sprintf($this->renameColumn,$tabname,$this->NameQuote($oldcolumn),$this->NameQuote($newcolumn),$column_def));
  344. }
  345. /**
  346. * Drop one column
  347. *
  348. * Some DBM's can't do that on there own, you need to supply the complete defintion of the new table,
  349. * to allow, recreating the table and copying the content over to the new table
  350. * @param string $tabname table-name
  351. * @param string $flds column-name and type for the changed column
  352. * @param string $tableflds='' complete defintion of the new table, eg. for postgres, default ''
  353. * @param array/string $tableoptions='' options for the new table see CreateTableSQL, default ''
  354. * @return array with SQL strings
  355. */
  356. function DropColumnSQL($tabname, $flds, $tableflds='',$tableoptions='')
  357. {
  358. $tabname = $this->TableName ($tabname);
  359. if (!is_array($flds)) $flds = explode(',',$flds);
  360. $sql = array();
  361. $alter = 'ALTER TABLE ' . $tabname . $this->dropCol . ' ';
  362. foreach($flds as $v) {
  363. $sql[] = $alter . $this->NameQuote($v);
  364. }
  365. return $sql;
  366. }
  367. function DropTableSQL($tabname)
  368. {
  369. return array (sprintf($this->dropTable, $this->TableName($tabname)));
  370. }
  371. function RenameTableSQL($tabname,$newname)
  372. {
  373. return array (sprintf($this->renameTable, $this->TableName($tabname),$this->TableName($newname)));
  374. }
  375. /*
  376. Generate the SQL to create table. Returns an array of sql strings.
  377. */
  378. function CreateTableSQL($tabname, $flds, $tableoptions=false)
  379. {
  380. if (!$tableoptions) $tableoptions = array();
  381. list($lines,$pkey) = $this->_GenFields($flds, true);
  382. $taboptions = $this->_Options($tableoptions);
  383. $tabname = $this->TableName ($tabname);
  384. $sql = $this->_TableSQL($tabname,$lines,$pkey,$taboptions);
  385. $tsql = $this->_Triggers($tabname,$taboptions);
  386. foreach($tsql as $s) $sql[] = $s;
  387. return $sql;
  388. }
  389. function _GenFields($flds,$widespacing=false)
  390. {
  391. if (is_string($flds)) {
  392. $padding = ' ';
  393. $txt = $flds.$padding;
  394. $flds = array();
  395. $flds0 = Lens_ParseArgs($txt,',');
  396. $hasparam = false;
  397. foreach($flds0 as $f0) {
  398. $f1 = array();
  399. foreach($f0 as $token) {
  400. switch (strtoupper($token)) {
  401. case 'CONSTRAINT':
  402. case 'DEFAULT':
  403. $hasparam = $token;
  404. break;
  405. default:
  406. if ($hasparam) $f1[$hasparam] = $token;
  407. else $f1[] = $token;
  408. $hasparam = false;
  409. break;
  410. }
  411. }
  412. $flds[] = $f1;
  413. }
  414. }
  415. $this->autoIncrement = false;
  416. $lines = array();
  417. $pkey = array();
  418. foreach($flds as $fld) {
  419. $fld = _array_change_key_case($fld);
  420. $fname = false;
  421. $fdefault = false;
  422. $fautoinc = false;
  423. $ftype = false;
  424. $fsize = false;
  425. $fprec = false;
  426. $fprimary = false;
  427. $fnoquote = false;
  428. $fdefts = false;
  429. $fdefdate = false;
  430. $fconstraint = false;
  431. $fnotnull = false;
  432. $funsigned = false;
  433. //-----------------
  434. // Parse attributes
  435. foreach($fld as $attr => $v) {
  436. if ($attr == 2 && is_numeric($v)) $attr = 'SIZE';
  437. else if (is_numeric($attr) && $attr > 1 && !is_numeric($v)) $attr = strtoupper($v);
  438. switch($attr) {
  439. case '0':
  440. case 'NAME': $fname = $v; break;
  441. case '1':
  442. case 'TYPE': $ty = $v; $ftype = $this->ActualType(strtoupper($v)); break;
  443. case 'SIZE':
  444. $dotat = strpos($v,'.'); if ($dotat === false) $dotat = strpos($v,',');
  445. if ($dotat === false) $fsize = $v;
  446. else {
  447. $fsize = substr($v,0,$dotat);
  448. $fprec = substr($v,$dotat+1);
  449. }
  450. break;
  451. case 'UNSIGNED': $funsigned = true; break;
  452. case 'AUTOINCREMENT':
  453. case 'AUTO': $fautoinc = true; $fnotnull = true; break;
  454. case 'KEY':
  455. case 'PRIMARY': $fprimary = $v; $fnotnull = true; break;
  456. case 'DEF':
  457. case 'DEFAULT': $fdefault = $v; break;
  458. case 'NOTNULL': $fnotnull = $v; break;
  459. case 'NOQUOTE': $fnoquote = $v; break;
  460. case 'DEFDATE': $fdefdate = $v; break;
  461. case 'DEFTIMESTAMP': $fdefts = $v; break;
  462. case 'CONSTRAINT': $fconstraint = $v; break;
  463. } //switch
  464. } // foreach $fld
  465. //--------------------
  466. // VALIDATE FIELD INFO
  467. if (!strlen($fname)) {
  468. if ($this->debug) ADOConnection::outp("Undefined NAME");
  469. return false;
  470. }
  471. $fid = strtoupper(preg_replace('/^`(.+)`$/', '$1', $fname));
  472. $fname = $this->NameQuote($fname);
  473. if (!strlen($ftype)) {
  474. if ($this->debug) ADOConnection::outp("Undefined TYPE for field '$fname'");
  475. return false;
  476. } else {
  477. $ftype = strtoupper($ftype);
  478. }
  479. $ftype = $this->_GetSize($ftype, $ty, $fsize, $fprec);
  480. if ($ty == 'X' || $ty == 'X2' || $ty == 'B') $fnotnull = false; // some blob types do not accept nulls
  481. if ($fprimary) $pkey[] = $fname;
  482. // some databases do not allow blobs to have defaults
  483. if ($ty == 'X') $fdefault = false;
  484. //--------------------
  485. // CONSTRUCT FIELD SQL
  486. if ($fdefts) {
  487. if (substr($this->connection->databaseType,0,5) == 'mysql') {
  488. $ftype = 'TIMESTAMP';
  489. } else {
  490. $fdefault = $this->connection->sysTimeStamp;
  491. }
  492. } else if ($fdefdate) {
  493. if (substr($this->connection->databaseType,0,5) == 'mysql') {
  494. $ftype = 'TIMESTAMP';
  495. } else {
  496. $fdefault = $this->connection->sysDate;
  497. }
  498. } else if ($fdefault !== false && !$fnoquote)
  499. if ($ty == 'C' or $ty == 'X' or
  500. ( substr($fdefault,0,1) != "'" && !is_numeric($fdefault)))
  501. if (strlen($fdefault) != 1 && substr($fdefault,0,1) == ' ' && substr($fdefault,strlen($fdefault)-1) == ' ')
  502. $fdefault = trim($fdefault);
  503. else if (strtolower($fdefault) != 'null')
  504. $fdefault = $this->connection->qstr($fdefault);
  505. $suffix = $this->_CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint,$funsigned);
  506. if ($widespacing) $fname = str_pad($fname,24);
  507. $lines[$fid] = $fname.' '.$ftype.$suffix;
  508. if ($fautoinc) $this->autoIncrement = true;
  509. } // foreach $flds
  510. return array($lines,$pkey);
  511. }
  512. /*
  513. GENERATE THE SIZE PART OF THE DATATYPE
  514. $ftype is the actual type
  515. $ty is the type defined originally in the DDL
  516. */
  517. function _GetSize($ftype, $ty, $fsize, $fprec)
  518. {
  519. if (strlen($fsize) && $ty != 'X' && $ty != 'B' && strpos($ftype,'(') === false) {
  520. $ftype .= "(".$fsize;
  521. if (strlen($fprec)) $ftype .= ",".$fprec;
  522. $ftype .= ')';
  523. }
  524. return $ftype;
  525. }
  526. // return string must begin with space
  527. function _CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint)
  528. {
  529. $suffix = '';
  530. if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault";
  531. if ($fnotnull) $suffix .= ' NOT NULL';
  532. if ($fconstraint) $suffix .= ' '.$fconstraint;
  533. return $suffix;
  534. }
  535. function _IndexSQL($idxname, $tabname, $flds, $idxoptions)
  536. {
  537. $sql = array();
  538. if ( isset($idxoptions['REPLACE']) || isset($idxoptions['DROP']) ) {
  539. $sql[] = sprintf ($this->dropIndex, $idxname);
  540. if ( isset($idxoptions['DROP']) )
  541. return $sql;
  542. }
  543. if ( empty ($flds) ) {
  544. return $sql;
  545. }
  546. $unique = isset($idxoptions['UNIQUE']) ? ' UNIQUE' : '';
  547. $s = 'CREATE' . $unique . ' INDEX ' . $idxname . ' ON ' . $tabname . ' ';
  548. if ( isset($idxoptions[$this->upperName]) )
  549. $s .= $idxoptions[$this->upperName];
  550. if ( is_array($flds) )
  551. $flds = implode(', ',$flds);
  552. $s .= '(' . $flds . ')';
  553. $sql[] = $s;
  554. return $sql;
  555. }
  556. function _DropAutoIncrement($tabname)
  557. {
  558. return false;
  559. }
  560. function _TableSQL($tabname,$lines,$pkey,$tableoptions)
  561. {
  562. $sql = array();
  563. if (isset($tableoptions['REPLACE']) || isset ($tableoptions['DROP'])) {
  564. $sql[] = sprintf($this->dropTable,$tabname);
  565. if ($this->autoIncrement) {
  566. $sInc = $this->_DropAutoIncrement($tabname);
  567. if ($sInc) $sql[] = $sInc;
  568. }
  569. if ( isset ($tableoptions['DROP']) ) {
  570. return $sql;
  571. }
  572. }
  573. $s = "CREATE TABLE $tabname (\n";
  574. $s .= implode(",\n", $lines);
  575. if (sizeof($pkey)>0) {
  576. $s .= ",\n PRIMARY KEY (";
  577. $s .= implode(", ",$pkey).")";
  578. }
  579. if (isset($tableoptions['CONSTRAINTS']))
  580. $s .= "\n".$tableoptions['CONSTRAINTS'];
  581. if (isset($tableoptions[$this->upperName.'_CONSTRAINTS']))
  582. $s .= "\n".$tableoptions[$this->upperName.'_CONSTRAINTS'];
  583. $s .= "\n)";
  584. if (isset($tableoptions[$this->upperName])) $s .= $tableoptions[$this->upperName];
  585. $sql[] = $s;
  586. return $sql;
  587. }
  588. /*
  589. GENERATE TRIGGERS IF NEEDED
  590. used when table has auto-incrementing field that is emulated using triggers
  591. */
  592. function _Triggers($tabname,$taboptions)
  593. {
  594. return array();
  595. }
  596. /*
  597. Sanitize options, so that array elements with no keys are promoted to keys
  598. */
  599. function _Options($opts)
  600. {
  601. if (!is_array($opts)) return array();
  602. $newopts = array();
  603. foreach($opts as $k => $v) {
  604. if (is_numeric($k)) $newopts[strtoupper($v)] = $v;
  605. else $newopts[strtoupper($k)] = $v;
  606. }
  607. return $newopts;
  608. }
  609. /*
  610. "Florian Buzin [ easywe ]" <florian.buzin#easywe.de>
  611. This function changes/adds new fields to your table. You don't
  612. have to know if the col is new or not. It will check on its own.
  613. */
  614. function ChangeTableSQL($tablename, $flds, $tableoptions = false, $forceAlter = false) // GS Fix for constraint impl - forceAlter
  615. {
  616. global $ADODB_FETCH_MODE;
  617. $save = $ADODB_FETCH_MODE;
  618. $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
  619. if ($this->connection->fetchMode !== false) $savem = $this->connection->SetFetchMode(false);
  620. // check table exists
  621. $save_handler = $this->connection->raiseErrorFn;
  622. $this->connection->raiseErrorFn = '';
  623. $cols = $this->MetaColumns($tablename);
  624. $this->connection->raiseErrorFn = $save_handler;
  625. if (isset($savem)) $this->connection->SetFetchMode($savem);
  626. $ADODB_FETCH_MODE = $save;
  627. if ( $forceAlter == false && empty($cols)) { // GS Fix for constraint impl
  628. return $this->CreateTableSQL($tablename, $flds, $tableoptions);
  629. }
  630. if (is_array($flds)) {
  631. // Cycle through the update fields, comparing
  632. // existing fields to fields to update.
  633. // if the Metatype and size is exactly the
  634. // same, ignore - by Mark Newham
  635. $holdflds = array();
  636. foreach($flds as $k=>$v) {
  637. if ( isset($cols[$k]) && is_object($cols[$k]) ) {
  638. // If already not allowing nulls, then don't change
  639. $obj = $cols[$k];
  640. if (isset($obj->not_null) && $obj->not_null)
  641. $v = str_replace('NOT NULL','',$v);
  642. $c = $cols[$k];
  643. $ml = $c->max_length;
  644. $mt = $this->MetaType($c->type,$ml);
  645. if ($ml == -1) $ml = '';
  646. if ($mt == 'X') $ml = $v['SIZE'];
  647. if (($mt != $v['TYPE']) || $ml != $v['SIZE']) {
  648. $holdflds[$k] = $v;
  649. }
  650. } else {
  651. $holdflds[$k] = $v;
  652. }
  653. }
  654. $flds = $holdflds;
  655. }
  656. // already exists, alter table instead
  657. list($lines,$pkey) = $this->_GenFields($flds);
  658. $alter = 'ALTER TABLE ' . $this->TableName($tablename);
  659. $sql = array();
  660. foreach ( $lines as $id => $v ) {
  661. if ( isset($cols[$id]) && is_object($cols[$id]) ) {
  662. $flds = Lens_ParseArgs($v,',');
  663. // We are trying to change the size of the field, if not allowed, simply ignore the request.
  664. if ($flds && in_array(strtoupper(substr($flds[0][1],0,4)),$this->invalidResizeTypes4)) continue;
  665. $sql[] = $alter . $this->alterCol . ' ' . $v;
  666. } else {
  667. $sql[] = $alter . $this->addCol . ' ' . $v;
  668. }
  669. }
  670. // GS Fix for constraint impl -- start
  671. if($forceAlter == false) return $sql;
  672. $sqlarray = array();
  673. $alter .= implode(",\n", $sql);
  674. if (sizeof($pkey)>0) {
  675. $alter .= ",\n PRIMARY KEY (";
  676. $alter .= implode(", ",$pkey).")";
  677. }
  678. if (isset($tableoptions['CONSTRAINTS']))
  679. $alter .= "\n".$tableoptions['CONSTRAINTS'];
  680. if (isset($tableoptions[$this->upperName.'_CONSTRAINTS']))
  681. $alter .= "\n".$tableoptions[$this->upperName.'_CONSTRAINTS'];
  682. if (isset($tableoptions[$this->upperName])) $alter .= $tableoptions[$this->upperName];
  683. $sqlarray[] = $alter;
  684. $taboptions = $this->_Options($tableoptions);
  685. $tsql = $this->_Triggers($this->TableName($tablename),$taboptions);
  686. foreach($tsql as $s) $sqlarray[] = $s;
  687. // GS Fix for constraint impl -- end
  688. return $sqlarray;
  689. }
  690. } // class
  691. ?>