<?php

/**
 * @file
 * Install, update and uninstall functions for the field_sql_storage module.
 */

/**
 * Implements hook_schema().
 */
function field_sql_storage_schema() {
  $schema = array();

  // Dynamic (data) tables.
  if (db_table_exists('field_config')) {
    $fields = field_read_fields(array(), array('include_deleted' => TRUE, 'include_inactive' => TRUE));
    drupal_load('module', 'field_sql_storage');
    foreach ($fields as $field) {
      if ($field['storage']['type'] == 'field_sql_storage') {
        $schema += _field_sql_storage_schema($field);
      }
    }
  }
  return $schema;
}

/**
 * Utility function: write field data directly to SQL storage.
 *
 * This function can be used for databases whose schema is at field module
 * version 7000 or higher.
 *
 * @ingroup update_api
 */
function _update_7000_field_sql_storage_write($entity_type, $bundle, $entity_id, $revision_id, $field_name, $data) {
  $table_name = "field_data_{$field_name}";
  $revision_name = "field_revision_{$field_name}";

  db_delete($table_name)
    ->condition('entity_type', $entity_type)
    ->condition('entity_id', $entity_id)
    ->execute();
  db_delete($revision_name)
    ->condition('entity_type', $entity_type)
    ->condition('entity_id', $entity_id)
    ->condition('revision_id', $revision_id)
    ->execute();

  $columns = array();
  foreach ($data as $langcode => $items) {
    foreach ($items as $delta => $item) {
      $record = array(
        'entity_type' => $entity_type,
        'entity_id' => $entity_id,
        'revision_id' => $revision_id,
        'bundle' => $bundle,
        'delta' => $delta,
        'language' => $langcode,
      );
      foreach ($item as $column => $value) {
        $record[_field_sql_storage_columnname($field_name, $column)] = $value;
      }

      $records[] = $record;
      // Record the columns used.
      $columns += $record;
    }
  }

  if ($columns) {
    $query = db_insert($table_name)->fields(array_keys($columns));
    $revision_query = db_insert($revision_name)->fields(array_keys($columns));
    foreach ($records as $record) {
      $query->values($record);
      if ($revision_id) {
        $revision_query->values($record);
      }
    }
    $query->execute();
    $revision_query->execute();
  }
}

/**
 * @addtogroup updates-6.x-to-7.x
 * @{
 */

/**
 * Field SQL storage update version placeholder.
 */
function field_sql_storage_update_7000() {
  // Some update helper functions (such as
  // _update_7000_field_sql_storage_write()) modify the database directly. They
  // can be used safely only if the database schema matches the field module
  // schema established for Drupal 7.0 (i.e. version 7000). This function exists
  // solely to set the schema version to 7000, so that update functions calling
  // those helpers can do so safely by declaring a dependency on
  // field_sql_storage_update_7000().
}

/**
 * Remove the field_config_entity_type table and store 'entity_type' strings.
 */
function field_sql_storage_update_7001(&$sandbox) {
  if (!isset($sandbox['progress'])) {
    // Collect current etids.
    $sandbox['etids'] = db_query('SELECT etid, type FROM {field_config_entity_type}')->fetchAllKeyed();

    // Collect affected tables: field data, field revision data, 'deleted'
    // tables.
    $sandbox['tables'] = array();
    $results = db_select('field_config', 'fc', array('fetch' => PDO::FETCH_ASSOC))
      ->fields('fc')
      ->condition('storage_module', 'field_sql_storage')
      ->execute();
    foreach ($results as $field) {
      if ($field['deleted']) {
        $sandbox['tables']["field_deleted_data_{$field['id']}"] = 'data';
        $sandbox['tables']["field_deleted_revision_{$field['id']}"] = 'revision';
      }
      else {
        $sandbox['tables']["field_data_{$field['field_name']}"] = 'data';
        $sandbox['tables']["field_revision_{$field['field_name']}"] = 'revision';
      }
    }
    reset($sandbox['tables']);

    $sandbox['total'] = count($sandbox['tables']);
    $sandbox['progress'] = 0;
  }

  if ($sandbox['tables']) {
    // Grab the next table to process.
    $table = key($sandbox['tables']);
    $type = array_shift($sandbox['tables']);

    if (db_table_exists($table)) {
      // Add the 'entity_type' column.
      if (!db_field_exists($table, 'entity_type')) {
        $column = array(
          'type' => 'varchar',
          'length' => 128,
          'not null' => TRUE,
          'default' => '',
          'description' => 'The entity type this data is attached to.',
        );
        db_add_field($table, 'entity_type', $column);

        // Populate the 'entity_type' column based on the 'etid' column.
        foreach ($sandbox['etids'] as $etid => $entity_type) {
          db_update($table)
            ->fields(array('entity_type' => $entity_type))
            ->condition('etid', $etid)
            ->execute();
        }

        // Index the new column.
        db_add_index($table, 'entity_type', array('entity_type'));
      }

      // Use the 'entity_type' column in the primary key.
      db_drop_primary_key($table);
      $primary_keys = array(
        'data' => array('entity_type', 'entity_id', 'deleted', 'delta', 'language'),
        'revision' => array('entity_type', 'entity_id', 'revision_id', 'deleted', 'delta', 'language'),
      );
      db_add_primary_key($table, $primary_keys[$type]);

      // Drop the 'etid' column.
      if (db_field_exists($table, 'etid')) {
        db_drop_field($table, 'etid');
      }
    }

    // Report progress.
    $sandbox['progress']++;
    $sandbox['#finished'] = min(0.99, $sandbox['progress'] / $sandbox['total']);
  }
  else {
    // No more tables left: drop the field_config_entity_type table.
    db_drop_table('field_config_entity_type');

    // Drop the previous 'field_sql_storage_ENTITYTYPE_etid' system variables.
    foreach ($sandbox['etids'] as $etid => $entity_type) {
      variable_del('field_sql_storage_' . $entity_type . '_etid');
    }

    // We're done.
    $sandbox['#finished'] = 1;
  }
}

/**
 * Fix primary keys in field revision data tables.
 */
function field_sql_storage_update_7002() {
  $results = db_select('field_config', 'fc', array('fetch' => PDO::FETCH_ASSOC))
    ->fields('fc')
    ->condition('storage_module', 'field_sql_storage')
    ->execute();
  foreach ($results as $field) {
    // Revision tables of deleted fields do not need to be fixed, since no new
    // data is written to them.
    if (!$field['deleted']) {
      $table = "field_revision_{$field['field_name']}";
      db_drop_primary_key($table);
      db_add_primary_key($table, array('entity_type', 'entity_id', 'revision_id', 'deleted', 'delta', 'language'));
    }
  }
}

/**
 * @} End of "addtogroup updates-6.x-to-7.x".
 */
