Differences Between: [Versions 310 and 311] [Versions 311 and 400] [Versions 311 and 401] [Versions 311 and 402] [Versions 311 and 403] [Versions 39 and 311]
1 <?php 2 3 /** 4 @version v5.21.0 2021-02-27 5 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved. 6 @copyright (c) 2014 Damien Regad, Mark Newnham and the ADOdb community 7 Released under both BSD license and Lesser GPL library license. 8 Whenever there is any discrepancy between the two licenses, 9 the BSD license will take precedence. 10 11 Set tabs to 4 for best viewing. 12 13 DOCUMENTATION: 14 15 See adodb/tests/test-datadict.php for docs and examples. 16 */ 17 18 /* 19 Test script for parser 20 */ 21 22 // security - hide paths 23 if (!defined('ADODB_DIR')) die(); 24 25 function lens_ParseTest() 26 { 27 $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"; 28 print "<p>$str</p>"; 29 $a= lens_ParseArgs($str); 30 print "<pre>"; 31 print_r($a); 32 print "</pre>"; 33 } 34 35 36 if (!function_exists('ctype_alnum')) { 37 function ctype_alnum($text) { 38 return preg_match('/^[a-z0-9]*$/i', $text); 39 } 40 } 41 42 //Lens_ParseTest(); 43 44 /** 45 Parse arguments, treat "text" (text) and 'text' as quotation marks. 46 To escape, use "" or '' or )) 47 48 Will read in "abc def" sans quotes, as: abc def 49 Same with 'abc def'. 50 However if `abc def`, then will read in as `abc def` 51 52 @param endstmtchar Character that indicates end of statement 53 @param tokenchars Include the following characters in tokens apart from A-Z and 0-9 54 @returns 2 dimensional array containing parsed tokens. 55 */ 56 function lens_ParseArgs($args,$endstmtchar=',',$tokenchars='_.-') 57 { 58 $pos = 0; 59 $intoken = false; 60 $stmtno = 0; 61 $endquote = false; 62 $tokens = array(); 63 $tokens[$stmtno] = array(); 64 $max = strlen($args); 65 $quoted = false; 66 $tokarr = array(); 67 68 while ($pos < $max) { 69 $ch = substr($args,$pos,1); 70 switch($ch) { 71 case ' ': 72 case "\t": 73 case "\n": 74 case "\r": 75 if (!$quoted) { 76 if ($intoken) { 77 $intoken = false; 78 $tokens[$stmtno][] = implode('',$tokarr); 79 } 80 break; 81 } 82 83 $tokarr[] = $ch; 84 break; 85 86 case '`': 87 if ($intoken) $tokarr[] = $ch; 88 case '(': 89 case ')': 90 case '"': 91 case "'": 92 93 if ($intoken) { 94 if (empty($endquote)) { 95 $tokens[$stmtno][] = implode('',$tokarr); 96 if ($ch == '(') $endquote = ')'; 97 else $endquote = $ch; 98 $quoted = true; 99 $intoken = true; 100 $tokarr = array(); 101 } else if ($endquote == $ch) { 102 $ch2 = substr($args,$pos+1,1); 103 if ($ch2 == $endquote) { 104 $pos += 1; 105 $tokarr[] = $ch2; 106 } else { 107 $quoted = false; 108 $intoken = false; 109 $tokens[$stmtno][] = implode('',$tokarr); 110 $endquote = ''; 111 } 112 } else 113 $tokarr[] = $ch; 114 115 }else { 116 117 if ($ch == '(') $endquote = ')'; 118 else $endquote = $ch; 119 $quoted = true; 120 $intoken = true; 121 $tokarr = array(); 122 if ($ch == '`') $tokarr[] = '`'; 123 } 124 break; 125 126 default: 127 128 if (!$intoken) { 129 if ($ch == $endstmtchar) { 130 $stmtno += 1; 131 $tokens[$stmtno] = array(); 132 break; 133 } 134 135 $intoken = true; 136 $quoted = false; 137 $endquote = false; 138 $tokarr = array(); 139 140 } 141 142 if ($quoted) $tokarr[] = $ch; 143 else if (ctype_alnum($ch) || strpos($tokenchars,$ch) !== false) $tokarr[] = $ch; 144 else { 145 if ($ch == $endstmtchar) { 146 $tokens[$stmtno][] = implode('',$tokarr); 147 $stmtno += 1; 148 $tokens[$stmtno] = array(); 149 $intoken = false; 150 $tokarr = array(); 151 break; 152 } 153 $tokens[$stmtno][] = implode('',$tokarr); 154 $tokens[$stmtno][] = $ch; 155 $intoken = false; 156 } 157 } 158 $pos += 1; 159 } 160 if ($intoken) $tokens[$stmtno][] = implode('',$tokarr); 161 162 return $tokens; 163 } 164 165 166 class ADODB_DataDict { 167 var $connection; 168 var $debug = false; 169 var $dropTable = 'DROP TABLE %s'; 170 var $renameTable = 'RENAME TABLE %s TO %s'; 171 var $dropIndex = 'DROP INDEX %s'; 172 var $addCol = ' ADD'; 173 var $alterCol = ' ALTER COLUMN'; 174 var $dropCol = ' DROP COLUMN'; 175 var $renameColumn = 'ALTER TABLE %s RENAME COLUMN %s TO %s'; // table, old-column, new-column, column-definitions (not used by default) 176 var $nameRegex = '\w'; 177 var $nameRegexBrackets = 'a-zA-Z0-9_\(\)'; 178 var $schema = false; 179 var $serverInfo = array(); 180 var $autoIncrement = false; 181 var $dataProvider; 182 var $invalidResizeTypes4 = array('CLOB','BLOB','TEXT','DATE','TIME'); // for changeTableSQL 183 var $blobSize = 100; /// any varchar/char field this size or greater is treated as a blob 184 /// in other words, we use a text area for editing. 185 186 /* 187 * Indicates whether a BLOB/CLOB field will allow a NOT NULL setting 188 * The type is whatever is matched to an X or X2 or B type. We must 189 * explicitly set the value in the driver to switch the behaviour on 190 */ 191 public $blobAllowsNotNull; 192 /* 193 * Indicates whether a BLOB/CLOB field will allow a DEFAULT set 194 * The type is whatever is matched to an X or X2 or B type. We must 195 * explicitly set the value in the driver to switch the behaviour on 196 */ 197 public $blobAllowsDefaultValue; 198 199 function getCommentSQL($table,$col) 200 { 201 return false; 202 } 203 204 function setCommentSQL($table,$col,$cmt) 205 { 206 return false; 207 } 208 209 function metaTables() 210 { 211 if (!$this->connection->isConnected()) return array(); 212 return $this->connection->metaTables(); 213 } 214 215 function metaColumns($tab, $upper=true, $schema=false) 216 { 217 if (!$this->connection->isConnected()) return array(); 218 return $this->connection->metaColumns($this->tableName($tab), $upper, $schema); 219 } 220 221 function metaPrimaryKeys($tab,$owner=false,$intkey=false) 222 { 223 if (!$this->connection->isConnected()) return array(); 224 return $this->connection->metaPrimaryKeys($this->tableName($tab), $owner, $intkey); 225 } 226 227 function metaIndexes($table, $primary = false, $owner = false) 228 { 229 if (!$this->connection->isConnected()) return array(); 230 return $this->connection->metaIndexes($this->tableName($table), $primary, $owner); 231 } 232 233 function metaType($t,$len=-1,$fieldobj=false) 234 { 235 static $typeMap = array( 236 'VARCHAR' => 'C', 237 'VARCHAR2' => 'C', 238 'CHAR' => 'C', 239 'C' => 'C', 240 'STRING' => 'C', 241 'NCHAR' => 'C', 242 'NVARCHAR' => 'C', 243 'VARYING' => 'C', 244 'BPCHAR' => 'C', 245 'CHARACTER' => 'C', 246 'INTERVAL' => 'C', # Postgres 247 'MACADDR' => 'C', # postgres 248 'VAR_STRING' => 'C', # mysql 249 ## 250 'LONGCHAR' => 'X', 251 'TEXT' => 'X', 252 'NTEXT' => 'X', 253 'M' => 'X', 254 'X' => 'X', 255 'CLOB' => 'X', 256 'NCLOB' => 'X', 257 'LVARCHAR' => 'X', 258 ## 259 'BLOB' => 'B', 260 'IMAGE' => 'B', 261 'BINARY' => 'B', 262 'VARBINARY' => 'B', 263 'LONGBINARY' => 'B', 264 'B' => 'B', 265 ## 266 'YEAR' => 'D', // mysql 267 'DATE' => 'D', 268 'D' => 'D', 269 ## 270 'UNIQUEIDENTIFIER' => 'C', # MS SQL Server 271 ## 272 'TIME' => 'T', 273 'TIMESTAMP' => 'T', 274 'DATETIME' => 'T', 275 'TIMESTAMPTZ' => 'T', 276 'SMALLDATETIME' => 'T', 277 'T' => 'T', 278 'TIMESTAMP WITHOUT TIME ZONE' => 'T', // postgresql 279 ## 280 'BOOL' => 'L', 281 'BOOLEAN' => 'L', 282 'BIT' => 'L', 283 'L' => 'L', 284 ## 285 'COUNTER' => 'R', 286 'R' => 'R', 287 'SERIAL' => 'R', // ifx 288 'INT IDENTITY' => 'R', 289 ## 290 'INT' => 'I', 291 'INT2' => 'I', 292 'INT4' => 'I', 293 'INT8' => 'I', 294 'INTEGER' => 'I', 295 'INTEGER UNSIGNED' => 'I', 296 'SHORT' => 'I', 297 'TINYINT' => 'I', 298 'SMALLINT' => 'I', 299 'I' => 'I', 300 ## 301 'LONG' => 'N', // interbase is numeric, oci8 is blob 302 'BIGINT' => 'N', // this is bigger than PHP 32-bit integers 303 'DECIMAL' => 'N', 304 'DEC' => 'N', 305 'REAL' => 'N', 306 'DOUBLE' => 'N', 307 'DOUBLE PRECISION' => 'N', 308 'SMALLFLOAT' => 'N', 309 'FLOAT' => 'N', 310 'NUMBER' => 'N', 311 'NUM' => 'N', 312 'NUMERIC' => 'N', 313 'MONEY' => 'N', 314 315 ## informix 9.2 316 'SQLINT' => 'I', 317 'SQLSERIAL' => 'I', 318 'SQLSMINT' => 'I', 319 'SQLSMFLOAT' => 'N', 320 'SQLFLOAT' => 'N', 321 'SQLMONEY' => 'N', 322 'SQLDECIMAL' => 'N', 323 'SQLDATE' => 'D', 324 'SQLVCHAR' => 'C', 325 'SQLCHAR' => 'C', 326 'SQLDTIME' => 'T', 327 'SQLINTERVAL' => 'N', 328 'SQLBYTES' => 'B', 329 'SQLTEXT' => 'X', 330 ## informix 10 331 "SQLINT8" => 'I8', 332 "SQLSERIAL8" => 'I8', 333 "SQLNCHAR" => 'C', 334 "SQLNVCHAR" => 'C', 335 "SQLLVARCHAR" => 'X', 336 "SQLBOOL" => 'L' 337 ); 338 339 if (!$this->connection->isConnected()) { 340 $t = strtoupper($t); 341 if (isset($typeMap[$t])) return $typeMap[$t]; 342 return ADODB_DEFAULT_METATYPE; 343 } 344 return $this->connection->metaType($t,$len,$fieldobj); 345 } 346 347 function nameQuote($name = NULL,$allowBrackets=false) 348 { 349 if (!is_string($name)) { 350 return FALSE; 351 } 352 353 $name = trim($name); 354 355 if ( !is_object($this->connection) ) { 356 return $name; 357 } 358 359 $quote = $this->connection->nameQuote; 360 361 // if name is of the form `name`, quote it 362 if ( preg_match('/^`(.+)`$/', $name, $matches) ) { 363 return $quote . $matches[1] . $quote; 364 } 365 366 // if name contains special characters, quote it 367 $regex = ($allowBrackets) ? $this->nameRegexBrackets : $this->nameRegex; 368 369 if ( !preg_match('/^[' . $regex . ']+$/', $name) ) { 370 return $quote . $name . $quote; 371 } 372 373 return $name; 374 } 375 376 function tableName($name) 377 { 378 if ( $this->schema ) { 379 return $this->nameQuote($this->schema) .'.'. $this->nameQuote($name); 380 } 381 return $this->nameQuote($name); 382 } 383 384 // Executes the sql array returned by getTableSQL and getIndexSQL 385 function executeSQLArray($sql, $continueOnError = true) 386 { 387 $rez = 2; 388 $conn = $this->connection; 389 $saved = $conn->debug; 390 foreach($sql as $line) { 391 392 if ($this->debug) $conn->debug = true; 393 $ok = $conn->execute($line); 394 $conn->debug = $saved; 395 if (!$ok) { 396 if ($this->debug) ADOConnection::outp($conn->errorMsg()); 397 if (!$continueOnError) return 0; 398 $rez = 1; 399 } 400 } 401 return $rez; 402 } 403 404 /** 405 Returns the actual type given a character code. 406 407 C: varchar 408 X: CLOB (character large object) or largest varchar size if CLOB is not supported 409 C2: Multibyte varchar 410 X2: Multibyte CLOB 411 412 B: BLOB (binary large object) 413 414 D: Date 415 T: Date-time 416 L: Integer field suitable for storing booleans (0 or 1) 417 I: Integer 418 F: Floating point number 419 N: Numeric or decimal number 420 */ 421 422 function actualType($meta) 423 { 424 return $meta; 425 } 426 427 function createDatabase($dbname,$options=false) 428 { 429 $options = $this->_options($options); 430 $sql = array(); 431 432 $s = 'CREATE DATABASE ' . $this->nameQuote($dbname); 433 if (isset($options[$this->upperName])) 434 $s .= ' '.$options[$this->upperName]; 435 436 $sql[] = $s; 437 return $sql; 438 } 439 440 /* 441 Generates the SQL to create index. Returns an array of sql strings. 442 */ 443 function createIndexSQL($idxname, $tabname, $flds, $idxoptions = false) 444 { 445 if (!is_array($flds)) { 446 $flds = explode(',',$flds); 447 } 448 449 foreach($flds as $key => $fld) { 450 # some indexes can use partial fields, eg. index first 32 chars of "name" with NAME(32) 451 $flds[$key] = $this->nameQuote($fld,$allowBrackets=true); 452 } 453 454 return $this->_indexSQL($this->nameQuote($idxname), $this->tableName($tabname), $flds, $this->_options($idxoptions)); 455 } 456 457 function dropIndexSQL ($idxname, $tabname = NULL) 458 { 459 return array(sprintf($this->dropIndex, $this->nameQuote($idxname), $this->tableName($tabname))); 460 } 461 462 function setSchema($schema) 463 { 464 $this->schema = $schema; 465 } 466 467 function addColumnSQL($tabname, $flds) 468 { 469 $tabname = $this->tableName($tabname); 470 $sql = array(); 471 list($lines,$pkey,$idxs) = $this->_genFields($flds); 472 // genfields can return FALSE at times 473 if ($lines == null) $lines = array(); 474 $alter = 'ALTER TABLE ' . $tabname . $this->addCol . ' '; 475 foreach($lines as $v) { 476 $sql[] = $alter . $v; 477 } 478 if (is_array($idxs)) { 479 foreach($idxs as $idx => $idxdef) { 480 $sql_idxs = $this->createIndexSql($idx, $tabname, $idxdef['cols'], $idxdef['opts']); 481 $sql = array_merge($sql, $sql_idxs); 482 } 483 } 484 return $sql; 485 } 486 487 /** 488 * Change the definition of one column 489 * 490 * As some DBMs can't do that on their own, you need to supply the complete definition of the new table, 491 * to allow recreating the table and copying the content over to the new table 492 * @param string $tabname table-name 493 * @param string $flds column-name and type for the changed column 494 * @param string $tableflds='' complete definition of the new table, eg. for postgres, default '' 495 * @param array/string $tableoptions='' options for the new table see createTableSQL, default '' 496 * @return array with SQL strings 497 */ 498 function alterColumnSQL($tabname, $flds, $tableflds='',$tableoptions='') 499 { 500 $tabname = $this->tableName($tabname); 501 $sql = array(); 502 list($lines,$pkey,$idxs) = $this->_genFields($flds); 503 // genfields can return FALSE at times 504 if ($lines == null) $lines = array(); 505 $alter = 'ALTER TABLE ' . $tabname . $this->alterCol . ' '; 506 foreach($lines as $v) { 507 $sql[] = $alter . $v; 508 } 509 if (is_array($idxs)) { 510 foreach($idxs as $idx => $idxdef) { 511 $sql_idxs = $this->createIndexSql($idx, $tabname, $idxdef['cols'], $idxdef['opts']); 512 $sql = array_merge($sql, $sql_idxs); 513 } 514 515 } 516 return $sql; 517 } 518 519 /** 520 * Rename one column 521 * 522 * Some DBMs can only do this together with changeing the type of the column (even if that stays the same, eg. mysql) 523 * @param string $tabname table-name 524 * @param string $oldcolumn column-name to be renamed 525 * @param string $newcolumn new column-name 526 * @param string $flds='' complete column-definition-string like for addColumnSQL, only used by mysql atm., default='' 527 * @return array with SQL strings 528 */ 529 function renameColumnSQL($tabname,$oldcolumn,$newcolumn,$flds='') 530 { 531 $tabname = $this->tableName($tabname); 532 if ($flds) { 533 list($lines,$pkey,$idxs) = $this->_genFields($flds); 534 // genfields can return FALSE at times 535 if ($lines == null) $lines = array(); 536 $first = current($lines); 537 list(,$column_def) = preg_split("/[\t ]+/",$first,2); 538 } 539 return array(sprintf($this->renameColumn,$tabname,$this->nameQuote($oldcolumn),$this->nameQuote($newcolumn),$column_def)); 540 } 541 542 /** 543 * Drop one column 544 * 545 * Some DBM's can't do that on their own, you need to supply the complete definition of the new table, 546 * to allow, recreating the table and copying the content over to the new table 547 * @param string $tabname table-name 548 * @param string $flds column-name and type for the changed column 549 * @param string $tableflds='' complete definition of the new table, eg. for postgres, default '' 550 * @param array/string $tableoptions='' options for the new table see createTableSQL, default '' 551 * @return array with SQL strings 552 */ 553 function dropColumnSQL($tabname, $flds, $tableflds='',$tableoptions='') 554 { 555 $tabname = $this->tableName($tabname); 556 if (!is_array($flds)) $flds = explode(',',$flds); 557 $sql = array(); 558 $alter = 'ALTER TABLE ' . $tabname . $this->dropCol . ' '; 559 foreach($flds as $v) { 560 $sql[] = $alter . $this->nameQuote($v); 561 } 562 return $sql; 563 } 564 565 function dropTableSQL($tabname) 566 { 567 return array (sprintf($this->dropTable, $this->tableName($tabname))); 568 } 569 570 function renameTableSQL($tabname,$newname) 571 { 572 return array (sprintf($this->renameTable, $this->tableName($tabname),$this->tableName($newname))); 573 } 574 575 /** 576 Generate the SQL to create table. Returns an array of sql strings. 577 */ 578 function createTableSQL($tabname, $flds, $tableoptions=array()) 579 { 580 list($lines,$pkey,$idxs) = $this->_genFields($flds, true); 581 // genfields can return FALSE at times 582 if ($lines == null) $lines = array(); 583 584 $taboptions = $this->_options($tableoptions); 585 $tabname = $this->tableName($tabname); 586 $sql = $this->_tableSQL($tabname,$lines,$pkey,$taboptions); 587 588 // ggiunta - 2006/10/12 - KLUDGE: 589 // if we are on autoincrement, and table options includes REPLACE, the 590 // autoincrement sequence has already been dropped on table creation sql, so 591 // we avoid passing REPLACE to trigger creation code. This prevents 592 // creating sql that double-drops the sequence 593 if ($this->autoIncrement && isset($taboptions['REPLACE'])) 594 unset($taboptions['REPLACE']); 595 $tsql = $this->_triggers($tabname,$taboptions); 596 foreach($tsql as $s) $sql[] = $s; 597 598 if (is_array($idxs)) { 599 foreach($idxs as $idx => $idxdef) { 600 $sql_idxs = $this->createIndexSql($idx, $tabname, $idxdef['cols'], $idxdef['opts']); 601 $sql = array_merge($sql, $sql_idxs); 602 } 603 } 604 605 return $sql; 606 } 607 608 609 610 function _genFields($flds,$widespacing=false) 611 { 612 if (is_string($flds)) { 613 $padding = ' '; 614 $txt = $flds.$padding; 615 $flds = array(); 616 $flds0 = lens_ParseArgs($txt,','); 617 $hasparam = false; 618 foreach($flds0 as $f0) { 619 $f1 = array(); 620 foreach($f0 as $token) { 621 switch (strtoupper($token)) { 622 case 'INDEX': 623 $f1['INDEX'] = ''; 624 // fall through intentionally 625 case 'CONSTRAINT': 626 case 'DEFAULT': 627 $hasparam = $token; 628 break; 629 default: 630 if ($hasparam) $f1[$hasparam] = $token; 631 else $f1[] = $token; 632 $hasparam = false; 633 break; 634 } 635 } 636 // 'index' token without a name means single column index: name it after column 637 if (array_key_exists('INDEX', $f1) && $f1['INDEX'] == '') { 638 $f1['INDEX'] = isset($f0['NAME']) ? $f0['NAME'] : $f0[0]; 639 // check if column name used to create an index name was quoted 640 if (($f1['INDEX'][0] == '"' || $f1['INDEX'][0] == "'" || $f1['INDEX'][0] == "`") && 641 ($f1['INDEX'][0] == substr($f1['INDEX'], -1))) { 642 $f1['INDEX'] = $f1['INDEX'][0].'idx_'.substr($f1['INDEX'], 1, -1).$f1['INDEX'][0]; 643 } 644 else 645 $f1['INDEX'] = 'idx_'.$f1['INDEX']; 646 } 647 // reset it, so we don't get next field 1st token as INDEX... 648 $hasparam = false; 649 650 $flds[] = $f1; 651 652 } 653 } 654 $this->autoIncrement = false; 655 $lines = array(); 656 $pkey = array(); 657 $idxs = array(); 658 foreach($flds as $fld) { 659 if (is_array($fld)) 660 $fld = array_change_key_case($fld,CASE_UPPER); 661 $fname = false; 662 $fdefault = false; 663 $fautoinc = false; 664 $ftype = false; 665 $fsize = false; 666 $fprec = false; 667 $fprimary = false; 668 $fnoquote = false; 669 $fdefts = false; 670 $fdefdate = false; 671 $fconstraint = false; 672 $fnotnull = false; 673 $funsigned = false; 674 $findex = ''; 675 $funiqueindex = false; 676 $fOptions = array(); 677 678 //----------------- 679 // Parse attributes 680 foreach($fld as $attr => $v) { 681 if ($attr == 2 && is_numeric($v)) 682 $attr = 'SIZE'; 683 elseif ($attr == 2 && strtoupper($ftype) == 'ENUM') 684 $attr = 'ENUM'; 685 else if (is_numeric($attr) && $attr > 1 && !is_numeric($v)) 686 $attr = strtoupper($v); 687 688 switch($attr) { 689 case '0': 690 case 'NAME': $fname = $v; break; 691 case '1': 692 case 'TYPE': $ty = $v; $ftype = $this->actualType(strtoupper($v)); break; 693 694 case 'SIZE': 695 $dotat = strpos($v,'.'); if ($dotat === false) $dotat = strpos($v,','); 696 if ($dotat === false) $fsize = $v; 697 else { 698 $fsize = substr($v,0,$dotat); 699 $fprec = substr($v,$dotat+1); 700 } 701 break; 702 case 'UNSIGNED': $funsigned = true; break; 703 case 'AUTOINCREMENT': 704 case 'AUTO': $fautoinc = true; $fnotnull = true; break; 705 case 'KEY': 706 // a primary key col can be non unique in itself (if key spans many cols...) 707 case 'PRIMARY': $fprimary = $v; $fnotnull = true; /*$funiqueindex = true;*/ break; 708 case 'DEF': 709 case 'DEFAULT': $fdefault = $v; break; 710 case 'NOTNULL': $fnotnull = $v; break; 711 case 'NOQUOTE': $fnoquote = $v; break; 712 case 'DEFDATE': $fdefdate = $v; break; 713 case 'DEFTIMESTAMP': $fdefts = $v; break; 714 case 'CONSTRAINT': $fconstraint = $v; break; 715 // let INDEX keyword create a 'very standard' index on column 716 case 'INDEX': $findex = $v; break; 717 case 'UNIQUE': $funiqueindex = true; break; 718 case 'ENUM': 719 $fOptions['ENUM'] = $v; break; 720 } //switch 721 } // foreach $fld 722 723 //-------------------- 724 // VALIDATE FIELD INFO 725 if (!strlen($fname)) { 726 if ($this->debug) ADOConnection::outp("Undefined NAME"); 727 return false; 728 } 729 730 $fid = strtoupper(preg_replace('/^`(.+)`$/', '$1', $fname)); 731 $fname = $this->nameQuote($fname); 732 733 if (!strlen($ftype)) { 734 if ($this->debug) ADOConnection::outp("Undefined TYPE for field '$fname'"); 735 return false; 736 } else { 737 $ftype = strtoupper($ftype); 738 } 739 740 $ftype = $this->_getSize($ftype, $ty, $fsize, $fprec, $fOptions); 741 742 if (($ty == 'X' || $ty == 'X2' || $ty == 'XL' || $ty == 'B') && !$this->blobAllowsNotNull) 743 /* 744 * some blob types do not accept nulls, so we override the 745 * previously defined value 746 */ 747 $fnotnull = false; 748 749 if ($fprimary) 750 $pkey[] = $fname; 751 752 if (($ty == 'X' || $ty == 'X2' || $ty == 'XL' || $ty == 'B') && !$this->blobAllowsDefaultValue) 753 /* 754 * some databases do not allow blobs to have defaults, so we 755 * override the previously defined value 756 */ 757 $fdefault = false; 758 759 // build list of indexes 760 if ($findex != '') { 761 if (array_key_exists($findex, $idxs)) { 762 $idxs[$findex]['cols'][] = ($fname); 763 if (in_array('UNIQUE', $idxs[$findex]['opts']) != $funiqueindex) { 764 if ($this->debug) ADOConnection::outp("Index $findex defined once UNIQUE and once not"); 765 } 766 if ($funiqueindex && !in_array('UNIQUE', $idxs[$findex]['opts'])) 767 $idxs[$findex]['opts'][] = 'UNIQUE'; 768 } 769 else 770 { 771 $idxs[$findex] = array(); 772 $idxs[$findex]['cols'] = array($fname); 773 if ($funiqueindex) 774 $idxs[$findex]['opts'] = array('UNIQUE'); 775 else 776 $idxs[$findex]['opts'] = array(); 777 } 778 } 779 780 //-------------------- 781 // CONSTRUCT FIELD SQL 782 if ($fdefts) { 783 if (substr($this->connection->databaseType,0,5) == 'mysql') { 784 $ftype = 'TIMESTAMP'; 785 } else { 786 $fdefault = $this->connection->sysTimeStamp; 787 } 788 } else if ($fdefdate) { 789 if (substr($this->connection->databaseType,0,5) == 'mysql') { 790 $ftype = 'TIMESTAMP'; 791 } else { 792 $fdefault = $this->connection->sysDate; 793 } 794 } else if ($fdefault !== false && !$fnoquote) { 795 if ($ty == 'C' or $ty == 'X' or 796 ( substr($fdefault,0,1) != "'" && !is_numeric($fdefault))) { 797 798 if (($ty == 'D' || $ty == 'T') && strtolower($fdefault) != 'null') { 799 // convert default date into database-aware code 800 if ($ty == 'T') 801 { 802 $fdefault = $this->connection->dbTimeStamp($fdefault); 803 } 804 else 805 { 806 $fdefault = $this->connection->dbDate($fdefault); 807 } 808 } 809 else 810 if (strlen($fdefault) != 1 && substr($fdefault,0,1) == ' ' && substr($fdefault,strlen($fdefault)-1) == ' ') 811 $fdefault = trim($fdefault); 812 else if (strtolower($fdefault) != 'null') 813 $fdefault = $this->connection->qstr($fdefault); 814 } 815 } 816 $suffix = $this->_createSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint,$funsigned); 817 818 // add index creation 819 if ($widespacing) $fname = str_pad($fname,24); 820 821 // check for field names appearing twice 822 if (array_key_exists($fid, $lines)) { 823 ADOConnection::outp("Field '$fname' defined twice"); 824 } 825 826 $lines[$fid] = $fname.' '.$ftype.$suffix; 827 828 if ($fautoinc) $this->autoIncrement = true; 829 } // foreach $flds 830 831 return array($lines,$pkey,$idxs); 832 } 833 834 /** 835 GENERATE THE SIZE PART OF THE DATATYPE 836 $ftype is the actual type 837 $ty is the type defined originally in the DDL 838 */ 839 function _getSize($ftype, $ty, $fsize, $fprec, $options=false) 840 { 841 if (strlen($fsize) && $ty != 'X' && $ty != 'B' && strpos($ftype,'(') === false) { 842 $ftype .= "(".$fsize; 843 if (strlen($fprec)) $ftype .= ",".$fprec; 844 $ftype .= ')'; 845 } 846 847 /* 848 * Handle additional options 849 */ 850 if (is_array($options)) 851 { 852 foreach($options as $type=>$value) 853 { 854 switch ($type) 855 { 856 case 'ENUM': 857 $ftype .= '(' . $value . ')'; 858 break; 859 860 default: 861 } 862 } 863 } 864 865 return $ftype; 866 } 867 868 869 // return string must begin with space 870 function _createSuffix($fname,&$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint,$funsigned) 871 { 872 $suffix = ''; 873 if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault"; 874 if ($fnotnull) $suffix .= ' NOT NULL'; 875 if ($fconstraint) $suffix .= ' '.$fconstraint; 876 return $suffix; 877 } 878 879 function _indexSQL($idxname, $tabname, $flds, $idxoptions) 880 { 881 $sql = array(); 882 883 if ( isset($idxoptions['REPLACE']) || isset($idxoptions['DROP']) ) { 884 $sql[] = sprintf ($this->dropIndex, $idxname); 885 if ( isset($idxoptions['DROP']) ) 886 return $sql; 887 } 888 889 if ( empty ($flds) ) { 890 return $sql; 891 } 892 893 $unique = isset($idxoptions['UNIQUE']) ? ' UNIQUE' : ''; 894 895 $s = 'CREATE' . $unique . ' INDEX ' . $idxname . ' ON ' . $tabname . ' '; 896 897 if ( isset($idxoptions[$this->upperName]) ) 898 $s .= $idxoptions[$this->upperName]; 899 900 if ( is_array($flds) ) 901 $flds = implode(', ',$flds); 902 $s .= '(' . $flds . ')'; 903 $sql[] = $s; 904 905 return $sql; 906 } 907 908 function _dropAutoIncrement($tabname) 909 { 910 return false; 911 } 912 913 function _tableSQL($tabname,$lines,$pkey,$tableoptions) 914 { 915 $sql = array(); 916 917 if (isset($tableoptions['REPLACE']) || isset ($tableoptions['DROP'])) { 918 $sql[] = sprintf($this->dropTable,$tabname); 919 if ($this->autoIncrement) { 920 $sInc = $this->_dropAutoIncrement($tabname); 921 if ($sInc) $sql[] = $sInc; 922 } 923 if ( isset ($tableoptions['DROP']) ) { 924 return $sql; 925 } 926 } 927 928 $s = "CREATE TABLE $tabname (\n"; 929 $s .= implode(",\n", $lines); 930 if (sizeof($pkey)>0) { 931 $s .= ",\n PRIMARY KEY ("; 932 $s .= implode(", ",$pkey).")"; 933 } 934 if (isset($tableoptions['CONSTRAINTS'])) 935 $s .= "\n".$tableoptions['CONSTRAINTS']; 936 937 if (isset($tableoptions[$this->upperName.'_CONSTRAINTS'])) 938 $s .= "\n".$tableoptions[$this->upperName.'_CONSTRAINTS']; 939 940 $s .= "\n)"; 941 if (isset($tableoptions[$this->upperName])) $s .= $tableoptions[$this->upperName]; 942 $sql[] = $s; 943 944 return $sql; 945 } 946 947 /** 948 GENERATE TRIGGERS IF NEEDED 949 used when table has auto-incrementing field that is emulated using triggers 950 */ 951 function _triggers($tabname,$taboptions) 952 { 953 return array(); 954 } 955 956 /** 957 Sanitize options, so that array elements with no keys are promoted to keys 958 */ 959 function _options($opts) 960 { 961 if (!is_array($opts)) return array(); 962 $newopts = array(); 963 foreach($opts as $k => $v) { 964 if (is_numeric($k)) $newopts[strtoupper($v)] = $v; 965 else $newopts[strtoupper($k)] = $v; 966 } 967 return $newopts; 968 } 969 970 971 function _getSizePrec($size) 972 { 973 $fsize = false; 974 $fprec = false; 975 $dotat = strpos($size,'.'); 976 if ($dotat === false) $dotat = strpos($size,','); 977 if ($dotat === false) $fsize = $size; 978 else { 979 $fsize = substr($size,0,$dotat); 980 $fprec = substr($size,$dotat+1); 981 } 982 return array($fsize, $fprec); 983 } 984 985 /** 986 "Florian Buzin [ easywe ]" <florian.buzin#easywe.de> 987 988 This function changes/adds new fields to your table. You don't 989 have to know if the col is new or not. It will check on its own. 990 */ 991 function changeTableSQL($tablename, $flds, $tableoptions = false, $dropOldFlds=false) 992 { 993 global $ADODB_FETCH_MODE; 994 995 $save = $ADODB_FETCH_MODE; 996 $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC; 997 if ($this->connection->fetchMode !== false) $savem = $this->connection->setFetchMode(false); 998 999 // check table exists 1000 $save_handler = $this->connection->raiseErrorFn; 1001 $this->connection->raiseErrorFn = ''; 1002 $cols = $this->metaColumns($tablename); 1003 $this->connection->raiseErrorFn = $save_handler; 1004 1005 if (isset($savem)) $this->connection->setFetchMode($savem); 1006 $ADODB_FETCH_MODE = $save; 1007 1008 if ( empty($cols)) { 1009 return $this->createTableSQL($tablename, $flds, $tableoptions); 1010 } 1011 1012 if (is_array($flds)) { 1013 // Cycle through the update fields, comparing 1014 // existing fields to fields to update. 1015 // if the Metatype and size is exactly the 1016 // same, ignore - by Mark Newham 1017 $holdflds = array(); 1018 foreach($flds as $k=>$v) { 1019 if ( isset($cols[$k]) && is_object($cols[$k]) ) { 1020 // If already not allowing nulls, then don't change 1021 $obj = $cols[$k]; 1022 if (isset($obj->not_null) && $obj->not_null) 1023 $v = str_replace('NOT NULL','',$v); 1024 if (isset($obj->auto_increment) && $obj->auto_increment && empty($v['AUTOINCREMENT'])) 1025 $v = str_replace('AUTOINCREMENT','',$v); 1026 1027 $c = $cols[$k]; 1028 $ml = $c->max_length; 1029 $mt = $this->metaType($c->type,$ml); 1030 1031 if (isset($c->scale)) $sc = $c->scale; 1032 else $sc = 99; // always force change if scale not known. 1033 1034 if ($sc == -1) $sc = false; 1035 list($fsize, $fprec) = $this->_getSizePrec($v['SIZE']); 1036 1037 if ($ml == -1) $ml = ''; 1038 if ($mt == 'X') $ml = $v['SIZE']; 1039 if (($mt != $v['TYPE']) || ($ml != $fsize || $sc != $fprec) || (isset($v['AUTOINCREMENT']) && $v['AUTOINCREMENT'] != $obj->auto_increment)) { 1040 $holdflds[$k] = $v; 1041 } 1042 } else { 1043 $holdflds[$k] = $v; 1044 } 1045 } 1046 $flds = $holdflds; 1047 } 1048 1049 1050 // already exists, alter table instead 1051 list($lines,$pkey,$idxs) = $this->_genFields($flds); 1052 // genfields can return FALSE at times 1053 if ($lines == null) $lines = array(); 1054 $alter = 'ALTER TABLE ' . $this->tableName($tablename); 1055 $sql = array(); 1056 1057 foreach ( $lines as $id => $v ) { 1058 if ( isset($cols[$id]) && is_object($cols[$id]) ) { 1059 1060 $flds = lens_ParseArgs($v,','); 1061 1062 // We are trying to change the size of the field, if not allowed, simply ignore the request. 1063 // $flds[1] holds the type, $flds[2] holds the size -postnuke addition 1064 if ($flds && in_array(strtoupper(substr($flds[0][1],0,4)),$this->invalidResizeTypes4) 1065 && (isset($flds[0][2]) && is_numeric($flds[0][2]))) { 1066 if ($this->debug) ADOConnection::outp(sprintf("<h3>%s cannot be changed to %s currently</h3>", $flds[0][0], $flds[0][1])); 1067 #echo "<h3>$this->alterCol cannot be changed to $flds currently</h3>"; 1068 continue; 1069 } 1070 $sql[] = $alter . $this->alterCol . ' ' . $v; 1071 } else { 1072 $sql[] = $alter . $this->addCol . ' ' . $v; 1073 } 1074 } 1075 1076 if ($dropOldFlds) { 1077 foreach ( $cols as $id => $v ) 1078 if ( !isset($lines[$id]) ) 1079 $sql[] = $alter . $this->dropCol . ' ' . $v->name; 1080 } 1081 return $sql; 1082 } 1083 } // class
title
Description
Body
title
Description
Body
title
Description
Body
title
Body