1. drupal
    1. 6
    2. 8
    3. 7
6 drupal_write_record($table, &$object, $update = array())
7 – 8 drupal_write_record($table, &$record, $primary_keys = array())

Saves (inserts or updates) a record to the database based upon the schema.


$table The name of the table; this must be defined by a hook_schema() implementation.

$record An object or array representing the record to write, passed in by reference. If inserting a new record, values not provided in $record will be populated in $record and in the database with the default values from the schema, as well as a single serial (auto-increment) field (if present). If updating an existing record, only provided values are updated in the database, and $record is not modified.

$primary_keys To indicate that this is a new record to be inserted, omit this argument. If this is an update, this argument specifies the primary keys' field names. If there is only 1 field in the key, you may pass in a string; if there are multiple fields in the key, pass in an array.

Return value

If the record insert or update failed, returns FALSE. If it succeeded, returns SAVED_NEW or SAVED_UPDATED, depending on the operation performed.

Related topics

▾ 33 functions call drupal_write_record()

block_theme_initialize in modules/block/block.module
Assign an initial, default set of blocks for a theme.
comment_save in modules/comment/comment.module
Accepts a submission of new or changed comment content.
contact_category_edit_form_submit in modules/contact/contact.admin.inc
Process the contact category edit page form submission.
DrupalDataApiTest::testDrupalWriteRecord in modules/simpletest/tests/common.test
Test the drupal_write_record() API function.
EntityFieldQueryTestCase::setUp in modules/simpletest/tests/entity_query.test
Generates a random database prefix, runs the install scripts on the prefixed database and enable the specified modules. After installation many caches are flushed and the internal browser is setup so that the page requests will run on the new prefix.…
EntityFieldQueryTestCase::testEntityFieldQuery in modules/simpletest/tests/entity_query.test
Tests EntityFieldQuery.
field_create_field in modules/field/field.crud.inc
Creates a field.
field_test_entity_save in modules/field/tests/field_test.entity.inc
Saves a test_entity.
field_update_field in modules/field/field.crud.inc
Updates a field.
FileSpaceUsedTest::setUp in modules/simpletest/tests/file.test
Generates a random database prefix, runs the install scripts on the prefixed database and enable the specified modules. After installation many caches are flushed and the internal browser is setup so that the page requests will run on the new prefix.…
FileTestCase::createFile in modules/simpletest/tests/file.test
Create a file and save it to the files table and assert that it occurs correctly.
file_save in includes/file.inc
Save a file object to the database.
hook_menu_link_insert in modules/system/system.api.php
Inform modules that a menu link has been created.
image_effect_save in modules/image/image.module
Save an image effect.
image_style_save in modules/image/image.module
Save an image style.
locale_date_format_save in includes/locale.inc
Save locale specific date formats to the database.
module_test_enable in modules/simpletest/tests/module_test.install
Implements hook_enable().
module_test_install in modules/simpletest/tests/module_test.install
Implements hook_install().
NodeQueryAlter::testNodeQueryAlterOverride in modules/node/node.test
Lower-level test of 'node_access' query alter override.
node_save in modules/node/node.module
Save changes to a node or add a new node.
path_save in includes/path.inc
Save a path alias to the database.
shortcut_set_save in modules/shortcut/shortcut.module
Saves a shortcut set.
StatisticsReportsTestCase::testPopularContentBlock in modules/statistics/statistics.test
Tests the "popular content" block.
system_date_format_save in modules/system/system.module
Saves a date format to the database.
system_date_format_type_save in modules/system/system.module
Saves a date type to the database.
taxonomy_term_save in modules/taxonomy/taxonomy.module
Saves a term object to the database.
taxonomy_vocabulary_save in modules/taxonomy/taxonomy.module
Saves a vocabulary.
translation_test_node_insert in modules/translation/tests/translation_test.module
Implements hook_node_insert().
user_role_save in modules/user/user.module
Save a user role to the database.
user_save in modules/user/user.module
Save changes to a user account or add a new user.
_block_rehash in modules/block/block.module
Update the 'block' DB table with the blocks currently exported by modules.
_field_write_instance in modules/field/field.crud.inc
Stores an instance record in the field configuration database.
_node_save_revision in modules/node/node.module
Helper function to save a revision with the uid of the current user.


includes/common.inc, line 6775

function drupal_write_record($table, &$record, $primary_keys = array()) {
  // Standardize $primary_keys to an array.
  if (is_string($primary_keys)) {
    $primary_keys = array($primary_keys);

  $schema = drupal_get_schema($table);
  if (empty($schema)) {
    return FALSE;

  $object = (object) $record;
  $fields = array();

  // Go through the schema to determine fields to write.
  foreach ($schema['fields'] as $field => $info) {
    if ($info['type'] == 'serial') {
      // Skip serial types if we are updating.
      if (!empty($primary_keys)) {
      // Track serial field so we can helpfully populate them after the query.
      // NOTE: Each table should come with one serial field only.
      $serial = $field;

    // Skip field if it is in $primary_keys as it is unnecessary to update a
    // field to the value it is already set to.
    if (in_array($field, $primary_keys)) {

    if (!property_exists($object, $field)) {
      // Skip fields that are not provided, default values are already known
      // by the database.

    // Build array of fields to update or insert.
    if (empty($info['serialize'])) {
      $fields[$field] = $object->$field;
    else {
      $fields[$field] = serialize($object->$field);

    // Type cast to proper datatype, except when the value is NULL and the
    // column allows this.
    // MySQL PDO silently casts e.g. FALSE and '' to 0 when inserting the value
    // into an integer column, but PostgreSQL PDO does not. Also type cast NULL
    // when the column does not allow this.
    if (isset($object->$field) || !empty($info['not null'])) {
      if ($info['type'] == 'int' || $info['type'] == 'serial') {
        $fields[$field] = (int) $fields[$field];
      elseif ($info['type'] == 'float') {
        $fields[$field] = (float) $fields[$field];
      else {
        $fields[$field] = (string) $fields[$field];

  if (empty($fields)) {

  // Build the SQL.
  if (empty($primary_keys)) {
    // We are doing an insert.
    $options = array('return' => Database::RETURN_INSERT_ID);
    if (isset($serial) && isset($fields[$serial])) {
      // If the serial column has been explicitly set with an ID, then we don't
      // require the database to return the last insert id.
      if ($fields[$serial]) {
        $options['return'] = Database::RETURN_AFFECTED;
      // If a serial column does exist with no value (i.e. 0) then remove it as
      // the database will insert the correct value for us.
      else {
    $query = db_insert($table, $options)->fields($fields);
    $return = SAVED_NEW;
  else {
    $query = db_update($table)->fields($fields);
    foreach ($primary_keys as $key) {
      $query->condition($key, $object->$key);
    $return = SAVED_UPDATED;

  // Execute the SQL.
  if ($query_return = $query->execute()) {
    if (isset($serial)) {
      // If the database was not told to return the last insert id, it will be
      // because we already know it.
      if (isset($options) && $options['return'] != Database::RETURN_INSERT_ID) {
        $object->$serial = $fields[$serial];
      else {
        $object->$serial = $query_return;
  // If we have a single-field primary key but got no insert ID, the
  // query failed. Note that we explicitly check for FALSE, because
  // a valid update query which doesn't change any values will return
  // zero (0) affected rows.
  elseif ($query_return === FALSE && count($primary_keys) == 1) {
    $return = FALSE;

  // If we are inserting, populate empty fields with default values.
  if (empty($primary_keys)) {
    foreach ($schema['fields'] as $field => $info) {
      if (isset($info['default']) && !property_exists($object, $field)) {
        $object->$field = $info['default'];

  // If we began with an array, convert back.
  if (is_array($record)) {
    $record = (array) $object;

  return $return;