[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/adodb/ -> adodb-datadict.inc.php (source)

   1  <?php
   2  
   3  /**
   4    @version   v5.20.3  01-Jan-2016
   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 editting.
 185  
 186  	function GetCommentSQL($table,$col)
 187      {
 188          return false;
 189      }
 190  
 191  	function SetCommentSQL($table,$col,$cmt)
 192      {
 193          return false;
 194      }
 195  
 196  	function MetaTables()
 197      {
 198          if (!$this->connection->IsConnected()) return array();
 199          return $this->connection->MetaTables();
 200      }
 201  
 202  	function MetaColumns($tab, $upper=true, $schema=false)
 203      {
 204          if (!$this->connection->IsConnected()) return array();
 205          return $this->connection->MetaColumns($this->TableName($tab), $upper, $schema);
 206      }
 207  
 208  	function MetaPrimaryKeys($tab,$owner=false,$intkey=false)
 209      {
 210          if (!$this->connection->IsConnected()) return array();
 211          return $this->connection->MetaPrimaryKeys($this->TableName($tab), $owner, $intkey);
 212      }
 213  
 214  	function MetaIndexes($table, $primary = false, $owner = false)
 215      {
 216          if (!$this->connection->IsConnected()) return array();
 217          return $this->connection->MetaIndexes($this->TableName($table), $primary, $owner);
 218      }
 219  
 220  	function MetaType($t,$len=-1,$fieldobj=false)
 221      {
 222          static $typeMap = array(
 223          'VARCHAR' => 'C',
 224          'VARCHAR2' => 'C',
 225          'CHAR' => 'C',
 226          'C' => 'C',
 227          'STRING' => 'C',
 228          'NCHAR' => 'C',
 229          'NVARCHAR' => 'C',
 230          'VARYING' => 'C',
 231          'BPCHAR' => 'C',
 232          'CHARACTER' => 'C',
 233          'INTERVAL' => 'C',  # Postgres
 234          'MACADDR' => 'C', # postgres
 235          'VAR_STRING' => 'C', # mysql
 236          ##
 237          'LONGCHAR' => 'X',
 238          'TEXT' => 'X',
 239          'NTEXT' => 'X',
 240          'M' => 'X',
 241          'X' => 'X',
 242          'CLOB' => 'X',
 243          'NCLOB' => 'X',
 244          'LVARCHAR' => 'X',
 245          ##
 246          'BLOB' => 'B',
 247          'IMAGE' => 'B',
 248          'BINARY' => 'B',
 249          'VARBINARY' => 'B',
 250          'LONGBINARY' => 'B',
 251          'B' => 'B',
 252          ##
 253          'YEAR' => 'D', // mysql
 254          'DATE' => 'D',
 255          'D' => 'D',
 256          ##
 257          'UNIQUEIDENTIFIER' => 'C', # MS SQL Server
 258          ##
 259          'TIME' => 'T',
 260          'TIMESTAMP' => 'T',
 261          'DATETIME' => 'T',
 262          'TIMESTAMPTZ' => 'T',
 263          'SMALLDATETIME' => 'T',
 264          'T' => 'T',
 265          'TIMESTAMP WITHOUT TIME ZONE' => 'T', // postgresql
 266          ##
 267          'BOOL' => 'L',
 268          'BOOLEAN' => 'L',
 269          'BIT' => 'L',
 270          'L' => 'L',
 271          ##
 272          'COUNTER' => 'R',
 273          'R' => 'R',
 274          'SERIAL' => 'R', // ifx
 275          'INT IDENTITY' => 'R',
 276          ##
 277          'INT' => 'I',
 278          'INT2' => 'I',
 279          'INT4' => 'I',
 280          'INT8' => 'I',
 281          'INTEGER' => 'I',
 282          'INTEGER UNSIGNED' => 'I',
 283          'SHORT' => 'I',
 284          'TINYINT' => 'I',
 285          'SMALLINT' => 'I',
 286          'I' => 'I',
 287          ##
 288          'LONG' => 'N', // interbase is numeric, oci8 is blob
 289          'BIGINT' => 'N', // this is bigger than PHP 32-bit integers
 290          'DECIMAL' => 'N',
 291          'DEC' => 'N',
 292          'REAL' => 'N',
 293          'DOUBLE' => 'N',
 294          'DOUBLE PRECISION' => 'N',
 295          'SMALLFLOAT' => 'N',
 296          'FLOAT' => 'N',
 297          'NUMBER' => 'N',
 298          'NUM' => 'N',
 299          'NUMERIC' => 'N',
 300          'MONEY' => 'N',
 301  
 302          ## informix 9.2
 303          'SQLINT' => 'I',
 304          'SQLSERIAL' => 'I',
 305          'SQLSMINT' => 'I',
 306          'SQLSMFLOAT' => 'N',
 307          'SQLFLOAT' => 'N',
 308          'SQLMONEY' => 'N',
 309          'SQLDECIMAL' => 'N',
 310          'SQLDATE' => 'D',
 311          'SQLVCHAR' => 'C',
 312          'SQLCHAR' => 'C',
 313          'SQLDTIME' => 'T',
 314          'SQLINTERVAL' => 'N',
 315          'SQLBYTES' => 'B',
 316          'SQLTEXT' => 'X',
 317           ## informix 10
 318          "SQLINT8" => 'I8',
 319          "SQLSERIAL8" => 'I8',
 320          "SQLNCHAR" => 'C',
 321          "SQLNVCHAR" => 'C',
 322          "SQLLVARCHAR" => 'X',
 323          "SQLBOOL" => 'L'
 324          );
 325  
 326          if (!$this->connection->IsConnected()) {
 327              $t = strtoupper($t);
 328              if (isset($typeMap[$t])) return $typeMap[$t];
 329              return 'N';
 330          }
 331          return $this->connection->MetaType($t,$len,$fieldobj);
 332      }
 333  
 334  	function NameQuote($name = NULL,$allowBrackets=false)
 335      {
 336          if (!is_string($name)) {
 337              return FALSE;
 338          }
 339  
 340          $name = trim($name);
 341  
 342          if ( !is_object($this->connection) ) {
 343              return $name;
 344          }
 345  
 346          $quote = $this->connection->nameQuote;
 347  
 348          // if name is of the form `name`, quote it
 349          if ( preg_match('/^`(.+)`$/', $name, $matches) ) {
 350              return $quote . $matches[1] . $quote;
 351          }
 352  
 353          // if name contains special characters, quote it
 354          $regex = ($allowBrackets) ? $this->nameRegexBrackets : $this->nameRegex;
 355  
 356          if ( !preg_match('/^[' . $regex . ']+$/', $name) ) {
 357              return $quote . $name . $quote;
 358          }
 359  
 360          return $name;
 361      }
 362  
 363  	function TableName($name)
 364      {
 365          if ( $this->schema ) {
 366              return $this->NameQuote($this->schema) .'.'. $this->NameQuote($name);
 367          }
 368          return $this->NameQuote($name);
 369      }
 370  
 371      // Executes the sql array returned by GetTableSQL and GetIndexSQL
 372  	function ExecuteSQLArray($sql, $continueOnError = true)
 373      {
 374          $rez = 2;
 375          $conn = $this->connection;
 376          $saved = $conn->debug;
 377          foreach($sql as $line) {
 378  
 379              if ($this->debug) $conn->debug = true;
 380              $ok = $conn->Execute($line);
 381              $conn->debug = $saved;
 382              if (!$ok) {
 383                  if ($this->debug) ADOConnection::outp($conn->ErrorMsg());
 384                  if (!$continueOnError) return 0;
 385                  $rez = 1;
 386              }
 387          }
 388          return $rez;
 389      }
 390  
 391      /**
 392           Returns the actual type given a character code.
 393  
 394          C:  varchar
 395          X:  CLOB (character large object) or largest varchar size if CLOB is not supported
 396          C2: Multibyte varchar
 397          X2: Multibyte CLOB
 398  
 399          B:  BLOB (binary large object)
 400  
 401          D:  Date
 402          T:  Date-time
 403          L:  Integer field suitable for storing booleans (0 or 1)
 404          I:  Integer
 405          F:  Floating point number
 406          N:  Numeric or decimal number
 407      */
 408  
 409  	function ActualType($meta)
 410      {
 411          return $meta;
 412      }
 413  
 414  	function CreateDatabase($dbname,$options=false)
 415      {
 416          $options = $this->_Options($options);
 417          $sql = array();
 418  
 419          $s = 'CREATE DATABASE ' . $this->NameQuote($dbname);
 420          if (isset($options[$this->upperName]))
 421              $s .= ' '.$options[$this->upperName];
 422  
 423          $sql[] = $s;
 424          return $sql;
 425      }
 426  
 427      /*
 428       Generates the SQL to create index. Returns an array of sql strings.
 429      */
 430  	function CreateIndexSQL($idxname, $tabname, $flds, $idxoptions = false)
 431      {
 432          if (!is_array($flds)) {
 433              $flds = explode(',',$flds);
 434          }
 435  
 436          foreach($flds as $key => $fld) {
 437              # some indexes can use partial fields, eg. index first 32 chars of "name" with NAME(32)
 438              $flds[$key] = $this->NameQuote($fld,$allowBrackets=true);
 439          }
 440  
 441          return $this->_IndexSQL($this->NameQuote($idxname), $this->TableName($tabname), $flds, $this->_Options($idxoptions));
 442      }
 443  
 444  	function DropIndexSQL ($idxname, $tabname = NULL)
 445      {
 446          return array(sprintf($this->dropIndex, $this->NameQuote($idxname), $this->TableName($tabname)));
 447      }
 448  
 449  	function SetSchema($schema)
 450      {
 451          $this->schema = $schema;
 452      }
 453  
 454  	function AddColumnSQL($tabname, $flds)
 455      {
 456          $tabname = $this->TableName ($tabname);
 457          $sql = array();
 458          list($lines,$pkey,$idxs) = $this->_GenFields($flds);
 459          // genfields can return FALSE at times
 460          if ($lines  == null) $lines = array();
 461          $alter = 'ALTER TABLE ' . $tabname . $this->addCol . ' ';
 462          foreach($lines as $v) {
 463              $sql[] = $alter . $v;
 464          }
 465          if (is_array($idxs)) {
 466              foreach($idxs as $idx => $idxdef) {
 467                  $sql_idxs = $this->CreateIndexSql($idx, $tabname, $idxdef['cols'], $idxdef['opts']);
 468                  $sql = array_merge($sql, $sql_idxs);
 469              }
 470          }
 471          return $sql;
 472      }
 473  
 474      /**
 475       * Change the definition of one column
 476       *
 477       * As some DBM's can't do that on there own, you need to supply the complete defintion of the new table,
 478       * to allow, recreating the table and copying the content over to the new table
 479       * @param string $tabname table-name
 480       * @param string $flds column-name and type for the changed column
 481       * @param string $tableflds='' complete defintion of the new table, eg. for postgres, default ''
 482       * @param array/string $tableoptions='' options for the new table see CreateTableSQL, default ''
 483       * @return array with SQL strings
 484       */
 485  	function AlterColumnSQL($tabname, $flds, $tableflds='',$tableoptions='')
 486      {
 487          $tabname = $this->TableName ($tabname);
 488          $sql = array();
 489          list($lines,$pkey,$idxs) = $this->_GenFields($flds);
 490          // genfields can return FALSE at times
 491          if ($lines == null) $lines = array();
 492          $alter = 'ALTER TABLE ' . $tabname . $this->alterCol . ' ';
 493          foreach($lines as $v) {
 494              $sql[] = $alter . $v;
 495          }
 496          if (is_array($idxs)) {
 497              foreach($idxs as $idx => $idxdef) {
 498                  $sql_idxs = $this->CreateIndexSql($idx, $tabname, $idxdef['cols'], $idxdef['opts']);
 499                  $sql = array_merge($sql, $sql_idxs);
 500              }
 501  
 502          }
 503          return $sql;
 504      }
 505  
 506      /**
 507       * Rename one column
 508       *
 509       * Some DBM's can only do this together with changeing the type of the column (even if that stays the same, eg. mysql)
 510       * @param string $tabname table-name
 511       * @param string $oldcolumn column-name to be renamed
 512       * @param string $newcolumn new column-name
 513       * @param string $flds='' complete column-defintion-string like for AddColumnSQL, only used by mysql atm., default=''
 514       * @return array with SQL strings
 515       */
 516  	function RenameColumnSQL($tabname,$oldcolumn,$newcolumn,$flds='')
 517      {
 518          $tabname = $this->TableName ($tabname);
 519          if ($flds) {
 520              list($lines,$pkey,$idxs) = $this->_GenFields($flds);
 521              // genfields can return FALSE at times
 522              if ($lines == null) $lines = array();
 523              list(,$first) = each($lines);
 524              list(,$column_def) = preg_split("/[\t ]+/",$first,2);
 525          }
 526          return array(sprintf($this->renameColumn,$tabname,$this->NameQuote($oldcolumn),$this->NameQuote($newcolumn),$column_def));
 527      }
 528  
 529      /**
 530       * Drop one column
 531       *
 532       * Some DBM's can't do that on there own, you need to supply the complete defintion of the new table,
 533       * to allow, recreating the table and copying the content over to the new table
 534       * @param string $tabname table-name
 535       * @param string $flds column-name and type for the changed column
 536       * @param string $tableflds='' complete defintion of the new table, eg. for postgres, default ''
 537       * @param array/string $tableoptions='' options for the new table see CreateTableSQL, default ''
 538       * @return array with SQL strings
 539       */
 540  	function DropColumnSQL($tabname, $flds, $tableflds='',$tableoptions='')
 541      {
 542          $tabname = $this->TableName ($tabname);
 543          if (!is_array($flds)) $flds = explode(',',$flds);
 544          $sql = array();
 545          $alter = 'ALTER TABLE ' . $tabname . $this->dropCol . ' ';
 546          foreach($flds as $v) {
 547              $sql[] = $alter . $this->NameQuote($v);
 548          }
 549          return $sql;
 550      }
 551  
 552  	function DropTableSQL($tabname)
 553      {
 554          return array (sprintf($this->dropTable, $this->TableName($tabname)));
 555      }
 556  
 557  	function RenameTableSQL($tabname,$newname)
 558      {
 559          return array (sprintf($this->renameTable, $this->TableName($tabname),$this->TableName($newname)));
 560      }
 561  
 562      /**
 563       Generate the SQL to create table. Returns an array of sql strings.
 564      */
 565  	function CreateTableSQL($tabname, $flds, $tableoptions=array())
 566      {
 567          list($lines,$pkey,$idxs) = $this->_GenFields($flds, true);
 568          // genfields can return FALSE at times
 569          if ($lines == null) $lines = array();
 570  
 571          $taboptions = $this->_Options($tableoptions);
 572          $tabname = $this->TableName ($tabname);
 573          $sql = $this->_TableSQL($tabname,$lines,$pkey,$taboptions);
 574  
 575          // ggiunta - 2006/10/12 - KLUDGE:
 576          // if we are on autoincrement, and table options includes REPLACE, the
 577          // autoincrement sequence has already been dropped on table creation sql, so
 578          // we avoid passing REPLACE to trigger creation code. This prevents
 579          // creating sql that double-drops the sequence
 580          if ($this->autoIncrement && isset($taboptions['REPLACE']))
 581              unset($taboptions['REPLACE']);
 582          $tsql = $this->_Triggers($tabname,$taboptions);
 583          foreach($tsql as $s) $sql[] = $s;
 584  
 585          if (is_array($idxs)) {
 586              foreach($idxs as $idx => $idxdef) {
 587                  $sql_idxs = $this->CreateIndexSql($idx, $tabname,  $idxdef['cols'], $idxdef['opts']);
 588                  $sql = array_merge($sql, $sql_idxs);
 589              }
 590          }
 591  
 592          return $sql;
 593      }
 594  
 595  
 596  
 597  	function _GenFields($flds,$widespacing=false)
 598      {
 599          if (is_string($flds)) {
 600              $padding = '     ';
 601              $txt = $flds.$padding;
 602              $flds = array();
 603              $flds0 = Lens_ParseArgs($txt,',');
 604              $hasparam = false;
 605              foreach($flds0 as $f0) {
 606                  $f1 = array();
 607                  foreach($f0 as $token) {
 608                      switch (strtoupper($token)) {
 609                      case 'INDEX':
 610                          $f1['INDEX'] = '';
 611                          // fall through intentionally
 612                      case 'CONSTRAINT':
 613                      case 'DEFAULT':
 614                          $hasparam = $token;
 615                          break;
 616                      default:
 617                          if ($hasparam) $f1[$hasparam] = $token;
 618                          else $f1[] = $token;
 619                          $hasparam = false;
 620                          break;
 621                      }
 622                  }
 623                  // 'index' token without a name means single column index: name it after column
 624                  if (array_key_exists('INDEX', $f1) && $f1['INDEX'] == '') {
 625                      $f1['INDEX'] = isset($f0['NAME']) ? $f0['NAME'] : $f0[0];
 626                      // check if column name used to create an index name was quoted
 627                      if (($f1['INDEX'][0] == '"' || $f1['INDEX'][0] == "'" || $f1['INDEX'][0] == "`") &&
 628                          ($f1['INDEX'][0] == substr($f1['INDEX'], -1))) {
 629                          $f1['INDEX'] = $f1['INDEX'][0].'idx_'.substr($f1['INDEX'], 1, -1).$f1['INDEX'][0];
 630                      }
 631                      else
 632                          $f1['INDEX'] = 'idx_'.$f1['INDEX'];
 633                  }
 634                  // reset it, so we don't get next field 1st token as INDEX...
 635                  $hasparam = false;
 636  
 637                  $flds[] = $f1;
 638  
 639              }
 640          }
 641          $this->autoIncrement = false;
 642          $lines = array();
 643          $pkey = array();
 644          $idxs = array();
 645          foreach($flds as $fld) {
 646              $fld = _array_change_key_case($fld);
 647  
 648              $fname = false;
 649              $fdefault = false;
 650              $fautoinc = false;
 651              $ftype = false;
 652              $fsize = false;
 653              $fprec = false;
 654              $fprimary = false;
 655              $fnoquote = false;
 656              $fdefts = false;
 657              $fdefdate = false;
 658              $fconstraint = false;
 659              $fnotnull = false;
 660              $funsigned = false;
 661              $findex = '';
 662              $funiqueindex = false;
 663  
 664              //-----------------
 665              // Parse attributes
 666              foreach($fld as $attr => $v) {
 667                  if ($attr == 2 && is_numeric($v)) $attr = 'SIZE';
 668                  else if (is_numeric($attr) && $attr > 1 && !is_numeric($v)) $attr = strtoupper($v);
 669  
 670                  switch($attr) {
 671                  case '0':
 672                  case 'NAME':     $fname = $v; break;
 673                  case '1':
 674                  case 'TYPE':     $ty = $v; $ftype = $this->ActualType(strtoupper($v)); break;
 675  
 676                  case 'SIZE':
 677                                  $dotat = strpos($v,'.'); if ($dotat === false) $dotat = strpos($v,',');
 678                                  if ($dotat === false) $fsize = $v;
 679                                  else {
 680                                      $fsize = substr($v,0,$dotat);
 681                                      $fprec = substr($v,$dotat+1);
 682                                  }
 683                                  break;
 684                  case 'UNSIGNED': $funsigned = true; break;
 685                  case 'AUTOINCREMENT':
 686                  case 'AUTO':    $fautoinc = true; $fnotnull = true; break;
 687                  case 'KEY':
 688                  // a primary key col can be non unique in itself (if key spans many cols...)
 689                  case 'PRIMARY':    $fprimary = $v; $fnotnull = true; /*$funiqueindex = true;*/ break;
 690                  case 'DEF':
 691                  case 'DEFAULT': $fdefault = $v; break;
 692                  case 'NOTNULL': $fnotnull = $v; break;
 693                  case 'NOQUOTE': $fnoquote = $v; break;
 694                  case 'DEFDATE': $fdefdate = $v; break;
 695                  case 'DEFTIMESTAMP': $fdefts = $v; break;
 696                  case 'CONSTRAINT': $fconstraint = $v; break;
 697                  // let INDEX keyword create a 'very standard' index on column
 698                  case 'INDEX': $findex = $v; break;
 699                  case 'UNIQUE': $funiqueindex = true; break;
 700                  } //switch
 701              } // foreach $fld
 702  
 703              //--------------------
 704              // VALIDATE FIELD INFO
 705              if (!strlen($fname)) {
 706                  if ($this->debug) ADOConnection::outp("Undefined NAME");
 707                  return false;
 708              }
 709  
 710              $fid = strtoupper(preg_replace('/^`(.+)`$/', '$1', $fname));
 711              $fname = $this->NameQuote($fname);
 712  
 713              if (!strlen($ftype)) {
 714                  if ($this->debug) ADOConnection::outp("Undefined TYPE for field '$fname'");
 715                  return false;
 716              } else {
 717                  $ftype = strtoupper($ftype);
 718              }
 719  
 720              $ftype = $this->_GetSize($ftype, $ty, $fsize, $fprec);
 721  
 722              if ($ty == 'X' || $ty == 'X2' || $ty == 'B') $fnotnull = false; // some blob types do not accept nulls
 723  
 724              if ($fprimary) $pkey[] = $fname;
 725  
 726              // some databases do not allow blobs to have defaults
 727              if ($ty == 'X') $fdefault = false;
 728  
 729              // build list of indexes
 730              if ($findex != '') {
 731                  if (array_key_exists($findex, $idxs)) {
 732                      $idxs[$findex]['cols'][] = ($fname);
 733                      if (in_array('UNIQUE', $idxs[$findex]['opts']) != $funiqueindex) {
 734                          if ($this->debug) ADOConnection::outp("Index $findex defined once UNIQUE and once not");
 735                      }
 736                      if ($funiqueindex && !in_array('UNIQUE', $idxs[$findex]['opts']))
 737                          $idxs[$findex]['opts'][] = 'UNIQUE';
 738                  }
 739                  else
 740                  {
 741                      $idxs[$findex] = array();
 742                      $idxs[$findex]['cols'] = array($fname);
 743                      if ($funiqueindex)
 744                          $idxs[$findex]['opts'] = array('UNIQUE');
 745                      else
 746                          $idxs[$findex]['opts'] = array();
 747                  }
 748              }
 749  
 750              //--------------------
 751              // CONSTRUCT FIELD SQL
 752              if ($fdefts) {
 753                  if (substr($this->connection->databaseType,0,5) == 'mysql') {
 754                      $ftype = 'TIMESTAMP';
 755                  } else {
 756                      $fdefault = $this->connection->sysTimeStamp;
 757                  }
 758              } else if ($fdefdate) {
 759                  if (substr($this->connection->databaseType,0,5) == 'mysql') {
 760                      $ftype = 'TIMESTAMP';
 761                  } else {
 762                      $fdefault = $this->connection->sysDate;
 763                  }
 764              } else if ($fdefault !== false && !$fnoquote) {
 765                  if ($ty == 'C' or $ty == 'X' or
 766                      ( substr($fdefault,0,1) != "'" && !is_numeric($fdefault))) {
 767  
 768                      if (($ty == 'D' || $ty == 'T') && strtolower($fdefault) != 'null') {
 769                          // convert default date into database-aware code
 770                          if ($ty == 'T')
 771                          {
 772                              $fdefault = $this->connection->DBTimeStamp($fdefault);
 773                          }
 774                          else
 775                          {
 776                              $fdefault = $this->connection->DBDate($fdefault);
 777                          }
 778                      }
 779                      else
 780                      if (strlen($fdefault) != 1 && substr($fdefault,0,1) == ' ' && substr($fdefault,strlen($fdefault)-1) == ' ')
 781                          $fdefault = trim($fdefault);
 782                      else if (strtolower($fdefault) != 'null')
 783                          $fdefault = $this->connection->qstr($fdefault);
 784                  }
 785              }
 786              $suffix = $this->_CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint,$funsigned);
 787  
 788              // add index creation
 789              if ($widespacing) $fname = str_pad($fname,24);
 790  
 791               // check for field names appearing twice
 792              if (array_key_exists($fid, $lines)) {
 793                   ADOConnection::outp("Field '$fname' defined twice");
 794              }
 795  
 796              $lines[$fid] = $fname.' '.$ftype.$suffix;
 797  
 798              if ($fautoinc) $this->autoIncrement = true;
 799          } // foreach $flds
 800  
 801          return array($lines,$pkey,$idxs);
 802      }
 803  
 804      /**
 805           GENERATE THE SIZE PART OF THE DATATYPE
 806              $ftype is the actual type
 807              $ty is the type defined originally in the DDL
 808      */
 809  	function _GetSize($ftype, $ty, $fsize, $fprec)
 810      {
 811          if (strlen($fsize) && $ty != 'X' && $ty != 'B' && strpos($ftype,'(') === false) {
 812              $ftype .= "(".$fsize;
 813              if (strlen($fprec)) $ftype .= ",".$fprec;
 814              $ftype .= ')';
 815          }
 816          return $ftype;
 817      }
 818  
 819  
 820      // return string must begin with space
 821  	function _CreateSuffix($fname,&$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint,$funsigned)
 822      {
 823          $suffix = '';
 824          if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault";
 825          if ($fnotnull) $suffix .= ' NOT NULL';
 826          if ($fconstraint) $suffix .= ' '.$fconstraint;
 827          return $suffix;
 828      }
 829  
 830  	function _IndexSQL($idxname, $tabname, $flds, $idxoptions)
 831      {
 832          $sql = array();
 833  
 834          if ( isset($idxoptions['REPLACE']) || isset($idxoptions['DROP']) ) {
 835              $sql[] = sprintf ($this->dropIndex, $idxname);
 836              if ( isset($idxoptions['DROP']) )
 837                  return $sql;
 838          }
 839  
 840          if ( empty ($flds) ) {
 841              return $sql;
 842          }
 843  
 844          $unique = isset($idxoptions['UNIQUE']) ? ' UNIQUE' : '';
 845  
 846          $s = 'CREATE' . $unique . ' INDEX ' . $idxname . ' ON ' . $tabname . ' ';
 847  
 848          if ( isset($idxoptions[$this->upperName]) )
 849              $s .= $idxoptions[$this->upperName];
 850  
 851          if ( is_array($flds) )
 852              $flds = implode(', ',$flds);
 853          $s .= '(' . $flds . ')';
 854          $sql[] = $s;
 855  
 856          return $sql;
 857      }
 858  
 859  	function _DropAutoIncrement($tabname)
 860      {
 861          return false;
 862      }
 863  
 864  	function _TableSQL($tabname,$lines,$pkey,$tableoptions)
 865      {
 866          $sql = array();
 867  
 868          if (isset($tableoptions['REPLACE']) || isset ($tableoptions['DROP'])) {
 869              $sql[] = sprintf($this->dropTable,$tabname);
 870              if ($this->autoIncrement) {
 871                  $sInc = $this->_DropAutoIncrement($tabname);
 872                  if ($sInc) $sql[] = $sInc;
 873              }
 874              if ( isset ($tableoptions['DROP']) ) {
 875                  return $sql;
 876              }
 877          }
 878          $s = "CREATE TABLE $tabname (\n";
 879          $s .= implode(",\n", $lines);
 880          if (sizeof($pkey)>0) {
 881              $s .= ",\n                 PRIMARY KEY (";
 882              $s .= implode(", ",$pkey).")";
 883          }
 884          if (isset($tableoptions['CONSTRAINTS']))
 885              $s .= "\n".$tableoptions['CONSTRAINTS'];
 886  
 887          if (isset($tableoptions[$this->upperName.'_CONSTRAINTS']))
 888              $s .= "\n".$tableoptions[$this->upperName.'_CONSTRAINTS'];
 889  
 890          $s .= "\n)";
 891          if (isset($tableoptions[$this->upperName])) $s .= $tableoptions[$this->upperName];
 892          $sql[] = $s;
 893  
 894          return $sql;
 895      }
 896  
 897      /**
 898          GENERATE TRIGGERS IF NEEDED
 899          used when table has auto-incrementing field that is emulated using triggers
 900      */
 901  	function _Triggers($tabname,$taboptions)
 902      {
 903          return array();
 904      }
 905  
 906      /**
 907          Sanitize options, so that array elements with no keys are promoted to keys
 908      */
 909  	function _Options($opts)
 910      {
 911          if (!is_array($opts)) return array();
 912          $newopts = array();
 913          foreach($opts as $k => $v) {
 914              if (is_numeric($k)) $newopts[strtoupper($v)] = $v;
 915              else $newopts[strtoupper($k)] = $v;
 916          }
 917          return $newopts;
 918      }
 919  
 920  
 921  	function _getSizePrec($size)
 922      {
 923          $fsize = false;
 924          $fprec = false;
 925          $dotat = strpos($size,'.');
 926          if ($dotat === false) $dotat = strpos($size,',');
 927          if ($dotat === false) $fsize = $size;
 928          else {
 929              $fsize = substr($size,0,$dotat);
 930              $fprec = substr($size,$dotat+1);
 931          }
 932          return array($fsize, $fprec);
 933      }
 934  
 935      /**
 936      "Florian Buzin [ easywe ]" <florian.buzin#easywe.de>
 937  
 938      This function changes/adds new fields to your table. You don't
 939      have to know if the col is new or not. It will check on its own.
 940      */
 941  	function ChangeTableSQL($tablename, $flds, $tableoptions = false, $dropOldFlds=false)
 942      {
 943      global $ADODB_FETCH_MODE;
 944  
 945          $save = $ADODB_FETCH_MODE;
 946          $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
 947          if ($this->connection->fetchMode !== false) $savem = $this->connection->SetFetchMode(false);
 948  
 949          // check table exists
 950          $save_handler = $this->connection->raiseErrorFn;
 951          $this->connection->raiseErrorFn = '';
 952          $cols = $this->MetaColumns($tablename);
 953          $this->connection->raiseErrorFn = $save_handler;
 954  
 955          if (isset($savem)) $this->connection->SetFetchMode($savem);
 956          $ADODB_FETCH_MODE = $save;
 957  
 958          if ( empty($cols)) {
 959              return $this->CreateTableSQL($tablename, $flds, $tableoptions);
 960          }
 961  
 962          if (is_array($flds)) {
 963          // Cycle through the update fields, comparing
 964          // existing fields to fields to update.
 965          // if the Metatype and size is exactly the
 966          // same, ignore - by Mark Newham
 967              $holdflds = array();
 968              foreach($flds as $k=>$v) {
 969                  if ( isset($cols[$k]) && is_object($cols[$k]) ) {
 970                      // If already not allowing nulls, then don't change
 971                      $obj = $cols[$k];
 972                      if (isset($obj->not_null) && $obj->not_null)
 973                          $v = str_replace('NOT NULL','',$v);
 974                      if (isset($obj->auto_increment) && $obj->auto_increment && empty($v['AUTOINCREMENT']))
 975                          $v = str_replace('AUTOINCREMENT','',$v);
 976  
 977                      $c = $cols[$k];
 978                      $ml = $c->max_length;
 979                      $mt = $this->MetaType($c->type,$ml);
 980  
 981                      if (isset($c->scale)) $sc = $c->scale;
 982                      else $sc = 99; // always force change if scale not known.
 983  
 984                      if ($sc == -1) $sc = false;
 985                      list($fsize, $fprec) = $this->_getSizePrec($v['SIZE']);
 986  
 987                      if ($ml == -1) $ml = '';
 988                      if ($mt == 'X') $ml = $v['SIZE'];
 989                      if (($mt != $v['TYPE']) || ($ml != $fsize || $sc != $fprec) || (isset($v['AUTOINCREMENT']) && $v['AUTOINCREMENT'] != $obj->auto_increment)) {
 990                          $holdflds[$k] = $v;
 991                      }
 992                  } else {
 993                      $holdflds[$k] = $v;
 994                  }
 995              }
 996              $flds = $holdflds;
 997          }
 998  
 999  
1000          // already exists, alter table instead
1001          list($lines,$pkey,$idxs) = $this->_GenFields($flds);
1002          // genfields can return FALSE at times
1003          if ($lines == null) $lines = array();
1004          $alter = 'ALTER TABLE ' . $this->TableName($tablename);
1005          $sql = array();
1006  
1007          foreach ( $lines as $id => $v ) {
1008              if ( isset($cols[$id]) && is_object($cols[$id]) ) {
1009  
1010                  $flds = Lens_ParseArgs($v,',');
1011  
1012                  //  We are trying to change the size of the field, if not allowed, simply ignore the request.
1013                  // $flds[1] holds the type, $flds[2] holds the size -postnuke addition
1014                  if ($flds && in_array(strtoupper(substr($flds[0][1],0,4)),$this->invalidResizeTypes4)
1015                   && (isset($flds[0][2]) && is_numeric($flds[0][2]))) {
1016                      if ($this->debug) ADOConnection::outp(sprintf("<h3>%s cannot be changed to %s currently</h3>", $flds[0][0], $flds[0][1]));
1017                      #echo "<h3>$this->alterCol cannot be changed to $flds currently</h3>";
1018                      continue;
1019                   }
1020                  $sql[] = $alter . $this->alterCol . ' ' . $v;
1021              } else {
1022                  $sql[] = $alter . $this->addCol . ' ' . $v;
1023              }
1024          }
1025  
1026          if ($dropOldFlds) {
1027              foreach ( $cols as $id => $v )
1028                  if ( !isset($lines[$id]) )
1029                      $sql[] = $alter . $this->dropCol . ' ' . $v->name;
1030          }
1031          return $sql;
1032      }
1033  } // class


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1