Index: moodle_database.php =================================================================== RCS file: /cvsroot/moodle/moodle/lib/dml/moodle_database.php,v retrieving revision 1.38 diff -u -r1.38 moodle_database.php --- moodle_database.php 21 Jul 2008 07:18:58 -0000 1.38 +++ moodle_database.php 21 Jul 2008 20:44:04 -0000 @@ -443,6 +443,12 @@ } /** + * Reset a sequence to the id field of a table. + * @return void + */ + public abstract function reset_sequence($table); + + /** * Returns sql generator used for db manipulation. * Used mostly in upgrade.php scripts. * @return object database_manager instance @@ -980,6 +986,16 @@ public abstract function insert_record($table, $dataobject, $returnid=true, $bulk=false); /** + * Import a record into a table (including the id field) and return the "id" field. + * Some conversions and safety checks are carried out. Lobs are supported. + * $dataobject is an object containing needed data + * @param string $table The database table to be inserted into + * @param object $dataobject A data object with values for one or more fields in the record (or null if nothing to import in table $table) + * @return mixed record id or false if record not imported + */ + 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 * @param mixed $params data record as object or array Index: mssql_adodb_moodle_database.php =================================================================== RCS file: /cvsroot/moodle/moodle/lib/dml/mssql_adodb_moodle_database.php,v retrieving revision 1.15 diff -u -r1.15 mssql_adodb_moodle_database.php --- mssql_adodb_moodle_database.php 28 Jun 2008 21:09:10 -0000 1.15 +++ mssql_adodb_moodle_database.php 21 Jul 2008 21:31:16 -0000 @@ -341,4 +341,97 @@ return ($returnid ? $id : true); } + + /** + * Reset a sequence to the id field of a table. + * @return void + */ + public function reset_sequence($table) { + // From http://msdn.microsoft.com/en-us/library/ms176057.aspx + $value = $this->get_field_sql('SELECT MAX(id) FROM {$table}'); + if(!is_numeric($value)) { + $value = 1; + } + $this->change_database_structure("DBCC CHECKIDENT ('$this->prefix$table', RESEED, $value)"); + } + + /** + * Import a record into a table (including the id field) and return the "id" field. + * Some conversions and safety checks are carried out. Lobs are supported. + * $dataobject is an object containing needed data + * @param string $table The database table to be inserted into + * @param object $dataobject A data object with values for one or more fields in the record (or null if nothing to import in table $table) + * @return mixed record id or false if record not imported + */ + public function import_record($table, $dataobject) { + if(is_null($dataobject)) { + return false; + } + $dataobject = (object)$dataobject; + // TODO: rewrite to use insert_record and insert_record_raw + + // begin: insert_record snippet + $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 + } + } else if (is_bool($value)) { + $value = (int)$value; // prevent "false" problems + } else if ($value === '') { + if ($column->meta_type == 'I' || $column->meta_type == 'F' || $column->meta_type == 'N') { + $value = 0; // prevent '' problems in numeric fields + } + } + $cleaned[$field] = $value; + } + + if (empty($cleaned)) { + return false; + } + // end: insert_record snippet + $id = @$cleaned['id']; + if (empty($id)) { + return false; + } + + // begin: insert_record_raw snippet + $this->writes++; + + $fields = implode(',', array_keys($cleaned)); + $qms = array_fill(0, count($cleaned), '?'); + $qms = implode(',', $qms); + + $sql = "INSERT INTO {$this->prefix}$table ($fields) VALUES($qms)"; + + if (!$rs = $this->adodb->Execute($sql, $cleaned)) { + $this->report_error($sql, $cleaned); + return false; + } + // end: insert_record_raw snippet + + // begin: insert_record snippet + foreach ($blobs as $key=>$value) { + $this->writes++; + if (!$this->adodb->UpdateBlob($this->prefix.$table, $key, $value, "id = $id")) { + return false; + } + } + // end: insert_record snippet + + return $id; + } } Index: mysqli_adodb_moodle_database.php =================================================================== RCS file: /cvsroot/moodle/moodle/lib/dml/mysqli_adodb_moodle_database.php,v retrieving revision 1.9 diff -u -r1.9 mysqli_adodb_moodle_database.php --- mysqli_adodb_moodle_database.php 16 Jun 2008 21:01:54 -0000 1.9 +++ mysqli_adodb_moodle_database.php 21 Jul 2008 21:29:24 -0000 @@ -274,4 +274,86 @@ public function sql_regex($positivematch=true) { return $positivematch ? 'REGEXP' : 'NOT REGEXP'; } + + /** + * Reset a sequence to the id field of a table. + * @return void + */ + public function reset_sequence($table) { + // From http://dev.mysql.com/doc/refman/5.0/en/alter-table.html + $value = $this->get_field_sql('SELECT MAX(id) FROM {$table}'); + if(is_numeric($value)) { + ++$value; + } else { + $value = 1; + } + $this->change_database_structure("ALTER TABLE $this->prefix$table AUTO_INCREMENT = $value"); + } + + /** + * Import a record into a table (including the id field) and return the "id" field. + * Some conversions and safety checks are carried out. Lobs are supported. + * $dataobject is an object containing needed data + * @param string $table The database table to be inserted into + * @param object $dataobject A data object with values for one or more fields in the record (or null if nothing to import in table $table) + * @return mixed record id or false if record not imported + */ + public function import_record($table, $dataobject) { + if(is_null($dataobject)) { + return false; + } + $dataobject = (object)$dataobject; + // TODO: rewrite to use insert_record and insert_record_raw + + // begin: insert_record snippet + $columns = $this->get_columns($table); + $cleaned = array(); + + foreach ($dataobject as $field=>$value) { + if (!isset($columns[$field])) { + continue; + } + $column = $columns[$field]; + if (is_bool($value)) { + $value = (int)$value; // prevent "false" problems + } + if (!empty($column->enums)) { + // workaround for problem with wrong enums in mysql + if (is_null($value) and !$column->not_null) { + // ok - nulls allowed + } else { + if (!in_array((string)$value, $column->enums)) { + debugging('Enum value '.s($value).' not allowed in field '.$field.' table '.$table.'.'); + return false; + } + } + } + $cleaned[$field] = $value; + } + + if (empty($cleaned)) { + return false; + } + // end: insert_record snippet + $id = @$cleaned['id']; + if (empty($id)) { + return false; + } + + // begin: insert_record_raw snippet + $this->writes++; + + $fields = implode(',', array_keys($cleaned)); + $qms = array_fill(0, count($cleaned), '?'); + $qms = implode(',', $qms); + + $sql = "INSERT INTO {$this->prefix}$table ($fields) VALUES($qms)"; + + if (!$rs = $this->adodb->Execute($sql, $cleaned)) { + $this->report_error($sql, $cleaned); + return false; + } + // end: insert_record_raw snippet + return $id; + } } Index: oci8po_adodb_moodle_database.php =================================================================== RCS file: /cvsroot/moodle/moodle/lib/dml/oci8po_adodb_moodle_database.php,v retrieving revision 1.16 diff -u -r1.16 oci8po_adodb_moodle_database.php --- oci8po_adodb_moodle_database.php 26 Jun 2008 18:27:22 -0000 1.16 +++ oci8po_adodb_moodle_database.php 21 Jul 2008 21:32:30 -0000 @@ -597,4 +597,140 @@ /// Fail safe to original value return $value; } + + /** + * Reset a sequence to the id field of a table. + * @return void + */ + public function reset_sequence($table) { + // From http://www.acs.ilstu.edu/docs/oracle/server.101/b10759/statements_2011.htm + $value = $this->get_field_sql('SELECT MAX(id) FROM {$table}'); + if(is_numeric($value)) { + ++$value; + } else { + $value = 1; + } + $dbman = $this->get_manager(); + $xmldb_table = new xmldb_table($table); + $this->reads++; + $seqname = $dbman->find_sequence_name($xmldb_table); + if (!$seqname) { + /// Fallback, seqname not found, something is wrong. Inform and use the alternative getNameForObject() method + $generator = $dbman->generator; + $generator->setPrefix($this->getPrefix()); + $seqname = $generator->getNameForObject($table, 'id', 'seq'); + } + + $this->change_database_structure("DROP SEQUENCE $seqname"); + $this->change_database_structure("CREATE SEQUENCE $seqname START WITH $value INCREMENT BY 1 NOMAXVALUE"); + } + + /** + * Import a record into a table (including the id field) and return the "id" field. + * Some conversions and safety checks are carried out. Lobs are supported. + * $dataobject is an object containing needed data + * @param string $table The database table to be inserted into + * @param object $dataobject A data object with values for one or more fields in the record (or null if nothing to import in table $table) + * @return mixed record id or false if record not imported + */ + public function import_record($table, $dataobject) { + if(is_null($dataobject)) { + return false; + } + $dataobject = (object)$dataobject; + // TODO: rewrite to use insert_record and insert_record_raw + + // begin: insert_record snippet + $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) + } + + } else if (is_bool($value)) { + $value = (int)$value; // prevent "false" problems + + } else if ($value === '' || $value === ' ') { + if ($column->meta_type == 'I' or $column->meta_type == 'F' or $column->meta_type == 'N') { + $value = 0; // prevent '' problems in numeric fields + } + } + $cleaned[$field] = $value; + } + + if (empty($cleaned)) { + return false; + } + // end: insert_record snippet + $id = @$cleaned['id']; + if (empty($id)) { + return false; + } + + // begin: insert_record_raw snippet + $fields = implode(',', array_keys($cleaned)); + $qms = array(); + /// Look for 'empty_clob() and empty_blob() params to replace question marks properly + /// Oracle requires those function calls on insert to prepare blob/clob storage, so we + /// specify them as SQL, deleting them from parameters + foreach ($cleaned as $key=>$param) { + if ($param === 'empty_blob()') { + $qms[] = 'empty_blob()'; + unset($cleaned[$key]); + } else if ($param === 'empty_clob()') { + $qms[] = 'empty_clob()'; + unset($cleaned[$key]); + } else { + $qms[] = '?'; + } + } + $qms = implode(',', $qms); + + $sql = "INSERT INTO {$this->prefix}$table ($fields) VALUES($qms)"; + + $this->writes++; + if (!$rs = $this->adodb->Execute($sql, $cleaned)) { + $this->report_error($sql, $cleaned); + return false; + } + // end: insert_record_raw snippet + + // begin: insert_record snippet + 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; + } + } + // end: insert_record snippet + + return $id; + } } Index: pdo_moodle_database.php =================================================================== RCS file: /cvsroot/moodle/moodle/lib/dml/pdo_moodle_database.php,v retrieving revision 1.8 diff -u -r1.8 pdo_moodle_database.php --- pdo_moodle_database.php 13 Jul 2008 20:28:08 -0000 1.8 +++ pdo_moodle_database.php 21 Jul 2008 21:47:52 -0000 @@ -564,4 +564,64 @@ return false; } } + + /** + * Import a record into a table (including the id field) and return the "id" field. + * Some conversions and safety checks are carried out. Lobs are supported. + * $dataobject is an object containing needed data + * @param string $table The database table to be inserted into + * @param object $dataobject A data object with values for one or more fields in the record (or null if nothing to import in table $table) + * @return mixed record id or false if record not imported + */ + public function import_record($table, $dataobject) { + if(is_null($dataobject)) { + return false; + } + $dataobject = (object)$dataobject; + // TODO: rewrite to use insert_record and insert_record_raw + + // begin: insert_record snippet + $columns = $this->get_columns($table); + $cleaned = array(); + + foreach ($dataobject as $field=>$value) { + if (!isset($columns[$field])) { + continue; + } + $column = $columns[$field]; + if (is_bool($value)) { + $value = (int)$value; // prevent "false" problems + } + if (!empty($column->enums)) { + if (!in_array((string)$value, $column->enums)) { + debugging('Enum value '.s($value).' not allowed in field '.$field.' table '.$table.'.'); + return false; + } + } + $cleaned[$field] = $value; + } + + if (empty($cleaned)) { + return false; + } + // end: insert_record snippet + $id = @$cleaned['id']; + if (empty($id)) { + return false; + } + + // begin: insert_record_raw snippet + $this->writes++; + + $fields = implode(',', array_keys($params)); + $qms = array_fill(0, count($params), '?'); + $qms = implode(',', $qms); + + $sql = "INSERT INTO {{$table}} ($fields) VALUES($qms)"; + if (!$this->execute($sql, $params)) { + return false; + } + // end: insert_record_raw snippet + return $id; + } } Index: postgres7_adodb_moodle_database.php =================================================================== RCS file: /cvsroot/moodle/moodle/lib/dml/postgres7_adodb_moodle_database.php,v retrieving revision 1.15 diff -u -r1.15 postgres7_adodb_moodle_database.php --- postgres7_adodb_moodle_database.php 22 Jun 2008 22:53:41 -0000 1.15 +++ postgres7_adodb_moodle_database.php 21 Jul 2008 21:37:54 -0000 @@ -461,4 +461,98 @@ public function sql_regex($positivematch=true) { return $positivematch ? '~*' : '!~*'; } + + /** + * Reset a sequence to the id field of a table. + * @return void + */ + public function reset_sequence($table) { + // From http://www.postgresql.org/docs/7.4/static/sql-altersequence.html + $value = $this->get_field_sql('SELECT MAX(id) FROM {$table}'); + if(is_numeric($value)) { + ++$value; + } else { + $value = 1; + } + $this->change_database_structure("ALTER SEQUENCE $this->prefix{$table}_id_seq RESTART WITH $value"); + } + + /** + * Import a record into a table (including the id field) and return the "id" field. + * Some conversions and safety checks are carried out. Lobs are supported. + * $dataobject is an object containing needed data + * @param string $table The database table to be inserted into + * @param object $dataobject A data object with values for one or more fields in the record (or null if nothing to import in table $table) + * @return mixed record id or false if record not imported + */ + public function import_record($table, $dataobject) { + if(is_null($dataobject)) { + return false; + } + $dataobject = (object)$dataobject; + // TODO: rewrite to use insert_record and insert_record_raw + + // begin: insert_record snippet + //TODO: add support for blobs BYTEA + $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)) { + $cleaned[$field] = null; + } else { + $blobs[$field] = $value; + $cleaned[$field] = '@#BLOB#@'; + } + continue; + } else if (is_bool($value)) { + $value = (int)$value; // prevent false '' problems + } else if ($value === '') { + if ($column->meta_type == 'I' or $column->meta_type == 'F' or $column->meta_type == 'N') { + $value = 0; // prevent '' problems in numeric fields + } + } + $cleaned[$field] = $value; + } + + if (empty($cleaned)) { + return false; + } + // end: insert_record snippet + $id = @$cleaned['id']; + if (empty($id)) { + return false; + } + + // begin: insert_record_raw snippet + $fields = implode(',', array_keys($cleaned)); + $qms = array_fill(0, count($cleaned), '?'); + $qms = implode(',', $qms); + + $sql = "INSERT INTO {$this->prefix}$table ($fields) VALUES($qms)"; + + $this->writes++; + + if (!$rs = $this->adodb->Execute($sql, $cleaned)) { + $this->report_error($sql, $cleaned); + return false; + } + // end: insert_record_raw snippet + + // begin: insert_record snippet + 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; + } + } + // end: insert_record snippet + return $id; + } } Index: sqlite3_pdo_moodle_database.php =================================================================== RCS file: /cvsroot/moodle/moodle/lib/dml/sqlite3_pdo_moodle_database.php,v retrieving revision 1.3 diff -u -r1.3 sqlite3_pdo_moodle_database.php --- sqlite3_pdo_moodle_database.php 13 Jul 2008 10:12:21 -0000 1.3 +++ sqlite3_pdo_moodle_database.php 21 Jul 2008 21:50:44 -0000 @@ -323,4 +323,17 @@ } return implode('||', $elements); } + + /** + * Reset a sequence to the id field of a table. + * @return void + */ + public function reset_sequence($table) { + // From http://sqlite.org/autoinc.html + $value = $this->get_field_sql('SELECT MAX(id) FROM {$table}'); + if(!is_numeric($value)) { + $value = 0; + } + $this->change_database_structure("UPDATE sqlite_sequence SET seq=$value WHERE name='$this->prefix$table'"); + } } \ No newline at end of file