Verzeichnisstruktur phpBB-3.0.0


Veröffentlicht
12.12.2007

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

      (Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

db_tools.php

Zuletzt modifiziert: 09.10.2024, 12:51 - Dateigröße: 37.39 KiB


 0001  <?php
 0002  /**
 0003  *
 0004  * @package dbal
 0005  * @version $Id$
 0006  * @copyright (c) 2007 phpBB Group
 0007  * @license http://opensource.org/licenses/gpl-license.php GNU Public License
 0008  *
 0009  */
 0010   
 0011  /**
 0012  * @ignore
 0013  */
 0014  if (!defined('IN_PHPBB'))
 0015  {
 0016      exit;
 0017  }
 0018   
 0019  /**
 0020  * Database Tools for handling cross-db actions such as altering columns, etc.
 0021  * Currently not supported is returning SQL for creating tables.
 0022  *
 0023  * @package dbal
 0024  * @note currently not used within phpBB3, but may be utilized later.
 0025  */
 0026  class phpbb_db_tools
 0027  {
 0028      /**
 0029      * Current sql layer
 0030      */
 0031      var $sql_layer = '';
 0032   
 0033      var $dbms_type_map = array(
 0034          'mysql_41'    => array(
 0035              'INT:'        => 'int(%d)',
 0036              'BINT'        => 'bigint(20)',
 0037              'UINT'        => 'mediumint(8) UNSIGNED',
 0038              'UINT:'        => 'int(%d) UNSIGNED',
 0039              'TINT:'        => 'tinyint(%d)',
 0040              'USINT'        => 'smallint(4) UNSIGNED',
 0041              'BOOL'        => 'tinyint(1) UNSIGNED',
 0042              'VCHAR'        => 'varchar(255)',
 0043              'VCHAR:'    => 'varchar(%d)',
 0044              'CHAR:'        => 'char(%d)',
 0045              'XSTEXT'    => 'text',
 0046              'XSTEXT_UNI'=> 'varchar(100)',
 0047              'STEXT'        => 'text',
 0048              'STEXT_UNI'    => 'varchar(255)',
 0049              'TEXT'        => 'text',
 0050              'TEXT_UNI'    => 'text',
 0051              'MTEXT'        => 'mediumtext',
 0052              'MTEXT_UNI'    => 'mediumtext',
 0053              'TIMESTAMP'    => 'int(11) UNSIGNED',
 0054              'DECIMAL'    => 'decimal(5,2)',
 0055              'DECIMAL:'    => 'decimal(%d,2)',
 0056              'PDECIMAL'    => 'decimal(6,3)',
 0057              'PDECIMAL:'    => 'decimal(%d,3)',
 0058              'VCHAR_UNI'    => 'varchar(255)',
 0059              'VCHAR_UNI:'=> 'varchar(%d)',
 0060              'VCHAR_CI'    => 'varchar(255)',
 0061              'VARBINARY'    => 'varbinary(255)',
 0062          ),
 0063   
 0064          'mysql_40'    => array(
 0065              'INT:'        => 'int(%d)',
 0066              'BINT'        => 'bigint(20)',
 0067              'UINT'        => 'mediumint(8) UNSIGNED',
 0068              'UINT:'        => 'int(%d) UNSIGNED',
 0069              'TINT:'        => 'tinyint(%d)',
 0070              'USINT'        => 'smallint(4) UNSIGNED',
 0071              'BOOL'        => 'tinyint(1) UNSIGNED',
 0072              'VCHAR'        => 'varbinary(255)',
 0073              'VCHAR:'    => 'varbinary(%d)',
 0074              'CHAR:'        => 'binary(%d)',
 0075              'XSTEXT'    => 'blob',
 0076              'XSTEXT_UNI'=> 'blob',
 0077              'STEXT'        => 'blob',
 0078              'STEXT_UNI'    => 'blob',
 0079              'TEXT'        => 'blob',
 0080              'TEXT_UNI'    => 'blob',
 0081              'MTEXT'        => 'mediumblob',
 0082              'MTEXT_UNI'    => 'mediumblob',
 0083              'TIMESTAMP'    => 'int(11) UNSIGNED',
 0084              'DECIMAL'    => 'decimal(5,2)',
 0085              'DECIMAL:'    => 'decimal(%d,2)',
 0086              'PDECIMAL'    => 'decimal(6,3)',
 0087              'PDECIMAL:'    => 'decimal(%d,3)',
 0088              'VCHAR_UNI'    => 'blob',
 0089              'VCHAR_UNI:'=> array('varbinary(%d)', 'limit' => array('mult', 3, 255, 'blob')),
 0090              'VCHAR_CI'    => 'blob',
 0091              'VARBINARY'    => 'varbinary(255)',
 0092          ),
 0093   
 0094          'firebird'    => array(
 0095              'INT:'        => 'INTEGER',
 0096              'BINT'        => 'DOUBLE PRECISION',
 0097              'UINT'        => 'INTEGER',
 0098              'UINT:'        => 'INTEGER',
 0099              'TINT:'        => 'INTEGER',
 0100              'USINT'        => 'INTEGER',
 0101              'BOOL'        => 'INTEGER',
 0102              'VCHAR'        => 'VARCHAR(255) CHARACTER SET NONE',
 0103              'VCHAR:'    => 'VARCHAR(%d) CHARACTER SET NONE',
 0104              'CHAR:'        => 'CHAR(%d) CHARACTER SET NONE',
 0105              'XSTEXT'    => 'BLOB SUB_TYPE TEXT CHARACTER SET NONE',
 0106              'STEXT'        => 'BLOB SUB_TYPE TEXT CHARACTER SET NONE',
 0107              'TEXT'        => 'BLOB SUB_TYPE TEXT CHARACTER SET NONE',
 0108              'MTEXT'        => 'BLOB SUB_TYPE TEXT CHARACTER SET NONE',
 0109              'XSTEXT_UNI'=> 'VARCHAR(100) CHARACTER SET UTF8',
 0110              'STEXT_UNI'    => 'VARCHAR(255) CHARACTER SET UTF8',
 0111              'TEXT_UNI'    => 'BLOB SUB_TYPE TEXT CHARACTER SET UTF8',
 0112              'MTEXT_UNI'    => 'BLOB SUB_TYPE TEXT CHARACTER SET UTF8',
 0113              'TIMESTAMP'    => 'INTEGER',
 0114              'DECIMAL'    => 'DOUBLE PRECISION',
 0115              'DECIMAL:'    => 'DOUBLE PRECISION',
 0116              'PDECIMAL'    => 'DOUBLE PRECISION',
 0117              'PDECIMAL:'    => 'DOUBLE PRECISION',
 0118              'VCHAR_UNI'    => 'VARCHAR(255) CHARACTER SET UTF8',
 0119              'VCHAR_UNI:'=> 'VARCHAR(%d) CHARACTER SET UTF8',
 0120              'VCHAR_CI'    => 'VARCHAR(255) CHARACTER SET UTF8',
 0121              'VARBINARY'    => 'CHAR(255) CHARACTER SET NONE',
 0122          ),
 0123   
 0124          'mssql'        => array(
 0125              'INT:'        => '[int]',
 0126              'BINT'        => '[float]',
 0127              'UINT'        => '[int]',
 0128              'UINT:'        => '[int]',
 0129              'TINT:'        => '[int]',
 0130              'USINT'        => '[int]',
 0131              'BOOL'        => '[int]',
 0132              'VCHAR'        => '[varchar] (255)',
 0133              'VCHAR:'    => '[varchar] (%d)',
 0134              'CHAR:'        => '[char] (%d)',
 0135              'XSTEXT'    => '[varchar] (1000)',
 0136              'STEXT'        => '[varchar] (3000)',
 0137              'TEXT'        => '[varchar] (8000)',
 0138              'MTEXT'        => '[text]',
 0139              'XSTEXT_UNI'=> '[varchar] (100)',
 0140              'STEXT_UNI'    => '[varchar] (255)',
 0141              'TEXT_UNI'    => '[varchar] (4000)',
 0142              'MTEXT_UNI'    => '[text]',
 0143              'TIMESTAMP'    => '[int]',
 0144              'DECIMAL'    => '[float]',
 0145              'DECIMAL:'    => '[float]',
 0146              'PDECIMAL'    => '[float]',
 0147              'PDECIMAL:'    => '[float]',
 0148              'VCHAR_UNI'    => '[varchar] (255)',
 0149              'VCHAR_UNI:'=> '[varchar] (%d)',
 0150              'VCHAR_CI'    => '[varchar] (255)',
 0151              'VARBINARY'    => '[varchar] (255)',
 0152          ),
 0153   
 0154          'oracle'    => array(
 0155              'INT:'        => 'number(%d)',
 0156              'BINT'        => 'number(20)',
 0157              'UINT'        => 'number(8)',
 0158              'UINT:'        => 'number(%d)',
 0159              'TINT:'        => 'number(%d)',
 0160              'USINT'        => 'number(4)',
 0161              'BOOL'        => 'number(1)',
 0162              'VCHAR'        => 'varchar2(255)',
 0163              'VCHAR:'    => 'varchar2(%d)',
 0164              'CHAR:'        => 'char(%d)',
 0165              'XSTEXT'    => 'varchar2(1000)',
 0166              'STEXT'        => 'varchar2(3000)',
 0167              'TEXT'        => 'clob',
 0168              'MTEXT'        => 'clob',
 0169              'XSTEXT_UNI'=> 'varchar2(300)',
 0170              'STEXT_UNI'    => 'varchar2(765)',
 0171              'TEXT_UNI'    => 'clob',
 0172              'MTEXT_UNI'    => 'clob',
 0173              'TIMESTAMP'    => 'number(11)',
 0174              'DECIMAL'    => 'number(5, 2)',
 0175              'DECIMAL:'    => 'number(%d, 2)',
 0176              'PDECIMAL'    => 'number(6, 3)',
 0177              'PDECIMAL:'    => 'number(%d, 3)',
 0178              'VCHAR_UNI'    => 'varchar2(765)',
 0179              'VCHAR_UNI:'=> array('varchar2(%d)', 'limit' => array('mult', 3, 765, 'clob')),
 0180              'VCHAR_CI'    => 'varchar2(255)',
 0181              'VARBINARY'    => 'raw(255)',
 0182          ),
 0183   
 0184          'sqlite'    => array(
 0185              'INT:'        => 'int(%d)',
 0186              'BINT'        => 'bigint(20)',
 0187              'UINT'        => 'INTEGER UNSIGNED', //'mediumint(8) UNSIGNED',
 0188              'UINT:'        => 'INTEGER UNSIGNED', // 'int(%d) UNSIGNED',
 0189              'TINT:'        => 'tinyint(%d)',
 0190              'USINT'        => 'INTEGER UNSIGNED', //'mediumint(4) UNSIGNED',
 0191              'BOOL'        => 'INTEGER UNSIGNED', //'tinyint(1) UNSIGNED',
 0192              'VCHAR'        => 'varchar(255)',
 0193              'VCHAR:'    => 'varchar(%d)',
 0194              'CHAR:'        => 'char(%d)',
 0195              'XSTEXT'    => 'text(65535)',
 0196              'STEXT'        => 'text(65535)',
 0197              'TEXT'        => 'text(65535)',
 0198              'MTEXT'        => 'mediumtext(16777215)',
 0199              'XSTEXT_UNI'=> 'text(65535)',
 0200              'STEXT_UNI'    => 'text(65535)',
 0201              'TEXT_UNI'    => 'text(65535)',
 0202              'MTEXT_UNI'    => 'mediumtext(16777215)',
 0203              'TIMESTAMP'    => 'INTEGER UNSIGNED', //'int(11) UNSIGNED',
 0204              'DECIMAL'    => 'decimal(5,2)',
 0205              'DECIMAL:'    => 'decimal(%d,2)',
 0206              'PDECIMAL'    => 'decimal(6,3)',
 0207              'PDECIMAL:'    => 'decimal(%d,3)',
 0208              'VCHAR_UNI'    => 'varchar(255)',
 0209              'VCHAR_UNI:'=> 'varchar(%d)',
 0210              'VCHAR_CI'    => 'varchar(255)',
 0211              'VARBINARY'    => 'blob',
 0212          ),
 0213   
 0214          'postgres'    => array(
 0215              'INT:'        => 'INT4',
 0216              'BINT'        => 'INT8',
 0217              'UINT'        => 'INT4', // unsigned
 0218              'UINT:'        => 'INT4', // unsigned
 0219              'USINT'        => 'INT2', // unsigned
 0220              'BOOL'        => 'INT2', // unsigned
 0221              'TINT:'        => 'INT2',
 0222              'VCHAR'        => 'varchar(255)',
 0223              'VCHAR:'    => 'varchar(%d)',
 0224              'CHAR:'        => 'char(%d)',
 0225              'XSTEXT'    => 'varchar(1000)',
 0226              'STEXT'        => 'varchar(3000)',
 0227              'TEXT'        => 'varchar(8000)',
 0228              'MTEXT'        => 'TEXT',
 0229              'XSTEXT_UNI'=> 'varchar(100)',
 0230              'STEXT_UNI'    => 'varchar(255)',
 0231              'TEXT_UNI'    => 'varchar(4000)',
 0232              'MTEXT_UNI'    => 'TEXT',
 0233              'TIMESTAMP'    => 'INT4', // unsigned
 0234              'DECIMAL'    => 'decimal(5,2)',
 0235              'DECIMAL:'    => 'decimal(%d,2)',
 0236              'PDECIMAL'    => 'decimal(6,3)',
 0237              'PDECIMAL:'    => 'decimal(%d,3)',
 0238              'VCHAR_UNI'    => 'varchar(255)',
 0239              'VCHAR_UNI:'=> 'varchar(%d)',
 0240              'VCHAR_CI'    => 'varchar_ci',
 0241              'VARBINARY'    => 'bytea',
 0242          ),
 0243      );
 0244   
 0245      // A list of types being unsigned for better reference in some db's
 0246      var $unsigned_types = array('UINT', 'UINT:', 'USINT', 'BOOL', 'TIMESTAMP');
 0247      var $supported_dbms = array('firebird', 'mssql', 'mysql_40', 'mysql_41', 'oracle', 'postgres', 'sqlite');
 0248   
 0249      /**
 0250      * Set this to true if you only want to return the 'to-be-executed' SQL statement(s) (as an array).
 0251      */
 0252      var $return_statements = false;
 0253   
 0254      /**
 0255      */
 0256      function phpbb_db_tools(&$db)
 0257      {
 0258          $this->db = $db;
 0259   
 0260          // Determine mapping database type
 0261          switch ($this->db->sql_layer)
 0262          {
 0263              case 'mysql':
 0264                  $this->sql_layer = 'mysql_40';
 0265              break;
 0266   
 0267              case 'mysql4':
 0268                  if (version_compare($this->db->mysql_version, '4.1.3', '>='))
 0269                  {
 0270                      $this->sql_layer = 'mysql_41';
 0271                  }
 0272                  else
 0273                  {
 0274                      $this->sql_layer = 'mysql_40';
 0275                  }
 0276              break;
 0277   
 0278              case 'mysqli':
 0279                  $this->sql_layer = 'mysql_41';
 0280              break;
 0281   
 0282              case 'mssql':
 0283              case 'mssql_odbc':
 0284                  $this->sql_layer = 'mssql';
 0285              break;
 0286   
 0287              default:
 0288                  $this->sql_layer = $this->db->sql_layer;
 0289              break;
 0290          }
 0291      }
 0292   
 0293      /**
 0294      * Handle passed database update array.
 0295      * Expected structure...
 0296      * Key being one of the following
 0297      *    change_columns: Column changes (only type, not name)
 0298      *    add_columns: Add columns to a table
 0299      *    drop_keys: Dropping keys
 0300      *    drop_columns: Removing/Dropping columns
 0301      *    add_primary_keys: adding primary keys
 0302      *    add_unique_index: adding an unique index
 0303      *    add_index: adding an index
 0304      *
 0305      * The values are in this format:
 0306      *        {TABLE NAME}        => array(
 0307      *            {COLUMN NAME}        => array({COLUMN TYPE}, {DEFAULT VALUE}, {OPTIONAL VARIABLES}),
 0308      *            {KEY/INDEX NAME}    => array({COLUMN NAMES}),
 0309      *        )
 0310      *
 0311      * For more information have a look at /develop/create_schema_files.php (only available through CVS)
 0312      */
 0313      function perform_schema_changes($schema_changes)
 0314      {
 0315          if (empty($schema_changes))
 0316          {
 0317              return;
 0318          }
 0319   
 0320          $statements = array();
 0321   
 0322          // Change columns?
 0323          if (!empty($schema_changes['change_columns']))
 0324          {
 0325              foreach ($schema_changes['change_columns'] as $table => $columns)
 0326              {
 0327                  foreach ($columns as $column_name => $column_data)
 0328                  {
 0329                      $result = $this->sql_column_change($table, $column_name, $column_data);
 0330   
 0331                      if ($this->return_statements)
 0332                      {
 0333                          $statements = array_merge($statements, $result);
 0334                      }
 0335                  }
 0336              }
 0337          }
 0338   
 0339          // Add columns?
 0340          if (!empty($schema_changes['add_columns']))
 0341          {
 0342              foreach ($schema_changes['add_columns'] as $table => $columns)
 0343              {
 0344                  foreach ($columns as $column_name => $column_data)
 0345                  {
 0346                      // Only add the column if it does not exist yet
 0347                      if (!$this->sql_column_exists($table, $column_name))
 0348                      {
 0349                          $result = $this->sql_column_add($table, $column_name, $column_data);
 0350   
 0351                          if ($this->return_statements)
 0352                          {
 0353                              $statements = array_merge($statements, $result);
 0354                          }
 0355                      }
 0356                  }
 0357              }
 0358          }
 0359   
 0360          // Remove keys?
 0361          if (!empty($schema_changes['drop_keys']))
 0362          {
 0363              foreach ($schema_changes['drop_keys'] as $table => $indexes)
 0364              {
 0365                  foreach ($indexes as $index_name)
 0366                  {
 0367                      $result = $this->sql_index_drop($table, $index_name);
 0368   
 0369                      if ($this->return_statements)
 0370                      {
 0371                          $statements = array_merge($statements, $result);
 0372                      }
 0373                  }
 0374              }
 0375          }
 0376   
 0377          // Drop columns?
 0378          if (!empty($schema_changes['drop_columns']))
 0379          {
 0380              foreach ($schema_changes['drop_columns'] as $table => $columns)
 0381              {
 0382                  foreach ($columns as $column)
 0383                  {
 0384                      $result = $this->sql_column_remove($table, $column);
 0385   
 0386                      if ($this->return_statements)
 0387                      {
 0388                          $statements = array_merge($statements, $result);
 0389                      }
 0390                  }
 0391              }
 0392          }
 0393   
 0394          // Add primary keys?
 0395          if (!empty($schema_changes['add_primary_keys']))
 0396          {
 0397              foreach ($schema_changes['add_primary_keys'] as $table => $columns)
 0398              {
 0399                  $result = $this->sql_create_primary_key($table, $columns);
 0400   
 0401                  if ($this->return_statements)
 0402                  {
 0403                      $statements = array_merge($statements, $result);
 0404                  }
 0405              }
 0406          }
 0407   
 0408          // Add unqiue indexes?
 0409          if (!empty($schema_changes['add_unique_index']))
 0410          {
 0411              foreach ($schema_changes['add_unique_index'] as $table => $index_array)
 0412              {
 0413                  foreach ($index_array as $index_name => $column)
 0414                  {
 0415                      $result = $this->sql_create_unique_index($table, $index_name, $column);
 0416   
 0417                      if ($this->return_statements)
 0418                      {
 0419                          $statements = array_merge($statements, $result);
 0420                      }
 0421                  }
 0422              }
 0423          }
 0424   
 0425          // Add indexes?
 0426          if (!empty($schema_changes['add_index']))
 0427          {
 0428              foreach ($schema_changes['add_index'] as $table => $index_array)
 0429              {
 0430                  foreach ($index_array as $index_name => $column)
 0431                  {
 0432                      $result = $this->sql_create_index($table, $index_name, $column);
 0433   
 0434                      if ($this->return_statements)
 0435                      {
 0436                          $statements = array_merge($statements, $result);
 0437                      }
 0438                  }
 0439              }
 0440          }
 0441   
 0442          if ($this->return_statements)
 0443          {
 0444              return $statements;
 0445          }
 0446      }
 0447   
 0448      /**
 0449      * Check if a specified column exist
 0450      * @return bool True if column exists, else false
 0451      */
 0452      function sql_column_exists($table, $column_name)
 0453      {
 0454          switch ($this->sql_layer)
 0455          {
 0456              case 'mysql_40':
 0457              case 'mysql_41':
 0458   
 0459                  $sql = "SHOW COLUMNS FROM $table";
 0460                  $result = $this->db->sql_query($sql);
 0461   
 0462                  while ($row = $this->db->sql_fetchrow($result))
 0463                  {
 0464                      // lower case just in case
 0465                      if (strtolower($row['Field']) == $column_name)
 0466                      {
 0467                          $this->db->sql_freeresult($result);
 0468                          return true;
 0469                      }
 0470                  }
 0471                  $this->db->sql_freeresult($result);
 0472                  return false;
 0473              break;
 0474   
 0475              // PostgreSQL has a way of doing this in a much simpler way but would
 0476              // not allow us to support all versions of PostgreSQL
 0477              case 'postgres':
 0478                  $sql = "SELECT a.attname
 0479                      FROM pg_class c, pg_attribute a
 0480                      WHERE c.relname = '{$table}'
 0481                          AND a.attnum > 0
 0482                          AND a.attrelid = c.oid";
 0483                  $result = $this->db->sql_query($sql);
 0484                  while ($row = $this->db->sql_fetchrow($result))
 0485                  {
 0486                      // lower case just in case
 0487                      if (strtolower($row['attname']) == $column_name)
 0488                      {
 0489                          $this->db->sql_freeresult($result);
 0490                          return true;
 0491                      }
 0492                  }
 0493                  $this->db->sql_freeresult($result);
 0494   
 0495                  return false;
 0496              break;
 0497   
 0498              // same deal with PostgreSQL, we must perform more complex operations than
 0499              // we technically could
 0500              case 'mssql':
 0501                  $sql = "SELECT c.name
 0502                      FROM syscolumns c
 0503                      LEFT JOIN sysobjects o ON c.id = o.id
 0504                      WHERE o.name = '{$table}'";
 0505                  $result = $this->db->sql_query($sql);
 0506                  while ($row = $this->db->sql_fetchrow($result))
 0507                  {
 0508                      // lower case just in case
 0509                      if (strtolower($row['name']) == $column_name)
 0510                      {
 0511                          $this->db->sql_freeresult($result);
 0512                          return true;
 0513                      }
 0514                  }
 0515                  $this->db->sql_freeresult($result);
 0516                  return false;
 0517              break;
 0518   
 0519              case 'oracle':
 0520                  $sql = "SELECT column_name
 0521                      FROM user_tab_columns
 0522                      WHERE table_name = '{$table}'";
 0523                  $result = $this->db->sql_query($sql);
 0524                  while ($row = $this->db->sql_fetchrow($result))
 0525                  {
 0526                      // lower case just in case
 0527                      if (strtolower($row['column_name']) == $column_name)
 0528                      {
 0529                          $this->db->sql_freeresult($result);
 0530                          return true;
 0531                      }
 0532                  }
 0533                  $this->db->sql_freeresult($result);
 0534                  return false;
 0535              break;
 0536   
 0537              case 'firebird':
 0538                  $sql = "SELECT RDB\$FIELD_NAME as FNAME
 0539                      FROM RDB\$RELATION_FIELDS
 0540                      WHERE RDB\$RELATION_NAME = '{$table}'";
 0541                  $result = $this->db->sql_query($sql);
 0542                  while ($row = $this->db->sql_fetchrow($result))
 0543                  {
 0544                      // lower case just in case
 0545                      if (strtolower($row['fname']) == $column_name)
 0546                      {
 0547                          $this->db->sql_freeresult($result);
 0548                          return true;
 0549                      }
 0550                  }
 0551                  $this->db->sql_freeresult($result);
 0552                  return false;
 0553              break;
 0554   
 0555              // ugh, SQLite
 0556              case 'sqlite':
 0557                  $sql = "SELECT sql
 0558                      FROM sqlite_master
 0559                      WHERE type = 'table'
 0560                          AND name = '{$table}'";
 0561                  $result = $this->db->sql_query($sql);
 0562   
 0563                  if (!$result)
 0564                  {
 0565                      return false;
 0566                  }
 0567   
 0568                  $row = $this->db->sql_fetchrow($result);
 0569                  $this->db->sql_freeresult($result);
 0570   
 0571                  preg_match('#\((.*)\)#s', $row['sql'], $matches);
 0572   
 0573                  $cols = trim($matches[1]);
 0574                  $col_array = preg_split('/,(?![\s\w]+\))/m', $cols);
 0575   
 0576                  foreach ($col_array as $declaration)
 0577                  {
 0578                      $entities = preg_split('#\s+#', trim($declaration));
 0579                      if ($entities[0] == 'PRIMARY')
 0580                      {
 0581                          continue;
 0582                      }
 0583   
 0584                      if (strtolower($entities[0]) == $column_name)
 0585                      {
 0586                          return true;
 0587                      }
 0588                  }
 0589                  return false;
 0590              break;
 0591          }
 0592      }
 0593   
 0594      /**
 0595      * Private method for performing sql statements (either execute them or return them)
 0596      * @private
 0597      */
 0598      function _sql_run_sql($statements)
 0599      {
 0600          if ($this->return_statements)
 0601          {
 0602              return $statements;
 0603          }
 0604   
 0605          // We could add error handling here...
 0606          foreach ($statements as $sql)
 0607          {
 0608              if ($sql === 'begin')
 0609              {
 0610                  $this->db->sql_transaction('begin');
 0611              }
 0612              else if ($sql === 'commit')
 0613              {
 0614                  $this->db->sql_transaction('commit');
 0615              }
 0616              else
 0617              {
 0618                  $this->db->sql_query($sql);
 0619              }
 0620          }
 0621   
 0622          return true;
 0623      }
 0624   
 0625      /**
 0626      * Function to prepare some column information for better usage
 0627      * @private
 0628      */
 0629      function sql_prepare_column_data($table_name, $column_name, $column_data)
 0630      {
 0631          // Get type
 0632          if (strpos($column_data[0], ':') !== false)
 0633          {
 0634              list($orig_column_type, $column_length) = explode(':', $column_data[0]);
 0635   
 0636              if (!is_array($this->dbms_type_map[$this->sql_layer][$orig_column_type . ':']))
 0637              {
 0638                  $column_type = sprintf($this->dbms_type_map[$this->sql_layer][$orig_column_type . ':'], $column_length);
 0639              }
 0640              else
 0641              {
 0642                  if (isset($this->dbms_type_map[$this->sql_layer][$orig_column_type . ':']['rule']))
 0643                  {
 0644                      switch ($this->dbms_type_map[$this->sql_layer][$orig_column_type . ':']['rule'][0])
 0645                      {
 0646                          case 'div':
 0647                              $column_length /= $this->dbms_type_map[$this->sql_layer][$orig_column_type . ':']['rule'][1];
 0648                              $column_length = ceil($column_length);
 0649                              $column_type = sprintf($this->dbms_type_map[$this->sql_layer][$orig_column_type . ':'][0], $column_length);
 0650                          break;
 0651                      }
 0652                  }
 0653   
 0654                  if (isset($this->dbms_type_map[$this->sql_layer][$orig_column_type . ':']['limit']))
 0655                  {
 0656                      switch ($this->dbms_type_map[$this->sql_layer][$orig_column_type . ':']['limit'][0])
 0657                      {
 0658                          case 'mult':
 0659                              $column_length *= $this->dbms_type_map[$this->sql_layer][$orig_column_type . ':']['limit'][1];
 0660                              if ($column_length > $this->dbms_type_map[$this->sql_layer][$orig_column_type . ':']['limit'][2])
 0661                              {
 0662                                  $column_type = $this->dbms_type_map[$this->sql_layer][$orig_column_type . ':']['limit'][3];
 0663                              }
 0664                              else
 0665                              {
 0666                                  $column_type = sprintf($this->dbms_type_map[$this->sql_layer][$orig_column_type . ':'][0], $column_length);
 0667                              }
 0668                          break;
 0669                      }
 0670                  }
 0671              }
 0672              $orig_column_type .= ':';
 0673          }
 0674          else
 0675          {
 0676              $orig_column_type = $column_data[0];
 0677              $column_type = $this->dbms_type_map[$this->sql_layer][$column_data[0]];
 0678          }
 0679   
 0680          // Adjust default value if db-dependant specified
 0681          if (is_array($column_data[1]))
 0682          {
 0683              $column_data[1] = (isset($column_data[1][$this->sql_layer])) ? $column_data[1][$this->sql_layer] : $column_data[1]['default'];
 0684          }
 0685   
 0686          $sql = '';
 0687   
 0688          $return_array = array();
 0689   
 0690          switch ($this->sql_layer)
 0691          {
 0692              case 'firebird':
 0693                  $sql .= " {$column_type} ";
 0694   
 0695                  if (!is_null($column_data[1]))
 0696                  {
 0697                      $sql .= 'DEFAULT ' . ((is_numeric($column_data[1])) ? $column_data[1] : "'{$column_data[1]}'") . ' ';
 0698                  }
 0699   
 0700                  $sql .= 'NOT NULL';
 0701   
 0702                  // This is a UNICODE column and thus should be given it's fair share
 0703                  if (preg_match('/^X?STEXT_UNI|VCHAR_(CI|UNI:?)/', $column_data[0]))
 0704                  {
 0705                      $sql .= ' COLLATE UNICODE';
 0706                  }
 0707   
 0708              break;
 0709   
 0710              case 'mssql':
 0711                  $sql .= " {$column_type} ";
 0712                  $sql_default = " {$column_type} ";
 0713   
 0714                  // For adding columns we need the default definition
 0715                  if (!is_null($column_data[1]))
 0716                  {
 0717                      // For hexadecimal values do not use single quotes
 0718                      if (strpos($column_data[1], '0x') === 0)
 0719                      {
 0720                          $sql_default .= 'DEFAULT (' . $column_data[1] . ') ';
 0721                      }
 0722                      else
 0723                      {
 0724                          $sql_default .= 'DEFAULT (' . ((is_numeric($column_data[1])) ? $column_data[1] : "'{$column_data[1]}'") . ') ';
 0725                      }
 0726                  }
 0727   
 0728                  $sql .= 'NOT NULL';
 0729                  $sql_default .= 'NOT NULL';
 0730   
 0731                  $return_array['column_type_sql_default'] = $sql_default;
 0732              break;
 0733   
 0734              case 'mysql_40':
 0735              case 'mysql_41':
 0736                  $sql .= " {$column_type} ";
 0737   
 0738                  // For hexadecimal values do not use single quotes
 0739                  if (!is_null($column_data[1]) && substr($column_type, -4) !== 'text' && substr($column_type, -4) !== 'blob')
 0740                  {
 0741                      $sql .= (strpos($column_data[1], '0x') === 0) ? "DEFAULT {$column_data[1]} " : "DEFAULT '{$column_data[1]}' ";
 0742                  }
 0743                  $sql .= 'NOT NULL';
 0744   
 0745                  if (isset($column_data[2]))
 0746                  {
 0747                      if ($column_data[2] == 'auto_increment')
 0748                      {
 0749                          $sql .= ' auto_increment';
 0750                      }
 0751                      else if ($this->sql_layer === 'mysql_41' && $column_data[2] == 'true_sort')
 0752                      {
 0753                          $sql .= ' COLLATE utf8_unicode_ci';
 0754                      }
 0755                  }
 0756   
 0757              break;
 0758   
 0759              case 'oracle':
 0760                  $sql .= " {$column_type} ";
 0761                  $sql .= (!is_null($column_data[1])) ? "DEFAULT '{$column_data[1]}' " : '';
 0762   
 0763                  // In Oracle empty strings ('') are treated as NULL.
 0764                  // Therefore in oracle we allow NULL's for all DEFAULT '' entries
 0765                  // Oracle does not like setting NOT NULL on a column that is already NOT NULL (this happens only on number fields)
 0766                  if (preg_match('/number/i', $column_type))
 0767                  {
 0768                      $sql .= ($column_data[1] === '') ? '' : 'NOT NULL';
 0769                  }
 0770              break;
 0771   
 0772              case 'postgres':
 0773                  $return_array['column_type'] = $column_type;
 0774   
 0775                  $sql .= " {$column_type} ";
 0776   
 0777                  if (isset($column_data[2]) && $column_data[2] == 'auto_increment')
 0778                  {
 0779                      $default_val = "nextval('{$table_name}_seq')";
 0780                  }
 0781                  else if (!is_null($column_data[1]))
 0782                  {
 0783                      $default_val = "'" . $column_data[1] . "'";
 0784                      $return_array['null'] = 'NOT NULL';
 0785                      $sql .= 'NOT NULL ';
 0786                  }
 0787   
 0788                  $return_array['default'] = $default_val;
 0789   
 0790                  $sql .= "DEFAULT {$default_val}";
 0791   
 0792                  // Unsigned? Then add a CHECK contraint
 0793                  if (in_array($orig_column_type, $this->unsigned_types))
 0794                  {
 0795                      $return_array['constraint'] = "CHECK ({$column_name} >= 0)";
 0796                      $sql .= " CHECK ({$column_name} >= 0)";
 0797                  }
 0798              break;
 0799   
 0800              case 'sqlite':
 0801                  if (isset($column_data[2]) && $column_data[2] == 'auto_increment')
 0802                  {
 0803                      $sql .= ' INTEGER PRIMARY KEY';
 0804                  }
 0805                  else
 0806                  {
 0807                      $sql .= ' ' . $column_type;
 0808                  }
 0809   
 0810                  $sql .= ' NOT NULL ';
 0811                  $sql .= (!is_null($column_data[1])) ? "DEFAULT '{$column_data[1]}'" : '';
 0812              break;
 0813          }
 0814   
 0815          $return_array['column_type_sql'] = $sql;
 0816   
 0817          return $return_array;
 0818      }
 0819   
 0820      /**
 0821      * Add new column
 0822      */
 0823      function sql_column_add($table_name, $column_name, $column_data)
 0824      {
 0825          $column_data = $this->sql_prepare_column_data($table_name, $column_name, $column_data);
 0826          $statements = array();
 0827   
 0828          switch ($this->sql_layer)
 0829          {
 0830              case 'firebird':
 0831                  $statements[] = 'ALTER TABLE "' . $table_name . '" ADD "' . $column_name . '" ' . $column_data['column_type_sql'];
 0832              break;
 0833   
 0834              case 'mssql':
 0835                  $statements[] = 'ALTER TABLE [' . $table_name . '] ADD [' . $column_name . '] ' . $column_data['column_type_sql_default'];
 0836              break;
 0837   
 0838              case 'mysql_40':
 0839              case 'mysql_41':
 0840                  $statements[] = 'ALTER TABLE `' . $table_name . '` ADD COLUMN `' . $column_name . '` ' . $column_data['column_type_sql'];
 0841              break;
 0842   
 0843              case 'oracle':
 0844                  $statements[] = 'ALTER TABLE ' . $table_name . ' ADD ' . $column_name . ' ' . $column_data['column_type_sql'];
 0845              break;
 0846   
 0847              case 'postgres':
 0848                  $statements[] = 'ALTER TABLE ' . $table_name . ' ADD COLUMN "' . $column_name . '" ' . $column_data['column_type_sql'];
 0849              break;
 0850   
 0851              case 'sqlite':
 0852                  if (version_compare(sqlite_libversion(), '3.0') == -1)
 0853                  {
 0854                      $sql = "SELECT sql
 0855                          FROM sqlite_master
 0856                          WHERE type = 'table'
 0857                              AND name = '{$table_name}'
 0858                          ORDER BY type DESC, name;";
 0859                      $result = $this->db->sql_query($sql);
 0860   
 0861                      if (!$result)
 0862                      {
 0863                          break;
 0864                      }
 0865   
 0866                      $row = $this->db->sql_fetchrow($result);
 0867                      $this->db->sql_freeresult($result);
 0868   
 0869                      $statements[] = 'begin';
 0870   
 0871                      // Create a backup table and populate it, destroy the existing one
 0872                      $statements[] = preg_replace('#CREATE\s+TABLE\s+"?' . $table_name . '"?#i', 'CREATE TEMPORARY TABLE ' . $table_name . '_temp', $row['sql']);
 0873                      $statements[] = 'INSERT INTO ' . $table_name . '_temp SELECT * FROM ' . $table_name;
 0874                      $statements[] = 'DROP TABLE ' . $table_name;
 0875   
 0876                      preg_match('#\((.*)\)#s', $row['sql'], $matches);
 0877   
 0878                      $new_table_cols = trim($matches[1]);
 0879                      $old_table_cols = preg_split('/,(?![\s\w]+\))/m', $new_table_cols);
 0880                      $column_list = array();
 0881   
 0882                      foreach ($old_table_cols as $declaration)
 0883                      {
 0884                          $entities = preg_split('#\s+#', trim($declaration));
 0885                          if ($entities[0] == 'PRIMARY')
 0886                          {
 0887                              continue;
 0888                          }
 0889                          $column_list[] = $entities[0];
 0890                      }
 0891   
 0892                      $columns = implode(',', $column_list);
 0893   
 0894                      $new_table_cols = $column_name . ' ' . $column_data['column_type_sql'] . ',' . $new_table_cols;
 0895   
 0896                      // create a new table and fill it up. destroy the temp one
 0897                      $statements[] = 'CREATE TABLE ' . $table_name . ' (' . $new_table_cols . ');';
 0898                      $statements[] = 'INSERT INTO ' . $table_name . ' (' . $columns . ') SELECT ' . $columns . ' FROM ' . $table_name . '_temp;';
 0899                      $statements[] = 'DROP TABLE ' . $table_name . '_temp';
 0900   
 0901                      $statements[] = 'commit';
 0902                  }
 0903                  else
 0904                  {
 0905                      $statements[] = 'ALTER TABLE ' . $table_name . ' ADD ' . $column_name . ' [' . $column_data['column_type_sql'] . ']';
 0906                  }
 0907              break;
 0908          }
 0909   
 0910          return $this->_sql_run_sql($statements);
 0911      }
 0912   
 0913      /**
 0914      * Drop column
 0915      */
 0916      function sql_column_remove($table_name, $column_name)
 0917      {
 0918          $statements = array();
 0919   
 0920          switch ($this->sql_layer)
 0921          {
 0922              case 'firebird':
 0923                  $statements[] = 'ALTER TABLE "' . $table_name . '" DROP "' . $column_name . '"';
 0924              break;
 0925   
 0926              case 'mssql':
 0927                  $statements[] = 'ALTER TABLE [' . $table_name . '] DROP COLUMN [' . $column_name . ']';
 0928              break;
 0929   
 0930              case 'mysql_40':
 0931              case 'mysql_41':
 0932                  $statements[] = 'ALTER TABLE `' . $table_name . '` DROP COLUMN `' . $column_name . '`';
 0933              break;
 0934   
 0935              case 'oracle':
 0936                  $statements[] = 'ALTER TABLE ' . $table_name . ' DROP ' . $column_name;
 0937              break;
 0938   
 0939              case 'postgres':
 0940                  $statements[] = 'ALTER TABLE ' . $table_name . ' DROP COLUMN "' . $column_name . '"';
 0941              break;
 0942   
 0943              case 'sqlite':
 0944                  if (version_compare(sqlite_libversion(), '3.0') == -1)
 0945                  {
 0946                      $sql = "SELECT sql
 0947                          FROM sqlite_master
 0948                          WHERE type = 'table'
 0949                              AND name = '{$table_name}'
 0950                          ORDER BY type DESC, name;";
 0951                      $result = $this->db->sql_query($sql);
 0952   
 0953                      if (!$result)
 0954                      {
 0955                          break;
 0956                      }
 0957   
 0958                      $row = $this->db->sql_fetchrow($result);
 0959                      $this->db->sql_freeresult($result);
 0960   
 0961                      $statements[] = 'begin';
 0962   
 0963                      // Create a backup table and populate it, destroy the existing one
 0964                      $statements[] = preg_replace('#CREATE\s+TABLE\s+"?' . $table_name . '"?#i', 'CREATE TEMPORARY TABLE ' . $table_name . '_temp', $row['sql']);
 0965                      $statements[] = 'INSERT INTO ' . $table_name . '_temp SELECT * FROM ' . $table_name;
 0966                      $statements[] = 'DROP TABLE ' . $table_name;
 0967   
 0968                      preg_match('#\((.*)\)#s', $row['sql'], $matches);
 0969   
 0970                      $new_table_cols = trim($matches[1]);
 0971                      $old_table_cols = preg_split('/,(?![\s\w]+\))/m', $new_table_cols);
 0972                      $column_list = array();
 0973   
 0974                      foreach ($old_table_cols as $declaration)
 0975                      {
 0976                          $entities = preg_split('#\s+#', trim($declaration));
 0977                          if ($entities[0] == 'PRIMARY' || $entities[0] === $column_name)
 0978                          {
 0979                              continue;
 0980                          }
 0981                          $column_list[] = $entities[0];
 0982                      }
 0983   
 0984                      $columns = implode(',', $column_list);
 0985   
 0986                      $new_table_cols = $new_table_cols = preg_replace('/' . $column_name . '[^,]+(?:,|$)/m', '', $new_table_cols);
 0987   
 0988                      // create a new table and fill it up. destroy the temp one
 0989                      $statements[] = 'CREATE TABLE ' . $table_name . ' (' . $new_table_cols . ');';
 0990                      $statements[] = 'INSERT INTO ' . $table_name . ' (' . $columns . ') SELECT ' . $columns . ' FROM ' . $table_name . '_temp;';
 0991                      $statements[] = 'DROP TABLE ' . $table_name . '_temp';
 0992   
 0993                      $statements[] = 'commit';
 0994                  }
 0995                  else
 0996                  {
 0997                      $statements[] = 'ALTER TABLE ' . $table_name . ' DROP COLUMN ' . $column_name;
 0998                  }
 0999              break;
 1000          }
 1001   
 1002          return $this->_sql_run_sql($statements);
 1003      }
 1004   
 1005      /**
 1006      * Drop Index
 1007      */
 1008      function sql_index_drop($table_name, $index_name)
 1009      {
 1010          $statements = array();
 1011   
 1012          switch ($this->sql_layer)
 1013          {
 1014              case 'mssql':
 1015                  $statements[] = 'DROP INDEX ' . $table_name . '.' . $index_name;
 1016              break;
 1017   
 1018              case 'mysql_40':
 1019              case 'mysql_41':
 1020                  $statements[] = 'DROP INDEX ' . $index_name . ' ON ' . $table_name;
 1021              break;
 1022   
 1023              case 'firebird':
 1024              case 'oracle':
 1025              case 'postgres':
 1026              case 'sqlite':
 1027                  $statements[] = 'DROP INDEX ' . $table_name . '_' . $index_name;
 1028              break;
 1029          }
 1030   
 1031          return $this->_sql_run_sql($statements);
 1032      }
 1033   
 1034      /**
 1035      * Add primary key
 1036      */
 1037      function sql_create_primary_key($table_name, $column)
 1038      {
 1039          $statements = array();
 1040   
 1041          switch ($this->sql_layer)
 1042          {
 1043              case 'firebird':
 1044              case 'postgres':
 1045                  $statements[] = 'ALTER TABLE ' . $table_name . ' ADD PRIMARY KEY (' . implode(', ', $column) . ')';
 1046              break;
 1047   
 1048              case 'mssql':
 1049                  $sql = "ALTER TABLE [{$table_name}] WITH NOCHECK ADD ";
 1050                  $sql .= "CONSTRAINT [PK_{$table_name}] PRIMARY KEY  CLUSTERED (";
 1051                  $sql .= '[' . implode("],\n\t\t[", $column) . ']';
 1052                  $sql .= ') ON [PRIMARY]';
 1053   
 1054                  $statements[] = $sql;
 1055              break;
 1056   
 1057              case 'mysql_40':
 1058              case 'mysql_41':
 1059                  $statements[] = 'ALTER TABLE ' . $table_name . ' ADD PRIMARY KEY (' . implode(', ', $column) . ')';
 1060              break;
 1061   
 1062              case 'oracle':
 1063                  $statements[] = 'ALTER TABLE ' . $table_name . 'add CONSTRAINT pk_' . $table_name . ' PRIMARY KEY (' . implode(', ', $column) . ')';
 1064              break;
 1065   
 1066              case 'sqlite':
 1067                  $sql = "SELECT sql
 1068                      FROM sqlite_master
 1069                      WHERE type = 'table'
 1070                          AND name = '{$table_name}'
 1071                      ORDER BY type DESC, name;";
 1072                  $result = $this->db->sql_query($sql);
 1073   
 1074                  if (!$result)
 1075                  {
 1076                      break;
 1077                  }
 1078   
 1079                  $row = $this->db->sql_fetchrow($result);
 1080                  $this->db->sql_freeresult($result);
 1081   
 1082                  $statements[] = 'begin';
 1083   
 1084                  // Create a backup table and populate it, destroy the existing one
 1085                  $statements[] = preg_replace('#CREATE\s+TABLE\s+"?' . $table_name . '"?#i', 'CREATE TEMPORARY TABLE ' . $table_name . '_temp', $row['sql']);
 1086                  $statements[] = 'INSERT INTO ' . $table_name . '_temp SELECT * FROM ' . $table_name;
 1087                  $statements[] = 'DROP TABLE ' . $table_name;
 1088   
 1089                  preg_match('#\((.*)\)#s', $row['sql'], $matches);
 1090   
 1091                  $new_table_cols = trim($matches[1]);
 1092                  $old_table_cols = preg_split('/,(?![\s\w]+\))/m', $new_table_cols);
 1093                  $column_list = array();
 1094   
 1095                  foreach ($old_table_cols as $declaration)
 1096                  {
 1097                      $entities = preg_split('#\s+#', trim($declaration));
 1098                      if ($entities[0] == 'PRIMARY')
 1099                      {
 1100                          continue;
 1101                      }
 1102                      $column_list[] = $entities[0];
 1103                  }
 1104   
 1105                  $columns = implode(',', $column_list);
 1106   
 1107                  // create a new table and fill it up. destroy the temp one
 1108                  $statements[] = 'CREATE TABLE ' . $table_name . ' (' . $new_table_cols . ', PRIMARY KEY (' . implode(', ', $column) . '));';
 1109                  $statements[] = 'INSERT INTO ' . $table_name . ' (' . $columns . ') SELECT ' . $columns . ' FROM ' . $table_name . '_temp;';
 1110                  $statements[] = 'DROP TABLE ' . $table_name . '_temp';
 1111   
 1112                  $statements[] = 'commit';
 1113              break;
 1114          }
 1115   
 1116          return $this->_sql_run_sql($statements);
 1117      }
 1118   
 1119      /**
 1120      * Add unique index
 1121      */
 1122      function sql_create_unique_index($table_name, $index_name, $column)
 1123      {
 1124          $statements = array();
 1125   
 1126          switch ($this->sql_layer)
 1127          {
 1128              case 'firebird':
 1129              case 'postgres':
 1130              case 'oracle':
 1131              case 'sqlite':
 1132                  $statements[] = 'CREATE UNIQUE INDEX ' . $table_name . '_' . $index_name . ' ON ' . $table_name . '(' . implode(', ', $column) . ')';
 1133              break;
 1134   
 1135              case 'mysql_40':
 1136              case 'mysql_41':
 1137                  $statements[] = 'CREATE UNIQUE INDEX ' . $index_name . ' ON ' . $table_name . '(' . implode(', ', $column) . ')';
 1138              break;
 1139   
 1140              case 'mssql':
 1141                  $statements[] = 'CREATE UNIQUE INDEX ' . $index_name . ' ON ' . $table_name . '(' . implode(', ', $column) . ') ON [PRIMARY]';
 1142              break;
 1143          }
 1144   
 1145          return $this->_sql_run_sql($statements);
 1146      }
 1147   
 1148      /**
 1149      * Add index
 1150      */
 1151      function sql_create_index($table_name, $index_name, $column)
 1152      {
 1153          $statements = array();
 1154   
 1155          switch ($this->sql_layer)
 1156          {
 1157              case 'firebird':
 1158              case 'postgres':
 1159              case 'oracle':
 1160              case 'sqlite':
 1161                  $statements[] = 'CREATE INDEX ' . $table_name . '_' . $index_name . ' ON ' . $table_name . '(' . implode(', ', $column) . ')';
 1162              break;
 1163   
 1164              case 'mysql_40':
 1165              case 'mysql_41':
 1166                  $statements[] = 'CREATE INDEX ' . $index_name . ' ON ' . $table_name . '(' . implode(', ', $column) . ')';
 1167              break;
 1168   
 1169              case 'mssql':
 1170                  $statements[] = 'CREATE INDEX ' . $index_name . ' ON ' . $table_name . '(' . implode(', ', $column) . ') ON [PRIMARY]';
 1171              break;
 1172          }
 1173   
 1174          return $this->_sql_run_sql($statements);
 1175      }
 1176   
 1177      /**
 1178      * List all of the indices that belong to a table,
 1179      * does not count:
 1180      * * UNIQUE indices
 1181      * * PRIMARY keys
 1182      */
 1183      function sql_list_index($table_name)
 1184      {
 1185          $index_array = array();
 1186   
 1187          if ($this->sql_layer == 'mssql')
 1188          {
 1189              $sql = "EXEC sp_statistics '$table_name'";
 1190              $result = $this->db->sql_query($sql);
 1191              while ($row = $this->db->sql_fetchrow($result))
 1192              {
 1193                  if ($row['TYPE'] == 3)
 1194                  {
 1195                      $index_array[] = $row['INDEX_NAME'];
 1196                  }
 1197              }
 1198              $this->db->sql_freeresult($result);
 1199          }
 1200          else
 1201          {
 1202              switch ($this->sql_layer)
 1203              {
 1204                  case 'firebird':
 1205                      $sql = "SELECT LOWER(RDB\$INDEX_NAME) as index_name
 1206                          FROM RDB\$INDICES
 1207                          WHERE RDB\$RELATION_NAME = " . strtoupper($table_name) . "
 1208                              AND RDB\$UNIQUE_FLAG IS NULL
 1209                              AND RDB\$FOREIGN_KEY IS NULL";
 1210                      $col = 'index_name';
 1211                  break;
 1212   
 1213                  case 'postgres':
 1214                      $sql = "SELECT ic.relname as index_name
 1215                          FROM pg_class bc, pg_class ic, pg_index i
 1216                          WHERE (bc.oid = i.indrelid)
 1217                              AND (ic.oid = i.indexrelid)
 1218                              AND (bc.relname = '" . $table_name . "')
 1219                              AND (i.indisunique != 't')
 1220                              AND (i.indisprimary != 't')";
 1221                      $col = 'index_name';
 1222                  break;
 1223   
 1224                  case 'mysql_40':
 1225                  case 'mysql_41':
 1226                      $sql = 'SHOW KEYS
 1227                          FROM ' . $table_name;
 1228                      $col = 'Key_name';
 1229                  break;
 1230   
 1231                  case 'oracle':
 1232                      $sql = "SELECT index_name
 1233                          FROM user_indexes
 1234                          WHERE table_name = '" . $table_name . "'
 1235                              AND generated = 'N'";
 1236                  break;
 1237   
 1238                  case 'sqlite':
 1239                      $sql = "PRAGMA index_info('" . $table_name . "');";
 1240                      $col = 'name';
 1241                  break;
 1242              }
 1243   
 1244              $result = $this->db->sql_query($sql);
 1245              while ($row = $this->db->sql_fetchrow($result))
 1246              {
 1247                  if (($this->sql_layer == 'mysql_40' || $this->sql_layer == 'mysql_41') && !$row['Non_unique'])
 1248                  {
 1249                      continue;
 1250                  }
 1251   
 1252                  switch ($this->sql_layer)
 1253                  {
 1254                      case 'firebird':
 1255                      case 'oracle':
 1256                      case 'postgres':
 1257                      case 'sqlite':
 1258                          $row[$col] = substr($row[$col], strlen($table_name) + 1);
 1259                      break;
 1260                  }
 1261   
 1262                  $index_array[] = $row[$col];
 1263              }
 1264              $this->db->sql_freeresult($result);
 1265          }
 1266   
 1267          return array_map('strtolower', $index_array);
 1268      }
 1269   
 1270      /**
 1271      * Change column type (not name!)
 1272      */
 1273      function sql_column_change($table_name, $column_name, $column_data)
 1274      {
 1275          $column_data = $this->sql_prepare_column_data($table_name, $column_name, $column_data);
 1276          $statements = array();
 1277   
 1278          switch ($this->sql_layer)
 1279          {
 1280              case 'firebird':
 1281                  // Change type...
 1282                  $statements[] = 'ALTER TABLE "' . $table_name . '" ALTER COLUMN "' . $column_name . '" TYPE ' . ' ' . $column_data['column_type_sql'];
 1283              break;
 1284   
 1285              case 'mssql':
 1286                  $statements[] = 'ALTER TABLE [' . $table_name . '] ALTER COLUMN [' . $column_name . '] ' . $column_data['column_type_sql'];
 1287              break;
 1288   
 1289              case 'mysql_40':
 1290              case 'mysql_41':
 1291                  $statements[] = 'ALTER TABLE `' . $table_name . '` CHANGE `' . $column_name . '` `' . $column_name . '` ' . $column_data['column_type_sql'];
 1292              break;
 1293   
 1294              case 'oracle':
 1295                  $statements[] = 'ALTER TABLE ' . $table_name . ' MODIFY ' . $column_name . ' ' . $column_data['column_type_sql'];
 1296              break;
 1297   
 1298              case 'postgres':
 1299                  $sql = 'ALTER TABLE ' . $table_name . ' ';
 1300   
 1301                  $sql_array = array();
 1302                  $sql_array[] = 'ALTER COLUMN ' . $column_name . ' TYPE ' . $column_data['column_type'];
 1303   
 1304                  if (isset($column_data['null']))
 1305                  {
 1306                      if ($column_data['null'] == 'NOT NULL')
 1307                      {
 1308                          $sql_array[] = 'ALTER COLUMN ' . $column_name . ' SET NOT NULL';
 1309                      }
 1310                      else if ($column_data['null'] == 'NULL')
 1311                      {
 1312                          $sql_array[] = 'ALTER COLUMN ' . $column_name . ' DROP NOT NULL';
 1313                      }
 1314                  }
 1315   
 1316                  if (isset($column_data['default']))
 1317                  {
 1318                      $sql_array[] = 'ALTER COLUMN ' . $column_name . ' SET DEFAULT ' . $column_data['default'];
 1319                  }
 1320   
 1321                  // we don't want to double up on constraints if we change different number data types
 1322                  if (isset($column_data['constraint']))
 1323                  {
 1324                      $constraint_sql = "SELECT consrc as constraint_data
 1325                                  FROM pg_constraint, pg_class bc
 1326                                  WHERE conrelid = bc.oid
 1327                                      AND bc.relname = '{$table_name}'
 1328                                      AND NOT EXISTS (
 1329                                          SELECT *
 1330                                              FROM pg_constraint as c, pg_inherits as i
 1331                                              WHERE i.inhrelid = pg_constraint.conrelid
 1332                                                  AND c.conname = pg_constraint.conname
 1333                                                  AND c.consrc = pg_constraint.consrc
 1334                                                  AND c.conrelid = i.inhparent
 1335                                      )";
 1336   
 1337                      $constraint_exists = false;
 1338   
 1339                      $result = $this->db->sql_query($constraint_sql);
 1340                      while ($row = $this->db->sql_fetchrow($result))
 1341                      {
 1342                          if (trim($row['constraint_data']) == trim($column_data['constraint']))
 1343                          {
 1344                              $constraint_exists = true;
 1345                              break;
 1346                          }
 1347                      }
 1348                      $this->db->sql_freeresult($result);
 1349   
 1350                      if (!$constraint_exists)
 1351                      {
 1352                          $sql_array[] = 'ADD ' . $column_data['constraint'];
 1353                      }
 1354                  }
 1355   
 1356                  $sql .= implode(', ', $sql_array);
 1357   
 1358                  $statements[] = $sql;
 1359              break;
 1360   
 1361              case 'sqlite':
 1362   
 1363                  $sql = "SELECT sql
 1364                      FROM sqlite_master
 1365                      WHERE type = 'table'
 1366                          AND name = '{$table_name}'
 1367                      ORDER BY type DESC, name;";
 1368                  $result = $this->db->sql_query($sql);
 1369   
 1370                  if (!$result)
 1371                  {
 1372                      break;
 1373                  }
 1374   
 1375                  $row = $this->db->sql_fetchrow($result);
 1376                  $this->db->sql_freeresult($result);
 1377   
 1378                  $statements[] = 'begin';
 1379   
 1380                  // Create a temp table and populate it, destroy the existing one
 1381                  $statements[] = preg_replace('#CREATE\s+TABLE\s+"?' . $table_name . '"?#i', 'CREATE TEMPORARY TABLE ' . $table_name . '_temp', $row['sql']);
 1382                  $statements[] = 'INSERT INTO ' . $table_name . '_temp SELECT * FROM ' . $table_name;
 1383                  $statements[] = 'DROP TABLE ' . $table_name;
 1384   
 1385                  preg_match('#\((.*)\)#s', $row['sql'], $matches);
 1386   
 1387                  $new_table_cols = trim($matches[1]);
 1388                  $old_table_cols = preg_split('/,(?![\s\w]+\))/m', $new_table_cols);
 1389                  $column_list = array();
 1390   
 1391                  foreach ($old_table_cols as $key => $declaration)
 1392                  {
 1393                      $entities = preg_split('#\s+#', trim($declaration));
 1394                      $column_list[] = $entities[0];
 1395                      if ($entities[0] == $column_name)
 1396                      {
 1397                          $old_table_cols[$key] = $column_name . ' ' . $column_data['column_type_sql'];
 1398                      }
 1399                  }
 1400   
 1401                  $columns = implode(',', $column_list);
 1402   
 1403                  // create a new table and fill it up. destroy the temp one
 1404                  $statements[] = 'CREATE TABLE ' . $table_name . ' (' . implode(',', $old_table_cols) . ');';
 1405                  $statements[] = 'INSERT INTO ' . $table_name . ' (' . $columns . ') SELECT ' . $columns . ' FROM ' . $table_name . '_temp;';
 1406                  $statements[] = 'DROP TABLE ' . $table_name . '_temp';
 1407   
 1408                  $statements[] = 'commit';
 1409   
 1410              break;
 1411          }
 1412   
 1413          return $this->_sql_run_sql($statements);
 1414      }
 1415  }
 1416   
 1417  ?>