* @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;
* @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.
*/
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
}
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;
+ }
}
$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
* @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();
$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;
+ }
}
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.
protected function get_pdooptions() {
return array(PDO::ATTR_PERSISTENT => $this->dbpersist);
}
-
+
protected function configure_dbconnection() {
///TODO: not needed preconfigure_dbconnection() stuff for PDO drivers?
}
* @return string
*/
public function get_name() {
- return get_string($this->get_dbtype() . '_pdo', 'install');
+ return get_string($this->get_dbtype() . '_pdo', 'install');
}
/**
} catch(PDOException $ex) {}
return $result;
}
-
+
/**
* Returns supported query parameter types
* @return bitmask
protected function allowed_param_types() {
return SQL_PARAMS_QM | SQL_PARAMS_NAMED;
}
-
+
/**
* Returns last error reported by database engine.
*/
}
echo '<hr />';
}
-
+
/**
* Do NOT use in code, to be used by database_manager only!
* @param string $sql query
}
/**
- * 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) {
return false;
}
}
-
+
/**
* Returns the sql statement with clauses to append used to limit a recordset range.
* @param string $sql the SQL statement to limit.
* @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;
}
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.
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
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);
+ }
}
* @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']);
}
}
$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
}
+ 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;
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);
}
}
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){}