]> git.mjollnir.org Git - moodle.git/commitdiff
MDL-15181 temp table support in ddl/dml
authorskodak <skodak>
Sat, 7 Jun 2008 14:41:01 +0000 (14:41 +0000)
committerskodak <skodak>
Sat, 7 Jun 2008 14:41:01 +0000 (14:41 +0000)
lib/ddl/database_manager.php
lib/ddl/mssql_sql_generator.php
lib/ddl/mysql_sql_generator.php
lib/ddl/oracle_sql_generator.php
lib/ddl/simpletest/testddllib.php
lib/ddl/sql_generator.php
lib/dml/moodle_database.php
lib/dml/mssql_adodb_moodle_database.php

index 1b2d140be747ea9566249a289952d02269fbc679..6382f41bfcc5e2dd356a1c693f629ee65547a9e7 100644 (file)
@@ -102,27 +102,11 @@ class database_manager {
      * Given one xmldb_table, check if it exists in DB (true/false)
      *
      * @param mixed the table to be searched (string name or xmldb_table instance)
+     * @param bool temp table (might need different checks)
      * @return boolean true/false
      */
-    public function table_exists($table) {
-    /// Do this function silenty (to avoid output in install/upgrade process)
-        $olddbdebug = $this->mdb->get_debug();
-        $this->mdb->set_debug(false);
-
-        if (is_string($table)) {
-            $tablename = $table;
-        } else {
-        /// Calculate the name of the table
-            $tablename = $table->getName();
-        }
-
-    /// get all tables in moodle database
-        $tables = $this->mdb->get_tables();
-        $exists = in_array($tablename, $tables);
-    /// Re-set original debug
-        $this->mdb->set_debug($olddbdebug);
-
-        return $exists;
+    public function table_exists($table, $temptable=false) {
+        return $this->generator->table_exists($table, $temptable);
     }
 
     /**
@@ -523,37 +507,33 @@ class database_manager {
      * This function will create the temporary table passed as argument with all its
      * fields/keys/indexes/sequences, everything based in the XMLDB object
      *
-     * TRUNCATE the table immediately after creation. A previous process using
-     * the same persistent connection may have created the temp table and failed to
-     * drop it. In that case, the table will exist, and create_temp_table() will
-     * will succeed.
-     *
-     * NOTE: The return value is the tablename - some DBs (MSSQL at least) use special
-     * names for temp tables.
-     *
-     * @TODO There is no way to know, from the return value alone, whether a table was actually created
-     *       or not: if an existing table is given as param, its name will be returned, but no DB action
-     *       will have occurred. This should be remedied using an Exception
+     * If table already exists it will be dropped and recreated, please make sure
+     * the table name does not collide with existing normal table!
      *
      * @param xmldb_table table object (full specs are required)
      * @param boolean continue to specify if must continue on error (true) or stop (false)
      * @param boolean feedback to specify to show status info (true) or not (false)
      * @return string tablename on success, false on error
      */
-    function create_temp_table($xmldb_table, $continue=true, $feedback=true) {
+    public function create_temp_table($xmldb_table, $continue=true, $feedback=true) {
         if (!($xmldb_table instanceof xmldb_table)) {
             debugging('Incorrect create_table() $xmldb_table parameter');
             return false;
         }
 
+    /// hack for mssql - it requires names to start with #
+        $xmldb_table = $this->generator->tweakTempTable($xmldb_table);
+
     /// Check table doesn't exist
-        if ($this->table_exists($xmldb_table)) {
-            debugging('Table ' . $xmldb_table->getName() .
-                      ' already exists. Create skipped', DEBUG_DEVELOPER);
-            return $xmldb_table->getName(); //Table exists, nothing to do
+        if ($this->table_exists($xmldb_table, true)) {
+            debugging('Temporary table ' . $xmldb_table->getName() .
+                      ' already exists, dropping and recreating it.', DEBUG_DEVELOPER);
+            if (!$this->drop_temp_table($xmldb_table, $continue, $feedback)) {
+                return false;
+            }
         }
 
-        if (!$sqlarr = $this->generator->getCreateTableSQL($xmldb_table)) {
+        if (!$sqlarr = $this->generator->getCreateTempTableSQL($xmldb_table)) {
             return $xmldb_table->getName(); //Empty array = nothing to do = no error
         }
 
@@ -564,6 +544,38 @@ class database_manager {
         }
     }
 
+    /**
+     * This function will drop the temporary table passed as argument with all its
+     * fields/keys/indexes/sequences, everything based in the XMLDB object
+     *
+     * It is recommended to drop temp table when not used anymore.
+     *
+     * @param xmldb_table table object
+     * @param boolean continue to specify if must continue on error (true) or stop (false)
+     * @param boolean feedback to specify to show status info (true) or not (false)
+     * @return string tablename on success, false on error
+     */
+    public function drop_temp_table($xmldb_table, $continue=true, $feedback=true) {
+        if (!($xmldb_table instanceof xmldb_table)) {
+            debugging('Incorrect create_table() $xmldb_table parameter');
+            return false;
+        }
+
+    /// mssql requires names to start with #
+        $xmldb_table = $this->generator->tweakTempTable($xmldb_table);
+
+    /// Check table doesn't exist
+        if (!$this->table_exists($xmldb_table, true)) {
+            return true;
+        }
+
+        if (!$sqlarr = $this->generator->getDropTempTableSQL($xmldb_table)) {
+            return false; // error
+        }
+
+        return $this->execute_sql_arr($sqlarr, $continue, $feedback);
+    }
+
     /**
      * This function will rename the table passed as argument
      * Before renaming the index, the function will check it exists
index 4616240d74332a2e97756ced13b48f4b8bda362c..8a771572981d9436771db4af073d04fae3174cf8 100644 (file)
@@ -78,52 +78,37 @@ class mssql_sql_generator extends sql_generator {
     }
 
     /**
-     * This function will create the temporary table passed as argument with all its
-     * fields/keys/indexes/sequences, everything based in the XMLDB object
-     *
-     * TRUNCATE the table immediately after creation. A previous process using
-     * the same persistent connection may have created the temp table and failed to
-     * drop it. In that case, the table will exist, and create_temp_table() will
-     * will succeed.
-     *
-     * NOTE: The return value is the tablename - some DBs (MSSQL at least) use special
-     * names for temp tables.
-     *
-     * @uses $CFG, $db
-     * @param xmldb_table table object (full specs are required)
-     * @param boolean continue to specify if must continue on error (true) or stop (false)
-     * @param boolean feedback to specify to show status info (true) or not (false)
-     * @return string tablename on success, false on error
+     * Given one correct xmldb_table, returns the SQL statements
+     * to create temporary table (inside one array)
      */
-    function create_temp_table($xmldb_table, $continue=true, $feedback=true) {
-        if (!($xmldb_table instanceof xmldb_table)) {
-            debugging('Incorrect create_table() $xmldb_table parameter');
-            return false;
-        }
-
-    /// Check table doesn't exist
-        if ($this->table_exists($xmldb_table)) {
-            debugging('Table ' . $xmldb_table->getName() .
-                      ' already exists. Create skipped', DEBUG_DEVELOPER);
-            return $xmldb_table->getName(); //Table exists, nothing to do
-        }
-
-        if (!$sqlarr = $this->getCreateTableSQL($xmldb_table)) {
-            return $xmldb_table->getName(); //Empty array = nothing to do = no error
-        }
-
-        // TODO: somehow change the name to have a #
-        /*$temporary = '';
+    public function getCreateTempTableSQL($xmldb_table) {
+        $sqlarr = $this->getCreateTableSQL($xmldb_table);
+        //ugly hack!
+        $this->mdb->temptables[trim($xmldb_table->getName(), '#')] = true;
+        return $sqlarr;
+    }
 
-        if (!empty($temporary)) {
-            $sqlarr = preg_replace('/^CREATE/', "CREATE $temporary", $sqlarr);
-        }*/
+    /**
+     * Given one correct xmldb_table and the new name, returns the SQL statements
+     * to drop it (inside one array)
+     */
+    public function getDropTempTableSQL($xmldb_table) {
+        $sqlarr = $this->getDropTableSQL($xmldb_table);
+        $tablename = $xmldb_table->getName();
+        array_unshift($sqlarr, "TRUNCATE TABLE {".$tablename."}"); // oracle requires truncate before being able to drop a temp table
+        //ugly hack!
+        unset($this->mdb->temptables[trim($xmldb_table->getName(), '#')]);
+        return $sqlarr;
+    }
 
-        if (execute_sql_arr($sqlarr, $continue, $feedback)) {
-            return $xmldb_table->getName();
-        } else {
-            return false;
+    /**
+     * Tweaks the temp table instance - required for mssql # naming
+     */
+    public function tweakTempTable($xmldb_table) {
+        if (strpos($xmldb_table->getName(), '#') !== 0) {
+            $xmldb_table->setName('#'.$xmldb_table->getName()); // MSSQL requires temp table names to start with #
         }
+        return $xmldb_table;
     }
 
     /**
index 4ccab7c65bc075111d931f730136ab1aa62ea3b1..608e2c6db10ec3d8c13d4e6633933d1adb45dda8 100644 (file)
@@ -80,6 +80,45 @@ class mysql_sql_generator extends sql_generator {
         parent::__construct($mdb);
     }
 
+    /**
+     * Given one xmldb_table, check if it exists in DB (true/false)
+     *
+     * @param mixed the table to be searched (string name or xmldb_table instance)
+     * @param bool temp table (might need different checks)
+     * @return boolean true/false
+     */
+    public function table_exists($table, $temptable=false) {
+        if (!$temptable) {
+            return parent::table_exists($table, $temptable);
+        }
+
+        if (is_string($table)) {
+            $tablename = $table;
+        } else {
+        /// Calculate the name of the table
+            $tablename = $table->getName();
+        }
+
+        // ugly hack - mysql does not list temporary tables :-(
+        if ($this->mdb->execute("DESCRIBE {".$tablename."}") === false) {
+            $exists = false;
+        } else {
+            $exists = true;
+        }
+
+        return $exists;
+    }
+
+    /**
+     * Given one correct xmldb_table and the new name, returns the SQL statements
+     * to drop it (inside one array)
+     */
+    public function getDropTableSQL($xmldb_table) {
+        $sqlarr = parent::getDropTableSQL($xmldb_table);
+        $sqlarr = preg_replace('/^DROP TABLE/', "DROP TEMPORARY TABLE", $sqlarr);
+        return $sqlarr;
+    }
+
     /**
      * Given one XMLDB Type, lenght and decimals, returns the DB proper SQL type
      */
index 8f4723875cd3ca152e6b7860f4de8b03cbdfc414..a7287d84bc12ab145f12bae6863ea0e002d4bbba 100644 (file)
@@ -62,6 +62,27 @@ class oracle_sql_generator extends sql_generator {
         parent::__construct($mdb);
     }
 
+    /**
+     * Given one correct xmldb_table, returns the SQL statements
+     * to create temporary table (inside one array)
+     */
+    public function getCreateTempTableSQL($xmldb_table) {
+        $sqlarr = $this->getCreateTableSQL($xmldb_table);
+        $sqlarr = preg_replace('/^CREATE TABLE/', "CREATE GLOBAL TEMPORARY TABLE", $sqlarr);
+        return $sqlarr;
+    }
+
+    /**
+     * Given one correct xmldb_table and the new name, returns the SQL statements
+     * to drop it (inside one array)
+     */
+    public function getDropTempTableSQL($xmldb_table) {
+        $sqlarr = $this->getDropTableSQL($xmldb_table);
+        $tablename = $xmldb_table->getName();
+        array_unshift($sqlarr, "TRUNCATE TABLE {".$tablename."}"); // oracle requires truncate before being able to drop a temp table
+        return $sqlarr;
+    }
+
     /**
      * Given one XMLDB Type, lenght and decimals, returns the DB proper SQL type
      */
@@ -111,50 +132,6 @@ class oracle_sql_generator extends sql_generator {
         return $dbtype;
     }
 
-    /**
-     * This function will create the temporary table passed as argument with all its
-     * fields/keys/indexes/sequences, everything based in the XMLDB object
-     *
-     * TRUNCATE the table immediately after creation. A previous process using
-     * the same persistent connection may have created the temp table and failed to
-     * drop it. In that case, the table will exist, and create_temp_table() will
-     * will succeed.
-     *
-     * NOTE: The return value is the tablename - some DBs (MSSQL at least) use special
-     * names for temp tables.
-     *
-     * @uses $CFG, $db
-     * @param xmldb_table table object (full specs are required)
-     * @param boolean continue to specify if must continue on error (true) or stop (false)
-     * @param boolean feedback to specify to show status info (true) or not (false)
-     * @return string tablename on success, false on error
-     */
-    function create_temp_table($xmldb_table, $continue=true, $feedback=true) {
-        if (!($xmldb_table instanceof xmldb_table)) {
-            debugging('Incorrect create_table() $xmldb_table parameter');
-            return false;
-        }
-
-    /// Check table doesn't exist
-        if ($this->table_exists($xmldb_table)) {
-            debugging('Table ' . $xmldb_table->getName() .
-                      ' already exists. Create skipped', DEBUG_DEVELOPER);
-            return $xmldb_table->getName(); //Table exists, nothing to do
-        }
-
-        if (!$sqlarr = $this->getCreateTableSQL($xmldb_table)) {
-            return $xmldb_table->getName(); //Empty array = nothing to do = no error
-        }
-
-        $sqlarr = preg_replace('/^CREATE/', "CREATE GLOBAL TEMPORARY", $sqlarr);
-
-        if (execute_sql_arr($sqlarr, $continue, $feedback)) {
-            return $xmldb_table->getName();
-        } else {
-            return false;
-        }
-    }
-
     /**
      * Returns the code needed to create one enum for the xmldb_table and xmldb_field passes
      */
index 7545d1608b3dd1e297a3b5d26cb9bcc7ab28f033..04cbf071780accdba0b79dec5aef18109181ded5 100755 (executable)
@@ -17,39 +17,37 @@ class ddllib_test extends UnitTestCase {
     private $dbmanager;
 
     public function setUp() {
-        global $CFG;
+        global $CFG, $DB;
 
-        $db = new mysqli_adodb_moodle_database();
-        $db->connect($CFG->dbhost, $CFG->dbuser, $CFG->dbpass, $CFG->dbname, $CFG->dbpersist, $CFG->prefix);
-        $this->dbmanager = $db->get_manager();
+        $this->dbmanager = $DB->get_manager();
 
         $table = new xmldb_table("testtable");
-        $table->addFieldInfo('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null, null, null);
-        $table->addFieldInfo('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0');
-        $table->addFieldInfo('type', XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, XMLDB_ENUM,
+        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null, null, null);
+        $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0');
+        $table->add_field('type', XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, XMLDB_ENUM,
                 array('single', 'news', 'general', 'social', 'eachuser', 'teacher', 'qanda'), 'general');
-        $table->addFieldInfo('name', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null, null);
-        $table->addFieldInfo('intro', XMLDB_TYPE_TEXT, 'small', null, XMLDB_NOTNULL, null, null, null, null);
-        $table->addFieldInfo('logo', XMLDB_TYPE_BINARY, 'big', null, XMLDB_NOTNULL, null, null, null);
-        $table->addFieldInfo('assessed', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0');
-        $table->addFieldInfo('assesstimestart', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0');
-        $table->addFieldInfo('assesstimefinish', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0');
-        $table->addFieldInfo('scale', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, null, '0');
-        $table->addFieldInfo('maxbytes', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0');
-        $table->addFieldInfo('forcesubscribe', XMLDB_TYPE_INTEGER, '1', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0');
-        $table->addFieldInfo('trackingtype', XMLDB_TYPE_INTEGER, '2', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '1');
-        $table->addFieldInfo('rsstype', XMLDB_TYPE_INTEGER, '2', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0');
-        $table->addFieldInfo('rssarticles', XMLDB_TYPE_INTEGER, '2', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0');
-        $table->addFieldInfo('timemodified', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0');
-        $table->addFieldInfo('grade', XMLDB_TYPE_NUMBER, '20,0', XMLDB_UNSIGNED, null, null, null, null, null);
-        $table->addFieldInfo('percent', XMLDB_TYPE_NUMBER, '5,2', null, null, null, null, null, null);
-        $table->addFieldInfo('warnafter', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0');
-        $table->addFieldInfo('blockafter', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0');
-        $table->addFieldInfo('blockperiod', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0');
-        $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('id'));
-        $table->addKeyInfo('type-name', XMLDB_KEY_UNIQUE, array('type', 'name'));
-        $table->addIndexInfo('course', XMLDB_INDEX_NOTUNIQUE, array('course'));
-        $table->addIndexInfo('rsstype', XMLDB_INDEX_UNIQUE, array('rsstype'));
+        $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null, null);
+        $table->add_field('intro', XMLDB_TYPE_TEXT, 'small', null, XMLDB_NOTNULL, null, null, null, null);
+        $table->add_field('logo', XMLDB_TYPE_BINARY, 'big', null, XMLDB_NOTNULL, null, null, null);
+        $table->add_field('assessed', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0');
+        $table->add_field('assesstimestart', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0');
+        $table->add_field('assesstimefinish', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0');
+        $table->add_field('scale', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, null, '0');
+        $table->add_field('maxbytes', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0');
+        $table->add_field('forcesubscribe', XMLDB_TYPE_INTEGER, '1', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0');
+        $table->add_field('trackingtype', XMLDB_TYPE_INTEGER, '2', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '1');
+        $table->add_field('rsstype', XMLDB_TYPE_INTEGER, '2', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0');
+        $table->add_field('rssarticles', XMLDB_TYPE_INTEGER, '2', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0');
+        $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0');
+        $table->add_field('grade', XMLDB_TYPE_NUMBER, '20,0', XMLDB_UNSIGNED, null, null, null, null, null);
+        $table->add_field('percent', XMLDB_TYPE_NUMBER, '5,2', null, null, null, null, null, null);
+        $table->add_field('warnafter', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0');
+        $table->add_field('blockafter', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0');
+        $table->add_field('blockperiod', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0');
+        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
+        $table->add_key('type-name', XMLDB_KEY_UNIQUE, array('type', 'name'));
+        $table->add_index('course', XMLDB_INDEX_NOTUNIQUE, array('course'));
+        $table->add_index('rsstype', XMLDB_INDEX_UNIQUE, array('rsstype'));
 
         $table->setComment("This is a test'n drop table. You can drop it safely");
         $this->dbmanager->create_table($table);
@@ -57,14 +55,14 @@ class ddllib_test extends UnitTestCase {
 
         // Second, smaller table
         $table = new xmldb_table ('anothertest');
-        $table->addFieldInfo('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null, null, null);
-        $table->addFieldInfo('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0');
-        $table->addFieldInfo('name', XMLDB_TYPE_CHAR, '30', null, null, null, null, null, 'Moodle');
-        $table->addFieldInfo('secondname', XMLDB_TYPE_CHAR, '30', null, XMLDB_NOTNULL, null, null, null, null);
-        $table->addFieldInfo('intro', XMLDB_TYPE_TEXT, 'medium', null, XMLDB_NOTNULL, null, null, null, null);
-        $table->addFieldInfo('avatar', XMLDB_TYPE_BINARY, 'medium', null, null, null, null, null, null);
-        $table->addFieldInfo('grade', XMLDB_TYPE_NUMBER, '20,10', null, null, null, null, null);
-        $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('id'));
+        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null, null, null);
+        $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0');
+        $table->add_field('name', XMLDB_TYPE_CHAR, '30', null, null, null, null, null, 'Moodle');
+        $table->add_field('secondname', XMLDB_TYPE_CHAR, '30', null, XMLDB_NOTNULL, null, null, null, null);
+        $table->add_field('intro', XMLDB_TYPE_TEXT, 'medium', null, XMLDB_NOTNULL, null, null, null, null);
+        $table->add_field('avatar', XMLDB_TYPE_BINARY, 'medium', null, null, null, null, null, null);
+        $table->add_field('grade', XMLDB_TYPE_NUMBER, '20,10', null, null, null, null, null);
+        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
 
         $this->dbmanager->create_table($table);
         $this->tables[] = $table;
@@ -77,28 +75,21 @@ class ddllib_test extends UnitTestCase {
             }
         }
         unset($this->tables);
-
-        setup_DB();
     }
 
     public function testCreateTable() {
-        $table = new xmldb_table("other_test_table");
-        $field = new xmldb_field('id');
-        $field->setAttributes(XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, true);
-        $table->addField($field);
-        $key = new xmldb_key('PRIMARY');
-        $key->setAttributes(XMLDB_KEY_PRIMARY, array('id'));
-        $table->addKey($key);
+        $table = $this->tables[1];
+        $this->dbmanager->drop_table($table);
 
         $this->assertTrue($this->dbmanager->create_table($table));
-        $this->assertTrue($this->dbmanager->table_exists("other_test_table"));
+        $this->assertTrue($this->dbmanager->table_exists("anothertest"));
         $this->dbmanager->drop_table($table);
+        $this->assertFalse($this->dbmanager->table_exists("anothertest"));
 
         // Give existing table as argument
-        $table = $this->tables[1];
         $this->assertFalse($this->dbmanager->create_table($table));
 
-        // Give a wrong table param
+        // Give a wrong table param (expect a debugging message)
         $table = 'string';
         $this->assertFalse($this->dbmanager->create_table($table));
 
@@ -122,7 +113,7 @@ class ddllib_test extends UnitTestCase {
         $table = $this->tables[0];
         /// Create a new field with complex specs (enums are good candidates)
         $field = new xmldb_field('type2');
-        $field->setAttributes(XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, XMLDB_ENUM,
+        $field->set_attributes(XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, XMLDB_ENUM,
             array('single', 'news', 'general', 'social', 'eachuser', 'teacher', 'qanda'), 'general', 'course');
         $this->assertTrue($this->dbmanager->add_field($table, $field));
         $this->assertTrue($this->dbmanager->field_exists($table, 'type2'));
@@ -134,7 +125,7 @@ class ddllib_test extends UnitTestCase {
         $table = $this->tables[0];
         /// Create a new field with complex specs (enums are good candidates)
         $field = new xmldb_field('onenumber');
-        $field->setAttributes(XMLDB_TYPE_INTEGER, '6', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, 0, 'type');
+        $field->set_attributes(XMLDB_TYPE_INTEGER, '6', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, 0, 'type');
         $this->assertTrue($this->dbmanager->add_field($table, $field));
         $this->assertTrue($this->dbmanager->field_exists($table, 'onenumber'));
 
@@ -153,122 +144,122 @@ class ddllib_test extends UnitTestCase {
     public function testChangeFieldType() {
         $table = $this->tables[1];
         $field = new xmldb_field('course');
-        $field->setAttributes(XMLDB_TYPE_CHAR, '30', null, XMLDB_NOTNULL, null, null, null, '0');
+        $field->set_attributes(XMLDB_TYPE_CHAR, '30', null, XMLDB_NOTNULL, null, null, null, '0');
         $this->assertTrue($this->dbmanager->change_field_type($this->tables[1], $field));
 
         $field = new xmldb_field('course');
-        $field->setAttributes(XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0');
+        $field->set_attributes(XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0');
         $this->assertTrue($this->dbmanager->change_field_type($this->tables[1], $field));
 
         $field = new xmldb_field('grade');
-        $field->setAttributes(XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, null, null, "test'n drop");
+        $field->set_attributes(XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, null, null, "test'n drop");
         $this->assertTrue($this->dbmanager->change_field_type($this->tables[1], $field));
 
         $field = new xmldb_field('grade');
-        $field->setAttributes(XMLDB_TYPE_FLOAT, '20,10', XMLDB_UNSIGNED, null, null, null, null, null);
+        $field->set_attributes(XMLDB_TYPE_FLOAT, '20,10', XMLDB_UNSIGNED, null, null, null, null, null);
         $this->assertTrue($this->dbmanager->change_field_type($this->tables[1], $field));
 
         $field = new xmldb_field('grade');
-        $field->setAttributes(XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, null, null, 'test');
+        $field->set_attributes(XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, null, null, 'test');
         $this->assertTrue($this->dbmanager->change_field_type($this->tables[1], $field));
 
         $field = new xmldb_field('grade');
-        $field->setAttributes(XMLDB_TYPE_NUMBER, '20,10', XMLDB_UNSIGNED, null, null, null, null, null);
+        $field->set_attributes(XMLDB_TYPE_NUMBER, '20,10', XMLDB_UNSIGNED, null, null, null, null, null);
         $this->assertTrue($this->dbmanager->change_field_type($this->tables[1], $field));
     }
 
     public function testChangeFieldPrecision() {
         $table = $this->tables[1];
         $field = new xmldb_field('intro');
-        $field->setAttributes(XMLDB_TYPE_TEXT, 'big', null, XMLDB_NOTNULL, null, null, null, null);
+        $field->set_attributes(XMLDB_TYPE_TEXT, 'big', null, XMLDB_NOTNULL, null, null, null, null);
         $this->assertTrue($this->dbmanager->change_field_precision($this->tables[1], $field));
 
         $field = new xmldb_field('secondname');
-        $field->setAttributes(XMLDB_TYPE_CHAR, '10', null, XMLDB_NOTNULL, null, null, null, null);
+        $field->set_attributes(XMLDB_TYPE_CHAR, '10', null, XMLDB_NOTNULL, null, null, null, null);
         $this->assertTrue($this->dbmanager->change_field_precision($this->tables[1], $field));
 
         $field = new xmldb_field('grade');
-        $field->setAttributes(XMLDB_TYPE_NUMBER, '10,2', null, null, null, null, null, null);
+        $field->set_attributes(XMLDB_TYPE_NUMBER, '10,2', null, null, null, null, null, null);
         $this->assertTrue($this->dbmanager->change_field_precision($this->tables[1], $field));
 
         $field = new xmldb_field('course');
-        $field->setAttributes(XMLDB_TYPE_INTEGER, '5', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0');
+        $field->set_attributes(XMLDB_TYPE_INTEGER, '5', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0');
         $this->assertTrue($this->dbmanager->change_field_precision($this->tables[1], $field));
     }
 
     public function testChangeFieldSign() {
         $table = $this->tables[1];
         $field = new xmldb_field('grade');
-        $field->setAttributes(XMLDB_TYPE_NUMBER, '10,2', XMLDB_UNSIGNED, null, null, null, null, null);
+        $field->set_attributes(XMLDB_TYPE_NUMBER, '10,2', XMLDB_UNSIGNED, null, null, null, null, null);
         $this->assertTrue($this->dbmanager->change_field_unsigned($this->tables[1], $field));
 
         $field = new xmldb_field('grade');
-        $field->setAttributes(XMLDB_TYPE_NUMBER, '10,2', null, null, null, null, null, null);
+        $field->set_attributes(XMLDB_TYPE_NUMBER, '10,2', null, null, null, null, null, null);
         $this->assertTrue($this->dbmanager->change_field_unsigned($this->tables[1], $field));
     }
 
     public function testChangeFieldNullability() {
         $table = $this->tables[1];
         $field = new xmldb_field('name');
-        $field->setAttributes(XMLDB_TYPE_CHAR, '30', null, XMLDB_NOTNULL, null, null, null, 'Moodle');
+        $field->set_attributes(XMLDB_TYPE_CHAR, '30', null, XMLDB_NOTNULL, null, null, null, 'Moodle');
         $this->assertTrue($this->dbmanager->change_field_notnull($this->tables[1], $field));
 
         $field = new xmldb_field('name');
-        $field->setAttributes(XMLDB_TYPE_CHAR, '30', null, null, null, null, null, 'Moodle');
+        $field->set_attributes(XMLDB_TYPE_CHAR, '30', null, null, null, null, null, 'Moodle');
         $this->assertTrue($this->dbmanager->change_field_notnull($this->tables[1], $field));
     }
 
     public function testChangeFieldDefault() {
         $table = $this->tables[1];
         $field = new xmldb_field('name');
-        $field->setAttributes(XMLDB_TYPE_CHAR, '30', null, null, null, null, null, null);
+        $field->set_attributes(XMLDB_TYPE_CHAR, '30', null, null, null, null, null, null);
         $this->assertTrue($this->dbmanager->change_field_default($this->tables[1], $field));
 
         $field = new xmldb_field('name');
-        $field->setAttributes(XMLDB_TYPE_CHAR, '30', null, null, null, null, null, 'Moodle');
+        $field->set_attributes(XMLDB_TYPE_CHAR, '30', null, null, null, null, null, 'Moodle');
         $this->assertTrue($this->dbmanager->change_field_default($this->tables[1], $field));
 
         $field = new xmldb_field('secondname');
-        $field->setAttributes(XMLDB_TYPE_CHAR, '10', null, XMLDB_NOTNULL, null, null, null, 'Moodle2');
+        $field->set_attributes(XMLDB_TYPE_CHAR, '10', null, XMLDB_NOTNULL, null, null, null, 'Moodle2');
         $this->assertTrue($this->dbmanager->change_field_default($this->tables[1], $field));
 
         $field = new xmldb_field('secondname');
-        $field->setAttributes(XMLDB_TYPE_CHAR, '10', null, XMLDB_NOTNULL, null, null, null, null);
+        $field->set_attributes(XMLDB_TYPE_CHAR, '10', null, XMLDB_NOTNULL, null, null, null, null);
         $this->assertTrue($this->dbmanager->change_field_default($this->tables[1], $field));
     }
 
     public function testAddUniqueIndex() {
         $table = $this->tables[1];
         $index = new xmldb_index('secondname');
-        $index->setAttributes(XMLDB_INDEX_UNIQUE, array('name', 'secondname', 'grade'));
+        $index->set_attributes(XMLDB_INDEX_UNIQUE, array('name', 'secondname', 'grade'));
         $this->assertTrue($this->dbmanager->add_index($this->tables[1], $index));
     }
 
     public function testAddNonUniqueIndex() {
         $table = $this->tables[1];
         $index = new xmldb_index('secondname');
-        $index->setAttributes(XMLDB_INDEX_NOTUNIQUE, array('course', 'name'));
+        $index->set_attributes(XMLDB_INDEX_NOTUNIQUE, array('course', 'name'));
         $this->assertTrue($this->dbmanager->add_index($this->tables[1], $index));
     }
 
     public function testFindIndexName() {
         $table = $this->tables[1];
         $index = new xmldb_index('secondname');
-        $index->setAttributes(XMLDB_INDEX_NOTUNIQUE, array('course', 'name'));
+        $index->set_attributes(XMLDB_INDEX_NOTUNIQUE, array('course', 'name'));
         $this->dbmanager->add_index($this->tables[1], $index);
 
         // TODO DBM Systems name their indices differently. Maybe just test for non-false (or simply true)
         $this->assertEqual($this->dbmanager->find_index_name($this->tables[1], $index), 'mdl_anot_counam_ix');
 
         $nonexistentindex = new xmldb_index('nonexistentindex');
-        $nonexistentindex->setAttributes(XMLDB_INDEX_NOTUNIQUE, array('name'));
+        $nonexistentindex->set_attributes(XMLDB_INDEX_NOTUNIQUE, array('name'));
         $this->assertFalse($this->dbmanager->find_index_name($this->tables[1], $nonexistentindex));
     }
 
     public function testDropIndex() {
         $table = $this->tables[1];
         $index = new xmldb_index('secondname');
-        $index->setAttributes(XMLDB_INDEX_NOTUNIQUE, array('course', 'name'));
+        $index->set_attributes(XMLDB_INDEX_NOTUNIQUE, array('course', 'name'));
         $this->dbmanager->add_index($this->tables[1], $index);
 
         $this->assertTrue($this->dbmanager->drop_index($this->tables[1], $index));
@@ -278,21 +269,21 @@ class ddllib_test extends UnitTestCase {
     public function testAddUniqueKey() {
         $table = $this->tables[1];
         $key = new xmldb_key('id-course-grade');
-        $key->setAttributes(XMLDB_KEY_UNIQUE, array('id', 'course', 'grade'));
+        $key->set_attributes(XMLDB_KEY_UNIQUE, array('id', 'course', 'grade'));
         $this->assertTrue($this->dbmanager->add_key($this->tables[1], $key));
     }
 
     public function testAddForeignUniqueKey() {
         $table = $this->tables[1];
         $key = new xmldb_key('course');
-        $key->setAttributes(XMLDB_KEY_FOREIGN_UNIQUE, array('course'), 'anothertest', array('id'));
+        $key->set_attributes(XMLDB_KEY_FOREIGN_UNIQUE, array('course'), 'anothertest', array('id'));
         $this->assertTrue($this->dbmanager->add_key($this->tables[1], $key));
     }
 
     public function testDropKey() {
         $table = $this->tables[1];
         $key = new xmldb_key('course');
-        $key->setAttributes(XMLDB_KEY_FOREIGN_UNIQUE, array('course'), 'anothertest', array('id'));
+        $key->set_attributes(XMLDB_KEY_FOREIGN_UNIQUE, array('course'), 'anothertest', array('id'));
         $this->dbmanager->add_key($this->tables[1], $key);
 
         $this->assertTrue($this->dbmanager->drop_key($this->tables[1], $key));
@@ -301,14 +292,14 @@ class ddllib_test extends UnitTestCase {
     public function testAddForeignKey() {
         $table = $this->tables[1];
         $key = new xmldb_key('course');
-        $key->setAttributes(XMLDB_KEY_FOREIGN, array('course'), 'anothertest', array('id'));
+        $key->set_attributes(XMLDB_KEY_FOREIGN, array('course'), 'anothertest', array('id'));
         $this->assertTrue($this->dbmanager->add_key($this->tables[1], $key));
     }
 
     public function testDropForeignKey() {
         $table = $this->tables[1];
         $key = new xmldb_key('course');
-        $key->setAttributes(XMLDB_KEY_FOREIGN, array('course'), 'anothertest', array('id'));
+        $key->set_attributes(XMLDB_KEY_FOREIGN, array('course'), 'anothertest', array('id'));
         $this->dbmanager->add_key($this->tables[1], $key);
 
         $this->assertTrue($this->dbmanager->drop_key($this->tables[1], $key));
@@ -318,14 +309,14 @@ class ddllib_test extends UnitTestCase {
         $table = $this->tables[0];
         // Removing an enum value
         $field = new xmldb_field('type');
-        $field->setAttributes(XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, XMLDB_ENUM,
+        $field->set_attributes(XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, XMLDB_ENUM,
                 array('news', 'general', 'social', 'eachuser', 'teacher', 'qanda'), 'general', 'course');
 
         $this->assertTrue($this->dbmanager->change_field_enum($table, $field));
 
         // Adding an enum value
         $field = new xmldb_field('type');
-        $field->setAttributes(XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, XMLDB_ENUM,
+        $field->set_attributes(XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, XMLDB_ENUM,
                 array('single', 'news', 'general', 'social', 'eachuser', 'teacher', 'qanda'), 'general', 'course');
         $this->assertTrue($this->dbmanager->change_field_enum($table, $field));
     }
@@ -333,7 +324,7 @@ class ddllib_test extends UnitTestCase {
     public function testRenameIndex() {
         $table = $this->tables[0];
         $index = new xmldb_index('course');
-        $index->setAttributes(XMLDB_INDEX_UNIQUE, array('course'));
+        $index->set_attributes(XMLDB_INDEX_UNIQUE, array('course'));
 
         $this->assertTrue($this->dbmanager->rename_index($table, $index, 'newindexname'));
     }
@@ -341,7 +332,7 @@ class ddllib_test extends UnitTestCase {
     public function testRenameKey() {
         $table = $this->tables[0];
         $key = new xmldb_key('course');
-        $key->setAttributes(XMLDB_KEY_UNIQUE, array('course'));
+        $key->set_attributes(XMLDB_KEY_UNIQUE, array('course'));
 
         $this->assertTrue($this->dbmanager->rename_key($table, $key, 'newkeyname'));
 
@@ -350,7 +341,7 @@ class ddllib_test extends UnitTestCase {
     public function testRenameField() {
         $table = $this->tables[0];
         $field = new xmldb_field('type');
-        $field->setAttributes(XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, XMLDB_ENUM,
+        $field->set_attributes(XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, XMLDB_ENUM,
                 array('single', 'news', 'general', 'social', 'eachuser', 'teacher', 'qanda'), 'general', 'course');
 
         $this->assertTrue($this->dbmanager->rename_field($table, $field, 'newfieldname'));
@@ -361,6 +352,7 @@ class ddllib_test extends UnitTestCase {
         $rand = round(rand() * 100);
         $this->assertFalse($this->dbmanager->table_exists('newtablename'. $rand));
         $this->assertTrue($this->dbmanager->rename_table($table, 'newtablename'. $rand));
+        $this->dbmanager->drop_table('newtablename' . $rand);
     }
 
     public function testTableExists() {
@@ -489,14 +481,11 @@ class ddllib_test extends UnitTestCase {
         // Feed incorrect table param
         $this->assertFalse($this->dbmanager->create_temp_table('anothertest'));
 
-        // Correct table but with existing name
-        $table = $this->tables[0];
-        $this->assertEqual('testtable', $this->dbmanager->create_temp_table($table));
+        $table = $this->tables[1];
 
         // New table
-        $this->dbmanager->drop_table($this->tables[0]);
-        $this->assertEqual('testtable', $this->dbmanager->create_temp_table($table));
-
+        $this->assertTrue($this->dbmanager->create_temp_table($table));
+        $this->assertTrue($this->dbmanager->drop_temp_table($table));
     }
 }
 ?>
index c2b37404a9b8645c0f1d2ff1d4f710654b03bc43..bef24fda11e409923c86c955672a6cf81ea9ae17 100644 (file)
@@ -158,6 +158,34 @@ abstract class sql_generator {
         }
     }
 
+    /**
+     * Given one xmldb_table, check if it exists in DB (true/false)
+     *
+     * @param mixed the table to be searched (string name or xmldb_table instance)
+     * @param bool temp table (might need different checks)
+     * @return boolean true/false
+     */
+    public function table_exists($table, $temptable=false) {
+    /// Do this function silenty (to avoid output in install/upgrade process)
+        $olddbdebug = $this->mdb->get_debug();
+        $this->mdb->set_debug(false);
+
+        if (is_string($table)) {
+            $tablename = $table;
+        } else {
+        /// Calculate the name of the table
+            $tablename = $table->getName();
+        }
+
+    /// get all tables in moodle database
+        $tables = $this->mdb->get_tables();
+        $exists = in_array($tablename, $tables);
+    /// Re-set original debug
+        $this->mdb->set_debug($olddbdebug);
+
+        return $exists;
+    }
+
     /**
      * This function will return the SQL code needed to create db tables and statements
      */
@@ -344,6 +372,23 @@ abstract class sql_generator {
         return $results;
     }
 
+    /**
+     * Given one correct xmldb_table, returns the SQL statements
+     * to create temporary table (inside one array)
+     */
+    public function getCreateTempTableSQL($xmldb_table) {
+        $sqlarr = $this->getCreateTableSQL($xmldb_table);
+        $sqlarr = preg_replace('/^CREATE TABLE/', "CREATE TEMPORARY TABLE", $sqlarr);
+        return $sqlarr;
+    }
+
+    /**
+     * Tweaks the temp table instance - required for mssql # naming
+     */
+    public function tweakTempTable($xmldb_table) {
+        return $xmldb_table;
+    }
+
     /**
      * Given one correct xmldb_index, returns the SQL statements
      * needed to create it (in array)
@@ -576,6 +621,14 @@ abstract class sql_generator {
         return $results;
     }
 
+    /**
+     * Given one correct xmldb_table and the new name, returns the SQL statements
+     * to drop it (inside one array)
+     */
+    public function getDropTempTableSQL($xmldb_table) {
+        return $this->getDropTableSQL($xmldb_table);
+    }
+
     /**
      * Given one xmldb_table and one xmldb_field, return the SQL statements needded to add the field to the table
      */
index 901d7819dfba79e9288e4092fded3949cd167bae..e170e7c77328ac3cc873a2391993b663b99a4e0b 100644 (file)
@@ -200,6 +200,15 @@ abstract class moodle_database {
         return array($sql, $params);
     }
 
+    /**
+     * Converts short table name {tablename} to real table name
+     * @param string sql
+     * @return string sql
+     */
+    protected function fix_table_names($sql) {
+        return preg_replace('/\{([a-z][a-z0-9_]*)\}/', $this->prefix.'$1', $sql);
+    }
+
     /**
      * Normalizes sql query parameters and verifies parameters.
      * @param string $sql query or part of it
@@ -210,7 +219,7 @@ abstract class moodle_database {
         $allowed_types = $this->allowed_param_types();
 
         // convert table names
-        $sql = preg_replace('/\{([a-z][a-z0-9_]*)\}/', $this->prefix.'$1', $sql);
+        $sql = $this->fix_table_names($sql);
 
         // NICOLAS C: Fixed regexp for negative backwards lookahead of double colons. Thanks for Sam Marshall's help
         $named_count = preg_match_all('/(?<!:):[a-z][a-z0-9_]*/', $sql, $named_matches); // :: used in pgsql casts
index 4ee0080885c95443efb9e83fd72fb66651ff3af1..65b9f2a7fd880cb03ae2bf32e2dccafc8d4339e0 100644 (file)
@@ -8,6 +8,10 @@ require_once($CFG->libdir.'/dml/adodb_moodle_database.php');
  * @package dmlib
  */
 class mssql_adodb_moodle_database extends adodb_moodle_database {
+    /**
+     * Ungly mssql hack needed for temp table names starting with '#'
+     */
+    public $temptables;
 
     public function connect($dbhost, $dbuser, $dbpass, $dbname, $dbpersist, $prefix, array $dboptions=null) {
         if ($prefix == '' and !$this->external) {
@@ -84,6 +88,26 @@ class mssql_adodb_moodle_database extends adodb_moodle_database {
         return $str;
     }
 
+    /**
+     * Converts short table name {tablename} to real table name
+     * @param string sql
+     * @return string sql
+     */
+    protected function fix_table_names($sql) {
+        // look for temporary tables, they must start with #
+        if (preg_match_all('/\{([a-z][a-z0-9_]*)\}/', $sql, $matches)) {
+            foreach($matches[0] as $key=>$match) {
+                $name = $matches[1][$key];
+                if (empty($this->temptables[$name])) {
+                    $sql = str_replace($match, $this->prefix.$name, $sql);
+                } else {
+                    $sql = str_replace($match, '#'.$this->prefix.$name, $sql);
+                }
+            }
+        }
+        return $sql;
+    }
+
     /**
      * Returns supported query parameter types
      * @return bitmask