]> git.mjollnir.org Git - moodle.git/commitdiff
MDL-15671, MDL-15717 DB->import_record() support - code based on patch by Andrei...
authorskodak <skodak>
Mon, 25 Aug 2008 21:00:47 +0000 (21:00 +0000)
committerskodak <skodak>
Mon, 25 Aug 2008 21:00:47 +0000 (21:00 +0000)
lib/dml/adodb_moodle_database.php
lib/dml/moodle_database.php
lib/dml/mssql_adodb_moodle_database.php
lib/dml/mysqli_adodb_moodle_database.php
lib/dml/oci8po_adodb_moodle_database.php
lib/dml/pdo_moodle_database.php
lib/dml/postgres7_adodb_moodle_database.php
lib/dml/simpletest/testdml.php

index b0b5de0203906bf0d01a480369ff3c9ed5da1f28..e07e9336760982c7fb1bbb5d6555b9af68a4ca3e 100644 (file)
@@ -238,13 +238,22 @@ abstract class adodb_moodle_database extends moodle_database {
      * @param mixed $params data record as object or array
      * @param bool $returnit return it of inserted record
      * @param bool $bulk true means repeated inserts expected
+     * @param bool $customsequence true if 'id' included in $params, disables $returnid
      * @return mixed success or new id
      */
-    public function insert_record_raw($table, $params, $returnid=true, $bulk=false) {
+    public function insert_record_raw($table, $params, $returnid=true, $bulk=false, $customsequence=false) {
         if (!is_array($params)) {
             $params = (array)$params;
         }
-        unset($params['id']);
+
+        if ($customsequence) {
+            if (!isset($params['id'])) {
+                return false;
+            }
+            $returnid = false;
+        } else {
+            unset($params['id']);
+        }
 
         if (empty($params)) {
             return false;
index 605b939796a9864203ecebe39aa0af3e09da557f..b37ef39361ff45b4745e46cc2d7919220231d8d4 100644 (file)
@@ -984,9 +984,10 @@ abstract class moodle_database {
      * @param mixed $params data record as object or array
      * @param bool $returnit return it of inserted record
      * @param bool $bulk true means repeated inserts expected
+     * @param bool $customsequence true if 'id' included in $params, disables $returnid
      * @return mixed success or new id
      */
-    public abstract function insert_record_raw($table, $params, $returnid=true, $bulk=false);
+    public abstract function insert_record_raw($table, $params, $returnid=true, $bulk=false, $customsequence=false);
 
     /**
      * Insert a record into a table and return the "id" field if required.
@@ -1001,6 +1002,16 @@ abstract class moodle_database {
      */
     public abstract function insert_record($table, $dataobject, $returnid=true, $bulk=false);
 
+    /**
+     * Import a record into a table, id field is required.
+     * Safety checks are NOT carried out. Lobs are supported.
+     *
+     * @param string $table name of database table to be inserted into
+     * @param object $dataobject A data object with values for one or more fields in the record
+     * @return bool success
+     */
+    public abstract function import_record($table, $dataobject);
+
     /**
      * Update record in database, as fast as possible, no safety checks, lobs not supported.
      * @param string $table name
index f3500446420026936467dfb9f5e9af64b8f6a273..c9350e1450d80198f0127356b61ceb248bdf2af2 100644 (file)
@@ -365,4 +365,58 @@ class mssql_adodb_moodle_database extends adodb_moodle_database {
         }
         return $this->change_database_structure("DBCC CHECKIDENT ('$this->prefix$table', RESEED, $value)");
     }
+
+
+    /**
+     * Import a record into a table, id field is required.
+     * Basic safety checks only. Lobs are supported.
+     * @param string $table name of database table to be inserted into
+     * @param mixed $dataobject object or array with fields in the record
+     * @return bool success
+     */
+    public function import_record($table, $dataobject) {
+        $dataobject = (object)$dataobject;
+
+        $columns = $this->get_columns($table);
+        $cleaned = array();
+        $blobs = array();
+
+        foreach ($dataobject as $field=>$value) {
+            if (!isset($columns[$field])) { // Non-existing table field, skip it
+                continue;
+            }
+            $column = $columns[$field];
+            if ($column->meta_type == 'B') { // BLOBs (IMAGE) columns need to be updated apart
+                if (!is_null($value)) {      // If value not null, add it to the list of BLOBs to update later
+                    $blobs[$field] = $value;
+                    $value = null;           // Set the default value to be inserted in first instance
+                }
+            } else if ($column->meta_type == 'X') { // MSSQL doesn't cast from int to text, so if text column
+                if (is_numeric($value)) {           // and is numeric value
+                    $value = (string)$value;        // cast to string
+                }
+            }
+
+            $cleaned[$field] = $value;
+        }
+
+        if (!$this->insert_record_raw($table, $cleaned, false, true, true)) {
+            return false;
+        }
+
+        if (empty($blobs)) {
+            return true;
+        }
+
+    /// We have BLOBs to postprocess
+
+        foreach ($blobs as $key=>$value) {
+            $this->writes++;
+            if (!$this->adodb->UpdateBlob($this->prefix.$table, $key, $value, "id = $id")) {
+                return false;
+            }
+        }
+
+        return true;
+    }
 }
index a3f2cb2ca9d1922b76f76a9bdd0b163b1588e9fc..a231208b7d182d0303388e81c3c03c386f9c4c04 100644 (file)
@@ -289,4 +289,31 @@ class mysqli_adodb_moodle_database extends adodb_moodle_database {
         $value++;
         return $this->change_database_structure("ALTER TABLE $this->prefix$table AUTO_INCREMENT = $value");
     }
+
+    /**
+     * Import a record into a table, id field is required.
+     * Basic safety checks only. Lobs are supported.
+     * @param string $table name of database table to be inserted into
+     * @param mixed $dataobject object or array with fields in the record
+     * @return bool success
+     */
+    public function import_record($table, $dataobject) {
+        $dataobject = (object)$dataobject;
+
+        if (empty($dataobject->id)) {
+            return false;
+        }
+
+        $columns = $this->get_columns($table);
+        $cleaned = array();
+
+        foreach ($dataobject as $field=>$value) {
+            if (!isset($columns[$field])) {
+                continue;
+            }
+            $cleaned[$field] = $value;
+        }
+
+        return $this->insert_record_raw($table, $cleaned, false, true, true);
+    }
 }
\ No newline at end of file
index 1b754713be15edd6cea57173242f212f39a239b6..3d02f662d8cdcbecf079a38c407eb009061c73ea 100644 (file)
@@ -450,13 +450,22 @@ class oci8po_adodb_moodle_database extends adodb_moodle_database {
      * @param mixed $params data record as object or array
      * @param bool $returnit return it of inserted record
      * @param bool $bulk true means repeated inserts expected
+     * @param bool $customsequence true if 'id' included in $params, disables $returnid
      * @return mixed success or new id
      */
-    public function insert_record_raw($table, $params, $returnid=true, $bulk=false) {
+    public function insert_record_raw($table, $params, $returnid=true, $bulk=false, $customsequence=false) {
         if (!is_array($params)) {
             $params = (array)$params;
         }
-        unset($params['id']);
+
+        if ($customsequence) {
+            if (!isset($params['id'])) {
+                return false;
+            }
+            $returnid = false;
+        } else {
+            unset($params['id']);
+        }
 
         if ($returnid) {
             $dbman = $this->get_manager();
@@ -631,4 +640,71 @@ class oci8po_adodb_moodle_database extends adodb_moodle_database {
         $this->change_database_structure("DROP SEQUENCE $seqname");
         return $this->change_database_structure("CREATE SEQUENCE $seqname START WITH $value INCREMENT BY 1 NOMAXVALUE");
     }
+
+    /**
+     * Import a record into a table, id field is required.
+     * Basic safety checks only. Lobs are supported.
+     * @param string $table name of database table to be inserted into
+     * @param mixed $dataobject object or array with fields in the record
+     * @return bool success
+     */
+    public function import_record($table, $dataobject) {
+        $dataobject = (object)$dataobject;
+
+        $columns = $this->get_columns($table);
+        $cleaned = array();
+        $blobs = array();
+        $clobs = array();
+
+        foreach ($dataobject as $field=>$value) {
+            if (!isset($columns[$field])) { /// Non-existing table field, skip it
+                continue;
+            }
+        /// Apply Oracle dirty hack to value, to have "correct" empty values for Oracle
+            $value = $this->oracle_dirty_hack($table, $field, $value);
+
+        /// Get column metadata
+            $column = $columns[$field];
+            if ($column->meta_type == 'B') { /// BLOBs columns need to be updated apart
+                if (!is_null($value)) {      /// If value not null, add it to the list of BLOBs to update later
+                    $blobs[$field] = $value;
+                    $value = 'empty_blob()'; /// Set the default value to be inserted (preparing lob storage for next update)
+                }
+
+            } else if ($column->meta_type == 'X' && strlen($value) > 4000) { /// CLOB columns need to be updated apart (if lenght > 4000)
+                if (!is_null($value)) {      /// If value not null, add it to the list of BLOBs to update later
+                    $clobs[$field] = $value;
+                    $value = 'empty_clob()'; /// Set the default value to be inserted (preparing lob storage for next update)
+                }
+            }
+
+            $cleaned[$field] = $value;
+        }
+
+        if (!$this->insert_record_raw($table, $cleaned, false, true, true)) {
+            return false;
+        }
+
+        if (empty($blobs) and empty($clobs)) {
+            return true;
+        }
+
+    /// We have BLOBs or CLOBs to postprocess
+
+        foreach ($blobs as $key=>$value) {
+            $this->writes++;
+            if (!$this->adodb->UpdateBlob($this->prefix.$table, $key, $value, "id = $id")) {
+                return false;
+            }
+        }
+
+        foreach ($clobs as $key=>$value) {
+            $this->writes++;
+            if (!$this->adodb->UpdateClob($this->prefix.$table, $key, $value, "id = $id")) {
+                return false;
+            }
+        }
+
+        return true;
+    }
 }
index fbc8369fe709fb10face0112e62e3c6029dbb9c8..7e150ee69eec7e43b6289f79fc5df8bbb2b29f94 100644 (file)
@@ -57,7 +57,7 @@ abstract class pdo_moodle_database extends moodle_database {
     protected function get_dsn() {
         return 'mysql:host='.$this->dbhost.';dbname='.$this->dbname;
     }
-    
+
     /**
      * Returns the driver-dependent connection attributes for PDO based on members stored by connect.
      * Must be called after $dbname, $dbhost, etc. members have been set.
@@ -66,7 +66,7 @@ abstract class pdo_moodle_database extends moodle_database {
     protected function get_pdooptions() {
         return array(PDO::ATTR_PERSISTENT => $this->dbpersist);
     }
-    
+
     protected function configure_dbconnection() {
         ///TODO: not needed preconfigure_dbconnection() stuff for PDO drivers?
     }
@@ -86,7 +86,7 @@ abstract class pdo_moodle_database extends moodle_database {
      * @return string
      */
     public function get_name() {
-        return get_string($this->get_dbtype() . '_pdo', 'install'); 
+        return get_string($this->get_dbtype() . '_pdo', 'install');
     }
 
     /**
@@ -112,7 +112,7 @@ abstract class pdo_moodle_database extends moodle_database {
         } catch(PDOException $ex) {}
         return $result;
     }
-    
+
     /**
      * Returns supported query parameter types
      * @return bitmask
@@ -120,7 +120,7 @@ abstract class pdo_moodle_database extends moodle_database {
     protected function allowed_param_types() {
         return SQL_PARAMS_QM | SQL_PARAMS_NAMED;
     }
-    
+
     /**
      * Returns last error reported by database engine.
      */
@@ -170,7 +170,7 @@ abstract class pdo_moodle_database extends moodle_database {
         }
         echo '<hr />';
     }
-    
+
     /**
      * Do NOT use in code, to be used by database_manager only!
      * @param string $sql query
@@ -201,10 +201,10 @@ abstract class pdo_moodle_database extends moodle_database {
     }
 
     /**
-     * Factory method that creates a recordset for return by a query. The generic pdo_moodle_recordset 
+     * Factory method that creates a recordset for return by a query. The generic pdo_moodle_recordset
      * class should fit most cases, but pdo_moodle_database subclasses can overide this method to return
      * a subclass of pdo_moodle_recordset.
-     * @param object $sth instance of PDOStatement 
+     * @param object $sth instance of PDOStatement
      * @return object instance of pdo_moodle_recordset
      */
     protected function create_recordset($sth) {
@@ -267,7 +267,7 @@ abstract class pdo_moodle_database extends moodle_database {
             return false;
         }
     }
-    
+
     /**
      * Returns the sql statement with clauses to append used to limit a recordset range.
      * @param string $sql the SQL statement to limit.
@@ -334,13 +334,22 @@ abstract class pdo_moodle_database extends moodle_database {
      * @param mixed $params data record as object or array
      * @param bool $returnit return it of inserted record
      * @param bool $bulk true means repeated inserts expected
+     * @param bool $customsequence true if 'id' included in $params, disables $returnid
      * @return mixed success or new id
      */
-    public function insert_record_raw($table, $params, $returnid=true, $bulk=false) {
+    public function insert_record_raw($table, $params, $returnid=true, $bulk=false, $customsequence=false) {
         if (!is_array($params)) {
             $params = (array)$params;
         }
-        unset($params['id']);
+
+        if ($customsequence) {
+            if (!isset($params['id'])) {
+                return false;
+            }
+            $returnid = false;
+        } else {
+            unset($params['id']);
+        }
 
         if (empty($params)) {
             return false;
@@ -364,7 +373,7 @@ abstract class pdo_moodle_database extends moodle_database {
         }
         return false;
     }
-    
+
     /**
      * Insert a record into a table and return the "id" field if required,
      * Some conversions and safety checks are carried out. Lobs are supported.
@@ -409,7 +418,7 @@ abstract class pdo_moodle_database extends moodle_database {
 
         return $this->insert_record_raw($table, $cleaned, $returnid, $bulk);
     }
-    
+
     /**
      * Update record in database, as fast as possible, no safety checks, lobs not supported.
      * @param string $table name
@@ -564,4 +573,26 @@ abstract class pdo_moodle_database extends moodle_database {
             return false;
         }
     }
+
+    /**
+     * Import a record into a table, id field is required.
+     * Basic safety checks only. Lobs are supported.
+     * @param string $table name of database table to be inserted into
+     * @param mixed $dataobject object or array with fields in the record
+     * @return bool success
+     */
+    public function import_record($table, $dataobject) {
+        $dataobject = (object)$dataobject;
+
+        $columns = $this->get_columns($table);
+        $cleaned = array();
+        foreach ($dataobject as $field=>$value) {
+            if (!isset($columns[$field])) {
+                continue;
+            }
+            $cleaned[$field] = $value;
+        }
+
+        return $this->insert_record_raw($table, $cleaned, false, true, true);
+    }
 }
index 9170b5c1797632a17a2902b4a840d7f45a8310e8..0710cec63fabb23d1628410cbf6bed5dad0ad1ec 100644 (file)
@@ -163,24 +163,34 @@ class postgres7_adodb_moodle_database extends adodb_moodle_database {
      * @param mixed $params data record as object or array
      * @param bool $returnit return it of inserted record
      * @param bool $bulk true means repeated inserts expected
+     * @param bool $customsequence true if 'id' included in $params, disables $returnid
      * @return mixed success or new id
      */
-    public function insert_record_raw($table, $params, $returnid=true, $bulk=false) {
-    /// Postgres doesn't have the concept of primary key built in
-    /// and will return the OID which isn't what we want.
-    /// The efficient and transaction-safe strategy is to
-    /// move the sequence forward first, and make the insert
-    /// with an explicit id.
-
+    public function insert_record_raw($table, $params, $returnid=true, $bulk=false, $customsequence=false) {
         if (!is_array($params)) {
             $params = (array)$params;
         }
-        unset($params['id']);
-        if ($returnid) {
-            $this->reads++;
-            $seqname = "{$this->prefix}{$table}_id_seq";
-            if ($nextval = $this->adodb->GenID($seqname)) {
-                $params['id'] = (int)$nextval;
+
+        if ($customsequence) {
+            if (!isset($params['id'])) {
+                return false;
+            }
+            $returnid = false;
+
+        } else {
+            /// Postgres doesn't have the concept of primary key built in
+            /// and will return the OID which isn't what we want.
+            /// The efficient and transaction-safe strategy is to
+            /// move the sequence forward first, and make the insert
+            /// with an explicit id.
+            if ($returnid) {
+                $this->reads++;
+                $seqname = "{$this->prefix}{$table}_id_seq";
+                if ($nextval = $this->adodb->GenID($seqname)) {
+                    $params['id'] = (int)$nextval;
+                }
+            } else {
+                unset($params['id']);
             }
         }
 
@@ -476,4 +486,53 @@ class postgres7_adodb_moodle_database extends adodb_moodle_database {
         $value++;
         return $this->change_database_structure("ALTER SEQUENCE $this->prefix{$table}_id_seq RESTART WITH $value");
     }
+
+    /**
+     * Import a record into a table, id field is required.
+     * Basic safety checks only. Lobs are supported.
+     * @param string $table name of database table to be inserted into
+     * @param mixed $dataobject object or array with fields in the record
+     * @return bool success
+     */
+    public function import_record($table, $dataobject) {
+        $dataobject = (object)$dataobject;
+
+        $columns = $this->get_columns($table);
+        $cleaned = array();
+        $blobs   = array();
+
+        foreach ($dataobject as $field=>$value) {
+            if (!isset($columns[$field])) {
+                continue;
+            }
+            $column = $columns[$field];
+            if ($column->meta_type == 'B') {
+                if (!is_null($value)) {
+                    $blobs[$field] = $value;
+                    $cleaned[$field] = '@#BLOB#@';
+                    continue;
+                }
+            }
+            $cleaned[$field] = $value;
+        }
+
+        if (!$this->insert_record_raw($table, $cleaned, false, true, true)) {
+            return false;
+        }
+
+        if (empty($blobs)) {
+            return true;
+        }
+
+    /// We have BLOBs to postprocess
+
+        foreach ($blobs as $key=>$value) {
+            $this->writes++;
+            if (!$this->adodb->UpdateBlob($this->prefix.$table, $key, $value, "id = $id", 'BLOB')) { // adodb does not use bound parameters for blob updates :-(
+                return false;
+            }
+        }
+
+        return true;
+    }
 }
\ No newline at end of file
index 61d6255884e6c96c87906b94d079d8ea1438958e..c4e54bd24c4861ca57dea94d0af665fde43252e8 100755 (executable)
@@ -992,6 +992,53 @@ class dml_test extends UnitTestCase {
 
     }
 
+    public function test_import_record() {
+        $DB = $this->tdb;
+        $dbman = $DB->get_manager();
+
+        $table = $this->get_test_table($dbman, "testtable");
+        $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_key('primary', XMLDB_KEY_PRIMARY, array('id'));
+        $dbman->create_table($table);
+        $this->tables[$table->getName()] = $table;
+
+        $record = (object)array('id'=>666, 'course'=>10);
+        $this->assertTrue($DB->import_record('testtable', $record));
+        $records = $DB->get_records('testtable');
+        $this->assertEqual(1, count($records));
+        $this->assertEqual(10, $records[666]->course);
+
+        $record = (object)array('id'=>13, 'course'=>2);
+        $this->assertTrue($DB->import_record('testtable', $record));
+        $records = $DB->get_records('testtable');
+        $this->assertEqual(2, $records[13]->course);
+    }
+
+    public function test_reset_sequence() {
+        $DB = $this->tdb;
+        $dbman = $DB->get_manager();
+
+        $table = $this->get_test_table($dbman, "testtable");
+        $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_key('primary', XMLDB_KEY_PRIMARY, array('id'));
+        $dbman->create_table($table);
+        $this->tables[$table->getName()] = $table;
+
+        $record = (object)array('id'=>666, 'course'=>10);
+        $DB->import_record('testtable', $record);
+        $DB->delete_records('testtable');
+
+        $this->assertTrue($DB->reset_sequence('testtable'));
+        $this->assertEqual(1, $DB->insert_record('testtable', (object)array('course'=>13)));
+
+        $DB->import_record('testtable', $record);
+        $this->assertTrue($DB->reset_sequence('testtable'));
+        $this->assertEqual(667, $DB->insert_record('testtable', (object)array('course'=>13)));
+    }
+
+
     public function test_insert_record_clob() {
         global $CFG;
 
@@ -1337,9 +1384,9 @@ class dml_test extends UnitTestCase {
     function test_sql_position() {
         $DB = $this->tdb;
         $this->assertEqual($DB->get_field_sql(
-                "SELECT " . $DB->sql_position("'ood'", "'Moodle'") . $DB->sql_null_from_clause()), 2); 
+                "SELECT " . $DB->sql_position("'ood'", "'Moodle'") . $DB->sql_null_from_clause()), 2);
         $this->assertEqual($DB->get_field_sql(
-                "SELECT " . $DB->sql_position("'Oracle'", "'Moodle'") . $DB->sql_null_from_clause()), 0); 
+                "SELECT " . $DB->sql_position("'Oracle'", "'Moodle'") . $DB->sql_null_from_clause()), 0);
     }
 }
 
@@ -1376,8 +1423,10 @@ class moodle_database_for_testing extends moodle_database {
     public function get_recordset_sql($sql, array $params=null, $limitfrom=0, $limitnum=0){}
     public function get_records_sql($sql, array $params=null, $limitfrom=0, $limitnum=0){}
     public function get_fieldset_sql($sql, array $params=null){}
-    public function insert_record_raw($table, $params, $returnid=true, $bulk=false){}
+    public function insert_record_raw($table, $params, $returnid=true, $bulk=false, $customsequence=false){}
     public function insert_record($table, $dataobject, $returnid=true, $bulk=false){}
+    public function import_record($table, $dataobject){}
+    public function reset_sequence($table){}
     public function update_record_raw($table, $params, $bulk=false){}
     public function update_record($table, $dataobject, $bulk=false){}
     public function set_field_select($table, $newfield, $newvalue, $select, array $params=null){}