<?php

function tripal_chado_install() {
  if (chado_is_installed()) {
    // For an upgraded site we need to move some vocabulary terms over
    // to the new 'local' vocabulary:
    chado_insert_db(array(
      'name' => 'local',
      'description' => variable_get('site_name', 'This site.'),
    ));

    // Move the library properties out of the tripal database and into the
    // local database.
    $sql = "
      UPDATE {dbxref}
        SET db_id = (SELECT db_id FROM {db} WHERE name = 'local')
      WHERE dbxref_id IN (
        SELECT DISTINCT CVT.dbxref_id
        FROM {cvterm} CVT
          INNER JOIN {cv} CV ON CV.cv_id = CVT.cv_id
        WHERE CV.name IN (
          'library_property',
          'library_type',
          'project_property',
          'nd_experiment_types',
          'nd_geolocation_property',
          'tripal_analysis'
        )
      )
    ";
    chado_query($sql);

    // Fix the SOFP feature_property issue from the legacy feature_property.
    tripal_chado_fix_legacy_SOFP_7338();

  }

  tripal_insert_variable('bundle_category', 'Bundles can be categorized to allow for grouping');
}

/**
 * Implementation of hook_uninstall().
 *
 * @ingroup tripal
 */
function tripal_chado_uninstall() {

//   // Drop the foreign key between tripal_custom_tables and tripal_mviews
//   // so that Drupal can then drop the tables
//   db_query('
//     ALTER TABLE {tripal_custom_tables}
//     DROP CONSTRAINT tripal_custom_tables_fk1 CASCADE
//   ');

  variable_set('tripal_chado_is_prepared', FALSE);
}

function tripal_chado_chado_semweb_schema(){
  return array(
    'fields' => array(
      'chado_semweb_id' => array(
        'type' => 'serial',
        'not null' => TRUE
      ),
      'chado_table' => array(
        'type' => 'varchar',
        'length ' => 128,
        'not null' => TRUE
      ),
      'chado_column' => array(
        'type' => 'text',
        'length ' => 128,
        'not null' => TRUE
      ),
      'cvterm_id' => array(
        'type' => 'int',
      ),
    ),
    'primary key' => array(
      0 => 'chado_semweb_id',
    ),
    'indexes' => array(
      'chado_semweb_id_idx1' => array('cvterm_id'),
      'chado_semweb_id_idx2' => array('chado_column'),
      'chado_semweb_id_idx3' => array('chado_table'),
    ),
    'unique keys' => array(
      'chado_semweb_uq1' => array('chado_table', 'chado_column'),
    ),
  );
}

/**
 * Table definition for the tripal_cv_obo table
 * @param $schema
 */
function tripal_chado_tripal_cv_obo_schema() {
  return array(
    'fields' => array(
      'obo_id' => array(
        'type' => 'serial',
        'unsigned' => TRUE,
        'not null' => TRUE
      ),
      'name' => array(
        'type' => 'varchar',
        'length' => 255
      ),
      'path'  => array(
        'type' => 'varchar',
        'length' => 1024
      ),
    ),
    'indexes' => array(
      'tripal_cv_obo_idx1' => array('obo_id'),
    ),
    'primary key' => array('obo_id'),
  );
}

/**
 *
 */
function tripal_chado_enable() {
  // If Tripal v2 is already installed, then when the module is first enabled
  // after an upgade, the installation of this module will try and recreate
  // some of the tables created with tripal_core and the installation will fail.
  // Therefore, the tables were temporarily moved out of the way to preserve
  // the data. Now we'll move them back.
  tripal_chado_upgrade_v2_v3_enable();
}

/**
 * Implements hook_schema().
 */
function tripal_chado_schema() {

  // If Tripal v2 is already installed, then when the module is first enabled
  // after an upgade, the installation of this module will try and recreate
  // some of the tables created with tripal_core and the installation will fail.
  // Therefore, we need to temporarily move those tables out of the way, let
  // the module install and then move them back.
  $migrated = variable_get('tripal_v2_upgrade_v3_check_chado', FALSE);
  if (!$migrated) {
    try {
      tripal_chado_upgrade_v2_v3_pre_enable();
      variable_set('tripal_v2_upgrade_v3_check_chado', TRUE);
    }
    catch(Exception $e) {
      watchdog_exception('tripal_chado', $e);
    }
  }

  // Links TripalEntity entities to the chado record.
  $schema['chado_bundle'] = tripal_chado_chado_bundle_schema();
  $schema['chado_semweb'] = tripal_chado_chado_semweb_schema();

  $schema['tripal_mviews'] = tripal_chado_tripal_mviews_schema();
  $schema['tripal_custom_tables'] = tripal_chado_tripal_custom_tables_schema();

  $schema['tripal_cv_obo'] = tripal_chado_tripal_cv_obo_schema();
  $schema['tripal_pub_import'] = tripal_chado_tripal_pub_import_schema();


  // if this module is already installed and enabled, then we want to provide
  // the schemas for all of the custom tables.  This will allow Views to
  // see the schemas.  We check if the module is installed because during
  // installation we don't want to make these custom tables available as we don't
  // want them created in the Drupal database.  The custom tables go in the
  // Chado database.
  if (db_table_exists('tripal_custom_tables')) {
    $sql = 'SELECT * FROM {tripal_custom_tables}';
    $results = db_query($sql);
    foreach ($results as $custom) {
      $schema[$custom->table_name] = unserialize($custom->schema);
    }
  }

  // Map cvterm usage to chado tables
  $schema['chado_cvterm_mapping'] = tripal_chado_chado_cvterm_mapping_schema();

  // When a chado Tripal content type is created, a linking table is also created to
  // link the entity to it's record in chado (@see tripal_chado_bundle_create() ).
  // This table is created via db_create_table() but in order to expose it to
  // the Drupal Schema API, we also need to define each one here.
  if (db_table_exists('chado_bundle')) {
    $resource = db_query('SELECT tb.name FROM chado_bundle cb LEFT JOIN tripal_bundle tb ON tb.id=cb.bundle_id');
    foreach ($resource as $r) {
      $bundle_name = $r->name;
      // This makes an assumption about the name of the linking table.
      // @todo: Switch to chado_get_bundle_entity_table($bundle).
      $chado_entity_table = 'chado_' . $bundle_name;
      $schema[$chado_entity_table] = array(
        'description' => 'The linker table that associates TripalEntities with Chado records for entities of type ' . $bundle_name . '.',
        'fields' => array(
          'mapping_id' => array(
            'type' => 'serial',
            'not null' => TRUE
          ),
          'entity_id' => array(
            'description' => 'The unique entity id.',
            'type' => 'int',
            'not null' => TRUE,
          ),
          'record_id' => array(
            'description' => 'The unique numerical identifier for the record that this entity is associated with (e.g. feature_id, stock_id, library_id, etc.).',
            'type' => 'int',
            'not null' => TRUE,
          ),
          'nid' => array(
            'description' => 'Optional. For linking nid to the entity when migrating Tripal v2 content',
            'type' => 'int',
          )
        ),
        'primary key' => array(
          'mapping_id',
        ),
        'indexes' => array(
          'record_id' => array('record_id'),
          'entity_id' => array('entity_id'),
          'nid' => array('nid'),
        ),
        'unique keys' => array(
          'table_record' => array('record_id'),
          'entity_id' => array('entity_id'),
        ),
      );
    }
  }

  return $schema;
}


/**
 * This function should be executed only one time during upgrade of v2 to v3.
 */
function tripal_chado_upgrade_v2_v3_pre_enable() {
  // If Tripal v2 is already installed, then when the module is first enabled
  // after an upgade, the installation of this module will try and recreate
  // some of the tables created with tripal_core and the installation will fail.
  // Therefore, we need to temporarily move those tables out of the way, let
  // the module install and then move them back.

  if (db_table_exists('tripal_mviews')) {
    // Move the tripal_mviews table out of the way.
    $sql = "ALTER TABLE tripal_mviews RENAME TO tripal_mviews2";
    db_query($sql);
    if (db_query("SELECT 1 FROM pg_indexes WHERE indexname = 'tripal_mviews_mv_name_key'")->fetchField()) {
      $sql = "ALTER INDEX tripal_mviews_mv_name_key RENAME TO tripal_mviews_mv_name_key2";
    }
    else {
      $sql = "CREATE UNIQUE INDEX tripal_mviews_mv_name_key2 ON tripal_mviews2 USING btree (name)";
    }
    db_query($sql);
    if (db_query("SELECT 1 FROM pg_indexes WHERE indexname = 'tripal_mviews_mv_table_key'")->fetchField()) {
      $sql = "ALTER INDEX tripal_mviews_mv_table_key RENAME TO tripal_mviews_mv_table_key2";
    }
    else {
      $sql = "CREATE UNIQUE INDEX tripal_mviews_mv_table_key2 ON tripal_mviews2 USING btree (mv_table)";
    }
    db_query($sql);
    if (db_query("SELECT 1 FROM pg_indexes WHERE indexname = 'tripal_mviews_mview_id_idx'")->fetchField()) {
      $sql = "ALTER INDEX tripal_mviews_mview_id_idx RENAME TO tripal_mviews_mview_id_idx2";
    }
    else {
      $sql = "CREATE INDEX tripal_mviews_mview_id_idx2 ON tripal_mviews2 USING btree (mview_id)";
    }
    db_query($sql);
    if (db_query("SELECT 1 FROM pg_indexes WHERE indexname = 'tripal_mviews_pkey'")->fetchField()) {
      $sql = "ALTER INDEX tripal_mviews_pkey RENAME TO tripal_mviews_pkey2";
    }
    else {
      $sql = "CREATE UNIQUE INDEX tripal_mviews_pkey2 ON tripal_mviews2 USING btree (mview_id)";
    }
    db_query($sql);
  }

  if (db_table_exists('tripal_custom_tables')) {
    // Move the tripal_custom_tables table out of the way.
    $sql = "ALTER TABLE tripal_custom_tables RENAME TO tripal_custom_tables2";
    db_query($sql);
    if (db_query("SELECT 1 FROM pg_indexes WHERE indexname = 'tripal_custom_tables_pkey'")->fetchField()) {
      $sql = "ALTER INDEX tripal_custom_tables_pkey RENAME TO tripal_custom_tables_pkey2";
    }
    else {
      $sql = "CREATE UNIQUE INDEX tripal_custom_tables_pkey2 ON tripal_custom_tables2 USING btree (table_id)";
    }
    db_query($sql);
    if (db_query("SELECT 1 FROM pg_indexes WHERE indexname = 'tripal_custom_tables_table_id_idx'")->fetchField()) {
      $sql = "ALTER INDEX tripal_custom_tables_table_id_idx RENAME TO tripal_custom_tables_table_id_idx2";
    }
    else {
      $sql = "CREATE INDEX tripal_custom_tables_table_id_idx2 ON tripal_custom_tables2 USING btree (table_id)";
    }
    db_query($sql);
  }

  if (db_table_exists('tripal_cv_obo')) {
    // Move the tripal_cv_obo table out of the way.
    $sql = "ALTER TABLE tripal_cv_obo RENAME TO tripal_cv_obo2";
    db_query($sql);
    if (db_query("SELECT 1 FROM pg_indexes WHERE indexname = 'tripal_cv_obo_obo_id_idx'")->fetchField()) {
      $sql = "ALTER INDEX tripal_cv_obo_obo_id_idx RENAME TO tripal_cv_obo_obo_id_idx2";
    }
    else if (db_query("SELECT 1 FROM pg_indexes WHERE indexname = 'tripal_cv_obo_tripal_cv_obo_idx1_idx'")->fetchField()) {
      $sql = "ALTER INDEX tripal_cv_obo_tripal_cv_obo_idx1_idx RENAME TO tripal_cv_obo_obo_id_idx2";
    }
    else {
      $sql = "CREATE INDEX tripal_cv_obo_obo_id_idx2 ON tripal_cv_obo2 USING btree (obo_id)";
    }
    db_query($sql);
    if (db_query("SELECT 1 FROM pg_indexes WHERE indexname = 'tripal_cv_obo_pkey'")->fetchField()) {
      $sql = "ALTER INDEX tripal_cv_obo_pkey RENAME TO tripal_cv_obo_pkey2";
    }
    else {
      $sql = "CREATE UNIQUE INDEX tripal_cv_obo_pkey2 ON tripal_cv_obo2 USING btree (obo_id)";
    }
    db_query($sql);
  }

  if (db_table_exists('tripal_pub_import')) {
    // Move the tripal_pub_import table out of the way.
    $sql = "ALTER TABLE tripal_pub_import RENAME TO tripal_pub_import2";
    db_query($sql);
    if (db_query("SELECT 1 FROM pg_indexes WHERE indexname = 'tripal_pub_import_name_idx'")->fetchField()) {
      $sql = "ALTER INDEX tripal_pub_import_name_idx RENAME TO tripal_pub_import_name_idx2";
    }
    else {
      $sql = "CREATE INDEX tripal_pub_import_name_idx2 ON tripal_pub_import2 USING btree (name)";
    }
    db_query($sql);
    if (db_query("SELECT 1 FROM pg_indexes WHERE indexname = 'tripal_pub_import_pkey'")->fetchField()) {
      $sql = "ALTER INDEX tripal_pub_import_pkey RENAME TO tripal_pub_import_pkey2";
    }
    else {
      $sql = "CREATE UNIQUE INDEX tripal_pub_import_pkey2 ON tripal_pub_import2 USING btree (pub_import_id)";
    }
    db_query($sql);
  }
}
/**
 * This function should be executed only one time during upgrade of v2 to v3.
 */
function tripal_chado_upgrade_v2_v3_enable() {
  // If Tripal v2 is already installed, the installation of this module
  // will try and recreate some of the tables created with tripal_core and the
  // installation will fail.  Therefore, in the install we renamed it. Now
  // we want to move it back.
  if (db_table_exists('tripal_mviews2')) {
    // tripal_mviews
    $sql = "DROP TABLE tripal_mviews";
    db_query($sql);
    $sql = "ALTER TABLE tripal_mviews2 RENAME to tripal_mviews";
    db_query($sql);
    $sql = "ALTER INDEX tripal_mviews_mv_name_key2 RENAME TO tripal_mviews_mv_name_key";
    db_query($sql);
    $sql = "ALTER INDEX tripal_mviews_mv_table_key2 RENAME TO tripal_mviews_mv_table_key";
    db_query($sql);
    $sql = "ALTER INDEX tripal_mviews_mview_id_idx2 RENAME TO tripal_mviews_mview_id_idx";
    db_query($sql);
    $sql = "ALTER INDEX tripal_mviews_pkey2 RENAME TO tripal_mviews_pkey";
    db_query($sql);
  }

  // tripal_custom_tables
  if (db_table_exists('tripal_custom_tables2')) {
    $sql = "DROP TABLE tripal_custom_tables";
    db_query($sql);
    $sql = "ALTER TABLE tripal_custom_tables2 RENAME to tripal_custom_tables";
    db_query($sql);
    $sql = "ALTER INDEX tripal_custom_tables_pkey2 RENAME TO tripal_custom_tables_pkey";
    db_query($sql);
    $sql = "ALTER INDEX tripal_custom_tables_table_id_idx2 RENAME TO tripal_custom_tables_table_id_idx";
    db_query($sql);
  }

  // tripal_cv_obo
  if (db_table_exists('tripal_cv_obo2')) {
    $sql = "DROP TABLE tripal_cv_obo";
    db_query($sql);
    $sql = "ALTER TABLE tripal_cv_obo2 RENAME to tripal_cv_obo";
    db_query($sql);
    $sql = "ALTER INDEX tripal_cv_obo_obo_id_idx2 RENAME TO tripal_cv_obo_obo_id_idx";
    db_query($sql);
    if (db_query("SELECT 1 FROM pg_indexes WHERE indexname = 'tripal_cv_obo_pkey2'")->fetchField()) {
      $sql = "ALTER INDEX tripal_cv_obo_pkey2 RENAME TO tripal_cv_obo_pkey";
    }
    db_query($sql);
  }

  // tripal_pub_import
  if (db_table_exists('tripal_pub_import2')) {
    $sql = "DROP TABLE tripal_pub_import";
    db_query($sql);
    $sql = "ALTER TABLE tripal_pub_import2 RENAME to tripal_pub_import";
    db_query($sql);
    $sql = "ALTER INDEX tripal_pub_import_name_idx2 RENAME TO tripal_pub_import_name_idx";
    db_query($sql);
    $sql = "ALTER INDEX tripal_pub_import_pkey2 RENAME TO tripal_pub_import_pkey";
    db_query($sql);
  }
}
/**
 * @section
 * Schema Definitions.
 */
/**
 * Implementation of hook_schema().
 *
 * @ingroup tripal_pub
 */
function tripal_chado_tripal_pub_import_schema() {

  return array(
    'fields' => array(
      'pub_import_id' => array(
        'type' => 'serial',
        'not null' => TRUE
      ),
      'name' => array(
        'type' => 'varchar',
        'length' => 255,
        'not null' => TRUE
      ),
      'criteria' => array(
        'type' => 'text',
        'size' => 'normal',
        'not null' => TRUE,
        'description' => 'Contains a serialized PHP array containing the search criteria'
      ),
      'disabled'  => array(
        'type' => 'int',
        'unsigned' => TRUE,
        'not NULL' => TRUE,
        'default' => 0
      ),
      'do_contact'  => array(
        'type' => 'int',
        'unsigned' => TRUE,
        'not NULL' => TRUE,
        'default' => 0
      ),
    ),
    'primary key' => array('pub_import_id'),
    'indexes' => array(
      'name' => array('name')
    ),
  );
}
/**
 * Describes the Tripal Custom Tables (tripal_custom_tables) table
 * This keeps track of tables created by Tripal and stored in chado that may or may not
 * also be materialized views.
 *
 * @ingroup tripal
 */
function tripal_chado_tripal_custom_tables_schema() {
  return array(
    'fields' => array(
      'table_id' => array(
        'type' => 'serial',
        'unsigned' => TRUE,
        'not NULL' => TRUE
      ),
      'table_name' => array(
        'type' => 'varchar',
        'length' => 255,
        'not NULL' => TRUE
      ),
      'schema' => array(
        'type' => 'text',
        'not NULL' => TRUE
      ),
      'mview_id' => array(
        'type' => 'int',
        'not NULL' => FALSE
      )
    ),
    'indexes' => array(
      'table_id' => array('table_id'),
    ),
    'primary key' => array('table_id'),
    'foreign keys' => array(
      'tripal_mviews' => array(
        'table' => 'tripal_mviews',
        'columns' => array(
          'mview_id' => 'mview_id'
        ),
      ),
    ),
  );
}
/**
 * Describes the Tripal Materialized View (tripal_mviews) table
 * This table keeps track of all materialized views created by Tripal and stored in chado
 *
 * @ingroup tripal
 */
function tripal_chado_tripal_mviews_schema() {
  return array(
    'fields' => array(
      'mview_id' => array(
        'type' => 'serial',
        'unsigned' => TRUE,
        'not NULL' => TRUE
      ),
      'name' => array(
        'type' => 'varchar',
        'length' => 255,
        'not NULL' => TRUE
      ),
      'modulename' => array(
        'type' => 'varchar',
        'length' => 50,
        'not NULL' => TRUE,
        'description' => 'The module name that provides the callback for this job'
      ),
      'mv_table' => array(
        'type' => 'varchar',
        'length' => 128,
        'not NULL' => FALSE
      ),
      'mv_specs' => array(
        'type' => 'text',
        'size' => 'normal',
        'not NULL' => FALSE
      ),
      'mv_schema' => array(
        'type' => 'text',
        'size' => 'normal',
        'not NULL' => FALSE
      ),
      'indexed' => array(
        'type' => 'text',
        'size' => 'normal',
        'not NULL' => FALSE
      ),
      'query' => array(
        'type' => 'text',
        'size' => 'normal',
        'not NULL' => TRUE
      ),
      'special_index' => array(
        'type' => 'text',
        'size' => 'normal',
        'not NULL' => FALSE
      ),
      'last_update' => array(
        'type' => 'int',
        'not NULL' => FALSE,
        'description' => 'UNIX integer time'
      ),
      'status'        => array(
        'type' => 'text',
        'size' => 'normal',
        'not NULL' => FALSE
      ),
      'comment' => array(
        'type' => 'text',
        'size' => 'normal',
        'not NULL' => FALSE
      ),
    ),
    'indexes' => array(
      'mview_id' => array('mview_id')
    ),
    'unique keys' => array(
      'mv_table' => array('mv_table'),
      'mv_name' => array('name'),
    ),
    'primary key' => array('mview_id'),
  );
}

/**
 * Links Biological Data Entities to the chado "base" table the data is stored in.
 * This is where we would specify that a particular gene maps to the record in the
 * chado.feature table with a feature_id=2432;
 */
function tripal_chado_chado_bundle_schema() {

  $schema = array(
    'description' => 'Describes how a bundle maps data to Chado',
    'fields' => array(
      'chado_bundle_id' => array(
        'description' => 'The primary identifier for this table.',
        'type' => 'serial',
        'unsigned' => TRUE,
        'not null' => TRUE,
      ),
      'bundle_id' => array(
        'description' => 'The unique entity id.',
        'type' => 'int',
        'not null' => TRUE,
      ),
      'data_table' => array(
        'description' => 'The table in Chado that this term services (e.g. feature, stock, library, etc.)',
        'type' => 'varchar',
        'length' => 128,
        'not null' => TRUE,
        'default' => '',
      ),
      'type_linker_table' => array(
        'description' => 'If a linker table (e.g. cvterm/prop) is needed to uniquely identify a content type then that table name is provided here.',
        'type' => 'varchar',
        'length' => 128,
        'not null' => FALSE,
        'default' => '',
      ),
      'type_column' => array(
        'description' => 'The column in the data table or linker table that distinguishes the data type. This must be in a foreign key relationship to the cvterm table.',
        'type' => 'varchar',
        'length' => 128,
        'not null' => FALSE,
        'default' => '',
      ),
      'type_id' => array(
        'description' => 'If a type_column is set then this is the cvterm_id of the data type that this bundle maps to.',
        'size' => 'big',
        'type' => 'int',
      ),
      'type_value' => array(
        'description' => 'If a property table is used for a linker, then the value that should be matched to identify this content type is stored here.',
        'type' => 'text',
        'not null' => FALSE,
        'default' => '',
      ),
      'base_type_id' => array(
        'description' => 'If a property table is used for a linker, and if the base table requires a type_id then this is the type that should be used on insert of new records in the base table.',
        'size' => 'big',
        'type' => 'int',
      )
    ),
    'indexes' => array(
      'bundle_id' => array('bundle_id'),
      'data_table' => array('data_table'),
    ),
    'unique keys' => array(
      'record' => array('bundle_id'),
    ),
    'primary key' => array('chado_bundle_id'),
  );
  return $schema;
}

/**
 * Tripal cvterm mapping schema
 * Map cvterms to chado tables that use them
 */
function tripal_chado_chado_cvterm_mapping_schema() {

  $schema = array (
    'table' => 'chado_cvterm_mapping',
    'fields' => array (
      'mapping_id' => array(
        'type' => 'serial',
        'not null' => TRUE
      ),
      'cvterm_id' => array (
        'type' => 'int',
        'not null' => TRUE
      ),
      'chado_table' => array (
        'type' => 'varchar',
        'length' => 128,
        'not null' => TRUE
      ),
      'chado_field' => array (
        'type' => 'varchar',
        'length' => 128,
        'not null' => FALSE
      ),
    ),
    'primary key' => array (
      0 => 'mapping_id'
    ),
    'unique key' => array(
      'cvterm_id',
    ),
    'indexes' => array(
      'tripal_cvterm2table_idx1' => array('cvterm_id'),
      'tripal_cvterm2table_idx2' => array('chado_table'),
      'tripal_cvterm2table_idx3' => array('chado_table', 'chado_field'),
    ),
  );
  return $schema;
}



/**
 * Fixes a problem with the legacy feature_property/SOFP
 * ontology loaded with previous verions of Chado and all terms are
 * relationships.
 *
 * This function is called by the tripal_chado_install() for a
 * new Tripal setup, and the tripal_chado_update_7338 for an existing
 * site.
 */

function tripal_chado_fix_legacy_SOFP_7338() {

  $sofp =  chado_get_db(['name' => 'SOFP']);
  $fp = chado_get_cv(['name' => 'feature_property']);

  // No need to update unless the SOFP db exists
  if (!$sofp || !$fp) {
    return;
  }
  $terms = chado_select_record('cvterm', ['cvterm_id', 'name'], [
    'dbxref_id' => [
      'db_id' => [
        'name' => 'SOFP',
      ],
    ],
    'cv_id' => ['name' => 'feature_property'],
  ]);

  if (empty($terms)) {
    return;
  }

  foreach ($terms as $term) {

    $id = $term->cvterm_id;
    $name = $term->name;

    if ($name == 'linked_to') {
      continue;
    }
    chado_update_record('cvterm', ['cvterm_id' => $id], ['is_relationshiptype' => 0]);
  }

  // Repopulate the mview.
  $mview_id = chado_get_mview_id('db2cv_mview');
  global $user;
  tripal_add_job(
    'Repopulating db2cv to fix legacy SOFP',
    'tripal_chado',
    'chado_populate_mview',
    [$mview_id],
    $user->uid
  );
}

/**
 * Fixes the phase on the tripal_gffcds_temp table used for importing GFF files, and fixes the db.name term mapping.
 *
 */
function tripal_chado_update_7300() {
  try {
    if (chado_table_exists('tripal_gffcds_temp')) {
      chado_query("ALTER TABLE {tripal_gffcds_temp} ALTER COLUMN phase DROP NOT NULL;");
    }

    $term = chado_insert_cvterm(array(
      'id' => 'data:1048',
      'name' => 'Database ID',
      'cv_name' => 'EDAM',
      'definition' => 'An identifier of a biological or bioinformatics database.',
    ));
    chado_associate_semweb_term('db', 'name', $term);
  }
  catch (\PDOException $e) {
    $error = $e->getMessage();
    throw new DrupalUpdateException('Could not fix phase on tripal_gffcds_temp table: '. $error);
  }
}

/**
 * Divides chado_entity table for better integration with views.
 */
function tripal_chado_update_7301() {

  module_load_include('inc', 'tripal_chado', 'includes/tripal_chado.bundle');
  try {
    $transaction = db_transaction();
    $query = db_select('chado_bundle', 'CB');
    $query->join('tripal_bundle', 'TB', 'TB.id = CB.bundle_id');
    $query->fields('CB', array('data_table'));
    $query->fields('TB', array('name'));
    $cbundles = $query->execute();

    // If the table for the bundle doesn't exist then create one, and then
    // move all of the records from the chado_entity table to it.
    while($cbundle = $cbundles->fetchObject()) {
      $cbundle_table = chado_get_bundle_entity_table($cbundle);

      if (!db_table_exists($cbundle_table)) {
        // Create the bundle table.
        tripal_chado_create_bundle_table($cbundle);

        // Now move the records over.
        $sql = "
          INSERT INTO {$cbundle_table} (entity_id, record_id, nid)
           SELECT CE.entity_id, CE.record_id, CE.nid
            FROM {chado_entity} CE
              INNER JOIN {tripal_entity} TE ON CE.entity_id = TE.id
            WHERE TE.bundle = :bundle
        ";
        db_query($sql, array(':bundle' => $cbundle->name));
      }
    }

    // Now remove the chado_entity table.
    db_drop_table('chado_entity');
  }
  catch (\PDOException $e) {
    $transaction->rollback();
    $error = $e->getMessage();
    throw new DrupalUpdateException('Could not perform update: '. $error);
  }
}

/**
 * Corrections to the EDAM database.
 */
function tripal_chado_update_7302(){
  try {
    // Add the term for the field.
    chado_insert_db(array(
      'name' => 'format',
      'description' => 'A defined way or layout of representing and structuring data in a computer file, blob, string, message, or elsewhere. The main focus in EDAM lies on formats as means of structuring data exchanged between different tools or resources. ',
      'url' => 'http://edamontology.org/page',
      'urlprefix' => 'http://edamontology.org/{db}_{accession}',
    ));
    chado_insert_db(array(
      'name' => 'operation',
      'description' => 'A function that processes a set of inputs and results in a set of outputs, or associates arguments (inputs) with values (outputs). Special cases are: a) An operation that consumes no input (has no input arguments).',
      'url' => 'http://edamontology.org/page',
      'urlprefix' => 'http://edamontology.org/{db}_{accession}',
    ));
    chado_insert_db(array(
      'name' => 'topic',
      'description' => 'A category denoting a rather broad domain or field of interest, of study, application, work, data, or technology. Topics have no clearly defined borders between each other.',
      'url' => 'http://edamontology.org/page',
      'urlprefix' => 'http://edamontology.org/{db}_{accession}',
    ));
    chado_insert_cv(
      'EDAM',
      'EDAM is an ontology of well established, familiar concepts that are prevalent within bioinformatics, including types of data and data identifiers, data formats, operations and topics. EDAM is a simple ontology - essentially a set of terms with synonyms and definitions - organised into an intuitive hierarchy for convenient use by curators, software developers and end-users. EDAM is suitable for large-scale semantic annotations and categorization of diverse bioinformatics resources. EDAM is also suitable for diverse application including for example within workbenches and workflow-management systems, software distributions, and resource registries.'
    );
  }
  catch (\PDOException $e) {
    $transaction->rollback();
    $error = $e->getMessage();
    throw new DrupalUpdateException('Could not perform update: '. $error);
  }
}

/**
 * Fixes inconsistency with Chado v1.3 update if was applied.
 */
function tripal_chado_update_7303() {
  try {
    $chado_version = chado_get_version();
    if ($chado_version == '1.3') {
      module_load_include('inc', 'tripal_chado', 'includes/setup/tripal_chado.setup');
      tripal_chado_fix_v1_3_custom_tables();
    }
  }
  catch (\PDOException $e) {
    $transaction->rollback();
    $error = $e->getMessage();
    throw new DrupalUpdateException('Could not perform update: '. $error);
  }
}

/**
 * Add some new controlled vocabulary terms.
 */
function tripal_chado_update_7304() {
  try {
    $term = chado_insert_cvterm(array(
      'id' => 'SIO:001080',
      'name' => 'vocabulary',
      'cv_name' => 'SIO',
      'definition' => 'A vocabulary is a collection of terms.',
    ));
    chado_associate_semweb_term('cvterm', 'cv_id', $term);
    $term = chado_insert_cvterm(array(
      'id' => 'data:2976',
      'name' => 'Protein sequence',
      'cv_name' => 'EDAM',
      'definition' => 'One or more protein sequences, possibly with associated annotation.',
    ));
    $term = chado_insert_cvterm(array(
      'id' => 'local:fmin',
      'name' => 'minimal boundary',
      'definition' => 'The leftmost, minimal boundary in the linear range ' .
      'represented by the feature location. Sometimes this is called ' .
      'start although this is confusing because it does not necessarily ' .
      'represent the 5-prime coordinate.',
      'cv_name' => 'local',
    ));
    chado_associate_semweb_term('featureloc', 'fmin', $term);
    $term = chado_insert_cvterm(array(
      'id' => 'local:fmax',
      'name' => 'maximal boundary',
      'definition' => 'The rightmost, maximal boundary in the linear range ' .
      'represented by the featureloc. Sometimes this is called end although ' .
      'this is confusing because it does not necessarily represent the ' .
      '3-prime coordinate',
      'cv_name' => 'local',
    ));
    chado_associate_semweb_term('featureloc', 'fmax', $term);
    $term = chado_insert_cvterm(array(
      'id' => 'data:2336',
      'name' => 'Translation phase specification',
      'cv_name' => 'EDAM',
      'definition' => 'Phase for translation of DNA (0, 1 or 2) relative to a fragment of the coding sequence.',
    ));
    chado_associate_semweb_term('featureloc', 'phase', $term);
    $term = chado_insert_cvterm(array(
      'id' => 'data:3002',
      'name' => 'Annotation track',
      'cv_name' => 'EDAM',
      'definition' => 'Annotation of one particular positional feature on a ' .
        'biomolecular (typically genome) sequence, suitable for import and ' .
        'display in a genome browser. Synonym: Sequence annotation track.',
    ));
    chado_associate_semweb_term('featureloc', 'srcfeature_id', $term);
  }
  catch (\PDOException $e) {
    $transaction->rollback();
    $error = $e->getMessage();
    throw new DrupalUpdateException('Could not perform update: '. $error);
  }
}
/**
 * Adding missing cv/db details and cvterms.
 */
function tripal_chado_update_7305() {
  try {
    chado_insert_db(array(
      'name' => 'rdfs',
      'description' => 'Resource Description Framework Schema',
      'url' => 'https://www.w3.org/TR/rdf-schema/',
      'urlprefix' => 'https://www.w3.org/TR/rdf-schema/#ch_{accession}',
    ));
    chado_insert_cv('rdfs', 'Resource Description Framework Schema');
    chado_insert_db(array(
      'name' => 'SO',
      'description' => 'The sequence ontology.',
      'url' => 'http://www.sequenceontology.org/',
      'urlprefix' => 'http://www.sequenceontology.org/browser/current_svn/term/{db}:{accession}',
    ));
    chado_insert_cv('sequence', 'The sequence ontology.');
    chado_insert_db(array(
      'name' => 'TAXRANK',
      'description' => 'A vocabulary of taxonomic ranks (species, family, phylum, etc)',
      'url' => 'http://www.obofoundry.org/ontology/taxrank.html',
      'urlprefix' => 'http://purl.obolibrary.org/obo/{db}_{accession}',
    ));
    chado_insert_cv('taxonomic_rank', 'A vocabulary of taxonomic ranks (species, family, phylum, etc)');
    chado_insert_db(array(
      'name' => 'hydra',
      'description' => 'A Vocabulary for Hypermedia-Driven Web APIs',
      'url' => 'http://www.w3.org/ns/hydra/core',
      'urlprefix' => 'http://www.w3.org/ns/hydra/core#{accession}',
    ));
    chado_insert_cv(
      'hydra',
      'A Vocabulary for Hypermedia-Driven Web APIs.'
    );
    chado_insert_db(array(
      'name' => 'dc',
      'description' => 'DCMI Metadata Terms.',
      'url' => 'http://purl.org/dc/dcmitype/',
      'urlprefix' => 'http://purl.org/dc/terms/{accession}',
    ));
    chado_insert_cv(
      'dc',
      'DCMI Metadata Terms.'
    );
    $term = chado_insert_cvterm(array(
      'id' => 'dc:Service',
      'name' => 'Service',
      'cv_name' => 'dc',
      'definition' => 'A system that provides one or more functions.',
    ));
    $name = chado_insert_cvterm(array(
      'id' => 'hydra:Collection',
      'name' => 'Collection',
      'cv_name' => 'hydra',
      'definition' => 'A collection holding references to a number of related resources.',
    ));
    $name = chado_insert_cvterm(array(
      'id' => 'hydra:member',
      'name' => 'member',
      'cv_name' => 'hydra',
      'definition' => 'A member of the collection',
    ));
    $name = chado_insert_cvterm(array(
      'id' => 'hydra:description',
      'name' => 'description',
      'cv_name' => 'hydra',
      'definition' => 'A description.',
    ));
    $name = chado_insert_cvterm(array(
      'id' => 'hydra:totalItems',
      'name' => 'totalItems',
      'cv_name' => 'hydra',
      'definition' => 'The total number of items referenced by a collection.',
    ));
    $name = chado_insert_cvterm(array(
      'id' => 'hydra:title',
      'name' => 'title',
      'cv_name' => 'hydra',
      'definition' => 'A title, often used along with a description.',
    ));
    $name = chado_insert_cvterm(array(
      'id' => 'hydra:PartialCollectionView',
      'name' => 'PartialCollectionView',
      'cv_name' => 'hydra',
      'definition' => 'A PartialCollectionView describes a partial view of a Collection. Multiple PartialCollectionViews can be connected with the the next/previous properties to allow a client to retrieve all members of the collection.',
    ));
    $term = chado_insert_cvterm(array(
      'id' => 'schema:ItemPage',
      'name' => 'ItemPage',
      'cv_name' => 'schema',
      'definition' => 'A page devoted to a single item, such as a particular product or hotel.',
    ));
    global $base_path;

    chado_insert_db(array(
      'name' => 'null',
      'description' => 'No online database.',
      'url' => $base_path . 'cv/lookup/null',
      'urlprefix' => $base_path. 'cv/lookup/{db}/{accession}',
    ));
    chado_insert_db(array(
      'name' => 'local',
      'description' => 'Terms created for this site.',
      'url' => $base_path . 'cv/lookup/local',
      'urlprefix' => $base_path . 'cv/lookup/{db}/{accession}',
    ));
    $term = chado_insert_cvterm(array(
      'id' => 'local:rank',
      'name' => 'rank',
      'definition' => 'A taxonmic rank',
      'cv_name' => 'local',
    ));

  }
  catch (\PDOException $e) {
    $transaction->rollback();
    $error = $e->getMessage();
    throw new DrupalUpdateException('Could not perform update: '. $error);
  }
}

/**
 * Add cvterm mapping for the Map entity type
 */
function tripal_chado_update_7306() {
  try {
    $identifier = array(
      'cv_id' => array('name' => 'EDAM'),
      'name' => 'Map'
    );
    $cvterm = chado_get_cvterm($identifier);
    tripal_chado_add_cvterm_mapping($cvterm->cvterm_id, 'featuremap', NULL);
  }
  catch (\PDOException $e) {
    $error = $e->getMessage();
    throw new DrupalUpdateException('Could not perform update: '. $error);
  }
}

/**
 * Add cvterm mapping for the Publication entity type
 */
function tripal_chado_update_7307() {
  try {
    $identifier = array(
      'cv_id' => array('name' => 'tripal_pub'),
      'name' => 'Publication'
    );
    $cvterm = chado_get_cvterm($identifier);
    tripal_chado_add_cvterm_mapping($cvterm->cvterm_id, 'pub', NULL);
  }
  catch (\PDOException $e) {
    $error = $e->getMessage();
    throw new DrupalUpdateException('Could not perform update: '. $error);
  }
}

/**
 * Add cvterm mapping for the analysis.sourcversion and analysis.sourcename.
 */
function tripal_chado_update_7308() {
  try {
    $term = chado_insert_cvterm(array(
      'id' => 'IAO:0000129',
      'name' => 'version number',
      'cv_name' => 'IAO',
      'definition' => 'A version number is an ' .
      'information content entity which is a sequence of characters ' .
      'borne by part of each of a class of manufactured products or its ' .
      'packaging and indicates its order within a set of other products ' .
      'having the same name.',
    ));
    chado_associate_semweb_term('analysis', 'sourceversion', $term);
    chado_associate_semweb_term(NULL, 'version', $term);

    $term = chado_insert_cvterm(array(
      'id' => 'schema:name',
      'name' => 'name',
      'cv_name' => 'schema',
      'definition' => 'The name of the item.',
    ));
    chado_associate_semweb_term('analysis', 'sourcename', $term);

    $term = chado_insert_cvterm(array(
      'id' => 'data:2091',
      'name' => 'Accession',
      'cv_name' => 'EDAM',
      'definition' => 'A persistent (stable) and unique identifier, typically identifying an object (entry) from a database.',
    ));
    chado_associate_semweb_term('dbxref', 'accession', $term);

  }
  catch (\PDOException $e) {
    $error = $e->getMessage();
    throw new DrupalUpdateException('Could not perform update: '. $error);
  }
}

/**
 * Add cvterm 'annotation' and maps to cvterm linking tables.
 */
function tripal_chado_update_7309() {
  try {
    $term = chado_insert_cvterm(array(
      'id' => 'SIO:001166',
      'name' => 'annotation',
      'cv_name' => 'SIO',
      'definition' => 'An annotation is a written explanatory or critical description, or other in-context information (e.g., pattern, motif, link), that has been associated with data or other types of information.',
    ));
    chado_associate_semweb_term('feature_cvterm', 'cvterm_id', $term);
    chado_associate_semweb_term('analysis_cvterm', 'cvterm_id', $term);
    chado_associate_semweb_term('cell_line_cvterm', 'cvterm_id', $term);
    chado_associate_semweb_term('environment_cvterm', 'cvterm_id', $term);
    chado_associate_semweb_term('expression_cvterm', 'cvterm_id', $term);
    chado_associate_semweb_term('library_cvterm', 'cvterm_id', $term);
    chado_associate_semweb_term('organism_cvterm', 'cvterm_id', $term);
    chado_associate_semweb_term('phenotype_cvterm', 'cvterm_id', $term);
    chado_associate_semweb_term('stock_cvterm', 'cvterm_id', $term);
    chado_associate_semweb_term('stock_relationship_cvterm', 'cvterm_id', $term);


    $term = chado_insert_cvterm(array(
      'id' => 'SIO:000281',
      'name' => 'negation',
      'cv_name' => 'SIO',
      'definition' => 'NOT is a logical operator in that has the value true if its operand is false.',
    ));
    chado_associate_semweb_term('feature_cvterm', 'is_not', $term);
    chado_associate_semweb_term('analysis_cvterm', 'is_not', $term);
    chado_associate_semweb_term('organism_cvterm', 'is_not', $term);
    chado_associate_semweb_term('stock_cvterm', 'is_not', $term);
  }
  catch (\PDOException $e) {
    $error = $e->getMessage();
    throw new DrupalUpdateException('Could not perform update: '. $error);
  }
}
/**
 * Adds the 'OBCS' and rank order term.
 */
function tripal_chado_update_7310() {
  try {
    chado_insert_db(array(
      'name' => 'OBCS',
      'description' => 'Ontology of Biological and Clinical Statistics.',
      'url' => 'https://github.com/obcs/obcs',
      'urlprefix' => 'http://purl.obolibrary.org/obo/{db}_{accession}',
    ));
    chado_insert_cv(
        'OBCS',
        'Ontology of Biological and Clinical Statistics.'
    );

    $term = chado_insert_cvterm(array(
      'id' => 'OBCS:0000117',
      'name' => 'rank order',
      'cv_name' => 'OBCS',
      'definition' => 'A data item that represents an arrangement according to a rank, i.e., the position of a particular case relative to other cases on a defined scale.',
    ));
    chado_associate_semweb_term(NULL, 'rank', $term);
  }
  catch (\PDOException $e) {
    $error = $e->getMessage();
    throw new DrupalUpdateException('Could not perform update: '. $error);
  }
}
/**
 * Fix a mistake with the association of the term with featureloc.fmin.
 */
function tripal_chado_update_7311() {
  try {
    $term = chado_insert_cvterm(array(
      'id' => 'local:fmin',
      'name' => 'minimal boundary',
      'definition' => 'The leftmost, minimal boundary in the linear range ' .
        'represented by the feature location. Sometimes this is called ' .
        'start although this is confusing because it does not necessarily ' .
        'represent the 5-prime coordinate.',
      'cv_name' => 'local',
    ));
    chado_associate_semweb_term('featureloc', 'fmin', $term);
  }
  catch (\PDOException $e) {
    $error = $e->getMessage();
    throw new DrupalUpdateException('Could not perform update: '. $error);
  }
}
/**
 * Associates a local term with the pub.miniref column.
 */
function tripal_chado_update_7312() {
  try {

    $term = chado_insert_cvterm(array(
      'id' => 'local:miniref',
      'name' => 'Mini-ref',
      'definition' => 'A small in-house unique identifier for a publication.',
      'cv_name' => 'local',
    ));
    chado_associate_semweb_term('pub', 'miniref', $term);
    $term = chado_insert_cvterm(array(
      'id' => 'schema:url',
      'name' => 'url',
      'cv_name' => 'schema',
      'definition' => 'URL of the item.',
    ));
    chado_associate_semweb_term('db', 'url', $term);
  }
  catch (\PDOException $e) {
    $error = $e->getMessage();
    throw new DrupalUpdateException('Could not perform update: '. $error);
  }
}

/**
 * Run the cvtermpath for the Tripal Pub and Contact ontologies.
 */
function tripal_chado_update_7313() {
  try {
    $cv = chado_get_cv(array('name' => 'tripal_pub'));
    chado_update_cvtermpath($cv->cv_id);
    $cv = chado_get_cv(array('name' => 'tripal_contact'));
    chado_update_cvtermpath($cv->cv_id);
  }
  catch (\PDOException $e) {
    $error = $e->getMessage();
    throw new DrupalUpdateException('Could not perform update: '. $error);
  }
}

/**
 * Adds a local term for the featuremap.feature_id column.
 */
function tripal_chado_update_7314() {
  try {
    $term = chado_insert_cvterm(array(
      'name' => 'Reference Feature',
      'definition' => 'A genomic or genetic feature on which other features are mapped.',
      'cv_name' => 'local',
      'is_relationship' => 0,
      'db_name' => 'local'
    ));
    chado_associate_semweb_term('featurepos', 'map_feature_id', $term);
  }
  catch (\PDOException $e) {
    $error = $e->getMessage();
    throw new DrupalUpdateException('Could not perform update: '. $error);
  }
}
/**
 * Fixes a mistake with the schema:additionalType term.
 */
function tripal_chado_update_7315() {
  try {
    $term = chado_insert_cvterm(array(
      'id' => 'schema:additionalType',
      'name' => 'additionalType',
      'cv_name' => 'schema',
      'definition' => 'An additional type for the item, typically used for adding more specific types from external vocabularies in microdata syntax. This is a relationship between something and a class that the thing is in.',
    ));
    chado_delete_record('cv', array('name' => 'An additional type for the item, typically used for adding more specific types from external vocabularies in microdata syntax. This is a relationship between something and a class that the thing is in.'));
  }
  catch (\PDOException $e) {
    $error = $e->getMessage();
    throw new DrupalUpdateException('Could not perform update: '. $error);
  }
}

/**
 * Adds the email term for potential use with contact properties.
 */
function tripal_chado_update_7316() {
  try {
    $term = chado_insert_cvterm(array(
      'id' => 'SIO:001323',
      'name' => 'email address',
      'cv_name' => 'SIO',
      'definition' => 'an email address is an identifier to send mail to particular electronic mailbox.',
    ));
  }
  catch (\PDOException $e) {
    $error = $e->getMessage();
    throw new DrupalUpdateException('Could not perform update: '. $error);
  }
}

/**
 * Support for the biomaterial table.
 */
function tripal_chado_update_7317() {
  try {
    $term = chado_insert_cvterm(array(
      'id' => 'OBI:0100026',
      'name' => 'organism',
      'cv_name' => 'obi',
      'definition' => 'A material entity that is an individual living system, such as animal, plant, bacteria or virus, that is capable of replicating or reproducing, growth and maintenance in the right environment. An organism may be unicellular or made up, like humans, of many billions of cells divided into specialized tissues and organs.',
    ));
    chado_associate_semweb_term('biomaterial', 'taxon_id', $term);
    $term = chado_insert_cvterm(array(
      'id' => 'local:contact',
      'name' => 'contact',
      'definition' => 'An entity (e.g. individual or organization) through ' .
      'whom a person can gain access to information, favors, ' .
      'influential people, and the like.',
      'cv_name' => 'local',
    ));
    chado_associate_semweb_term('biomaterial', 'biosourceprovider_id', $term);
  }
  catch (\PDOException $e) {
    $error = $e->getMessage();
    throw new DrupalUpdateException('Could not perform update: '. $error);
  }
}

/**
 * Adding biological sample term for biomaterial entities.
 */
function tripal_chado_update_7318() {
  try {
    chado_insert_db(array(
      'name' => 'sep',
      'description' => 'Sample processing and separation techniques.',
      'url' => 'http://psidev.info/index.php?q=node/312',
      'urlprefix' => 'http://purl.obolibrary.org/obo/{db}_{accession}',
    ));
    chado_insert_cv('sep','A structured controlled vocabulary for the annotation of sample processing and separation techniques in scientific experiments.');
    $term = chado_insert_cvterm(array(
      'id' => 'sep:00195',
      'name' => 'biological sample',
      'cv_name' => 'sep',
      'definition' => 'A biological sample analysed by a particular technology.',
    ));
  }
  catch (\PDOException $e) {
    $error = $e->getMessage();
    throw new DrupalUpdateException('Could not perform update: '. $error);
  }
}


/**
 * Adding new Analysis term.
 */
function tripal_chado_update_7319() {
  try {
    $term = chado_insert_cvterm(array(
      'id' => 'operation:2945',
      'name' => 'Analysis',
      'cv_name' => 'EDAM',
      'definition' => 'Apply analytical methods to existing data of a specific type.',
    ));
  }
  catch (\PDOException $e) {
    $error = $e->getMessage();
    throw new DrupalUpdateException('Could not perform update: '. $error);
  }
}

/**
 * Adding Phylogenetic Tree content type.
 */
function tripal_chado_update_7320() {
    try {
    // Associate the Analysis term with the analysis_id of the phylotree table.
    $term = chado_get_cvterm(array('id' => 'operation:2945'));
    chado_associate_semweb_term('phylotree', 'analysis_id', $term);

    $term = chado_insert_cvterm(array(
      'id' => 'data:0872',
      'name' => 'Phylogenetic tree',
      'cv_name' => 'EDAM',
      'definition' => 'The raw data (not just an image) from which a phylogenetic tree is directly generated or plotted, such as topology, lengths (in time or in expected amounts of variance) and a confidence interval for each length.',
    ));
    $term = chado_insert_cvterm(array(
      'id' => 'data:3272',
      'name' => 'Species tree',
      'cv_name' => 'EDAM',
      'definition' => 'A phylogenetic tree that reflects phylogeny of the taxa from which the characters (used in calculating the tree) were sampled.',
    ));
    $term = chado_insert_cvterm(array(
      'id' => 'data:3271',
      'name' => 'Gene tree',
      'cv_name' => 'EDAM',
      'definition' => 'A phylogenetic tree that is an estimate of the character\'s phylogeny.',
    ));
    $term = chado_insert_cvterm(array(
      'id' => 'operation:0567',
      'name' => 'Phylogenetic tree visualisation',
      'cv_name' => 'EDAM',
      'definition' => 'A phylogenetic tree that is an estimate of the character\'s phylogeny.',
    ));

    // Create the 'Phylogenetic tree' content type.
    $error = '';
    $args = array(
      'vocabulary' => 'data',
      'accession' => '0872',
      'term_name' => 'Phylogenetic tree',
      'storage_args' => array(
        'data_table' => 'phylotree',
      )
    );
    $term = tripal_load_term_entity(array('vocabulary' => 'data', 'accession' => '0872'));
    if ($term) {
      $bundle = tripal_load_bundle_entity(array('term_id' => $term->id));
    }
    if (!$term or !$bundle) {
      if (!tripal_create_bundle($args)) {
        throw new Exception('Error Encountered creating "Phylogenetic tree" Tripal Content Type.');
      }
    }
  }
  catch (\PDOException $e) {
    $error = $e->getMessage();
    throw new DrupalUpdateException('Could not perform update: '. $error);
  }
}

/**
 * Updating details for local ontologies.
 */
function tripal_chado_update_7321() {
  try {
    chado_insert_db(array(
      'name' => 'TPUB',
      'description' => 'Tripal Publication Ontology. A temporary ontology until a more formal appropriate ontology an be identified.',
      'url' => '/cv/lookup/TPUB',
      'urlprefix' => '/cv/lookup/TPUB/{accession}',
    ));
    chado_insert_cv('tripal_pub', 'Tripal Publication Ontology. A temporary ontology until a more formal appropriate ontology an be identified.');

    chado_insert_db(array(
      'name' => 'rdf',
      'description' => 'Resource Description Framework',
      'url' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns',
      'urlprefix' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
    ));
    chado_insert_cv(
      'rdf',
      'Resource Description Framework'
    );
    chado_insert_db(array(
      'name' => 'rdfs',
      'description' => 'Resource Description Framework Schema',
      'url' => 'https://www.w3.org/TR/rdf-schema/',
      'urlprefix' => 'http://www.w3.org/2000/01/rdf-schema#{accession}',
    ));
    chado_insert_db(array(
      'name' => 'hydra',
      'description' => 'A Vocabulary for Hypermedia-Driven Web APIs',
      'url' => 'http://www.w3.org/ns/hydra/core',
      'urlprefix' => 'http://www.w3.org/ns/hydra/core#{accession}',
    ));
    chado_insert_cv(
      'hydra',
      'A Vocabulary for Hypermedia-Driven Web APIs.'
    );
  }
  catch (\PDOException $e) {
    $error = $e->getMessage();
    throw new DrupalUpdateException('Could not perform update: '. $error);
  }
}
/**
 * Fixing the SWO, TPUB and TContact vocabulary URLs
 */
function tripal_chado_update_7322() {
  try {
    chado_insert_db(array(
      'name' => 'TPUB',
      'description' => 'Tripal Publication Ontology. A temporary ontology until a more formal appropriate ontology an be identified.',
      'url' => 'cv/lookup/TPUB',
      'urlprefix' => 'cv/lookup/TPUB/{accession}',
    ));
    chado_insert_db(array(
      'name' => 'TContact',
      'description' => 'Tripal Contact Ontology. A temporary ontology until a more formal appropriate ontology an be identified.',
      'url' => 'cv/lookup/TContact',
      'urlprefix' => 'cv/lookup/TContact/{accession}',
    ));
    chado_insert_cv('tripal_contact', 'Tripal Contact Ontology. A temporary ontology until a more formal appropriate ontology an be identified.');

    chado_insert_db(array(
      'name' => 'SWO',
      'description' => 'Software Ontology',
      'url' => 'http://purl.obolibrary.org/obo/swo',
      'urlprefix' => 'http://www.ebi.ac.uk/swo/',
    ));
  }
  catch (\PDOException $e) {
    $error = $e->getMessage();
    throw new DrupalUpdateException('Could not perform update: '. $error);
  }
}
/**
 * Adding the db2cv materialized view.
 */
function tripal_chado_update_7323() {
  try {
    module_load_include('inc', 'tripal_chado', 'includes/setup/tripal_chado.chado_vx_x');
    tripal_chado_add_db2cv_mview_mview();

    drupal_set_message('Populating materialized view db2cv_mview...');
    $mview_id = chado_get_mview_id('db2cv_mview');
    chado_populate_mview($mview_id);

    drupal_set_message('Populating materialized view cv_root_mview...');
    $mview_id = chado_get_mview_id('cv_root_mview');
    chado_populate_mview($mview_id);
  }
  catch (\PDOException $e) {
    $error = $e->getMessage();
    throw new DrupalUpdateException('Could not perform update: '. $error);
  }
}
/**
 * Updating the db2cv materialized view.
 */
function tripal_chado_update_7324() {
  try {
    if (chado_table_exists(db2cv_mview) and !chado_column_exists('db2cv_mview', 'num_terms')) {
      module_load_include('inc', 'tripal_chado', 'includes/setup/tripal_chado.chado_vx_x');

      // Remove the old mview.
      $mview_id = chado_get_mview_id('db2cv_mview');
      chado_delete_mview($mview_id);

      // Readd the mview.
      tripal_chado_add_db2cv_mview_mview();
      drupal_set_message('Populating materialized view db2cv_mview...');
      $mview_id = chado_get_mview_id('db2cv_mview');
      chado_populate_mview($mview_id);
    }
  }
  catch (\PDOException $e) {
    $error = $e->getMessage();
    throw new DrupalUpdateException('Could not perform update: '. $error);
  }
}

/**
 * Adding additional vocabulary term mapping to Chado table columns.
 */
function tripal_chado_update_7325() {
  try {
    module_load_include('inc', 'tripal_chado', 'includes/tripal_chado.semweb');
    tripal_chado_populate_chado_semweb_table();
  }
  catch (\PDOException $e) {
    $error = $e->getMessage();
    throw new DrupalUpdateException('Could not perform update: '. $error);
  }
}


/**
 * Adding a "Company" term.
 */
function tripal_chado_update_7326() {
  try {
    // The Company term is missing for the Tripal Contact ontology, but is
    // useful for the arraydesign.manufacturer which is an FK to Contact.
    // It seems better to use a term from a curated ontology than to add to
    // Tripal Contact.
    $term = chado_insert_cvterm(array(
      'id' => 'NCIT:C54131',
      'name' => 'Company',
      'cv_name' => 'ncit',
      'definition' => 'Any formal business entity for profit, which may be a corporation, a partnership, association or individual proprietorship. [ NCI http://dictionary.law.com ]',
    ));
  }
  catch (\PDOException $e) {
    $error = $e->getMessage();
    throw new DrupalUpdateException('Could not perform update: '. $error);
  }
}

/**
 * Adding terms for sequence visualization.
 */
function tripal_chado_update_7327() {
  try {
    $term = chado_insert_cvterm(array(
      'id' => 'operation:0564',
      'name' => 'Sequence visualisation',
      'cv_name' => 'EDAM',
      'definition' => 'Visualise, format or render a molecular sequence or sequences such as a sequence alignment, possibly with sequence features or properties shown.',
    ));
  }
  catch (\PDOException $e) {
    $error = $e->getMessage();
    throw new DrupalUpdateException('Could not perform update: '. $error);
  }
}

/**
 * Don't count relationship cvterms as ontology roots.
 */
function tripal_chado_update_7328() {
  try {
    $mv_name = 'cv_root_mview';
    // Remove the old mview.
    $mview_id = chado_get_mview_id($mv_name);
    chado_delete_mview($mview_id);
    module_load_include('inc', 'tripal_chado', 'includes/setup/tripal_chado.chado_vx_x');
    // Re-add the mview.
    tripal_chado_add_cv_root_mview_mview();
    $mview_id = chado_get_mview_id($mv_name);
    chado_populate_mview($mview_id);
  }
  catch (\PDOException $e) {
    $error = $e->getMessage();
    throw new DrupalUpdateException('Could not perform update: '. $error);
  }
}

/**
 * Fixing the chado_bundle.type_id type.
 */
function tripal_chado_update_7329() {
  try {
    db_change_field('chado_bundle', 'type_id', 'type_id', [
      'description' => 'If a type_column is set then this is the cvterm_id of the data type that this bundle maps to.',
      'size' => 'big',
      'type' => 'int',
    ]);
  }
  catch (\PDOException $e) {
    $error = $e->getMessage();
    throw new DrupalUpdateException('Could not perform update: '. $error);
  }
}

/**
 * Associates categories with content types.
 */
function tripal_chado_update_7330() {
  try {
    tripal_insert_variable('bundle_category', 'Bundles can be categorized to allow for grouping');

    $bundles = [
      'General' => [
        // Organism
        'OBI:0100026',
        // Analyis
        'operation:2945',
        // Project
        'NCIT:C47885',
        // Study
        'SIO:001066',
        // Contact
        'local:contact',
        // Publication
        'TPUB:0000002',
        // Protocol
        'sep:00101',
      ],
      'Genomic' => [
        // Gene
        'SO:0000704',
        // mRNA
        'SO:0000234',
        // Phylogenetci Tree
        'data:0872',
        // Physical Map
        'data:1280',
        // DNA Library
        'NCIT:C16223',
        // Genome Assembly
        'operation:0525',
        // Genome Annotation
        'operation:0362',
        // Genome Project
        'local:Genome Project',
      ],
      'Genetic' => [
        // Genetic Map
        'data:1278',
        // QTL
        'SO:0000771',
        // Sequence Variant
        'SO:0001060',
        // Genetic Marker
        'SO:0001645',
        // Heritable Phenotypic Marker
        'SO:0001500',
      ],
      'Germplasm/Breeding' => [
        // Germplasm Accession
        'CO_010:0000044',
        // Breeding Cross
        'CO_010:0000255',
        // Cutlivar
        'CO_010:0000029',
        // Recombinant Inbred Line
        'CO_010:0000162',
      ],
      'Expression' => [
        // Biological Sample
        'sep:00195',
        // Assay
        'OBI:0000070',
        // Array Design
        'EFO:0000269',
      ]
    ];
    foreach ($bundles as $category => $accessions) {
      foreach ($accessions as $accession) {
        $bundle = tripal_load_bundle_entity(['accession' => $accession]);
        if ($bundle) {
          tripal_set_bundle_variable('bundle_category', $bundle->id, $category);
        }
      }
    }
  }
  catch (\PDOException $e) {
    $error = $e->getMessage();
    throw new DrupalUpdateException('Could not perform update: '. $error);
  }
}

/**
 * Adds a base_type_id to the chado_bundle table.
 */
function tripal_chado_update_7331() {
  try {
    if (!db_field_exists('chado_bundle', 'base_type_id')) {
      db_add_field('chado_bundle', 'base_type_id', [
        'description' => 'If a property table is used for a linker, and if the base table requires a type_id then this is the type that should be used on insert of new records in the base table.',
        'size' => 'big',
        'type' => 'int',
      ]);
    }
  }
  catch (\PDOException $e) {
    $error = $e->getMessage();
    throw new DrupalUpdateException('Could not perform update: '. $error);
  }
}

/**
 * Adds additional vocabs for the OBO Importer.
 */
function tripal_chado_update_7332() {
  try {
    // We have to add the db and cv in case the user hasn't yet prepared Chado.
    // If they have prepared Chado then no harm done.
    chado_insert_db([
      'name' => 'NCIT',
      'description' => 'NCI Thesaurus OBO Edition.',
      'url' => 'http://purl.obolibrary.org/obo/ncit.owl',
      'urlprefix' => ' http://purl.obolibrary.org/obo/{db}_{accession}',
    ]);
    chado_insert_cv(
      'ncit',
      'The NCIt OBO Edition project aims to increase integration of the NCIt with OBO Library ontologies. NCIt is a reference terminology that includes broad coverage of the cancer domain, including cancer related diseases, findings and abnormalities. NCIt OBO Edition releases should be considered experimental.'
    );

    $term = chado_insert_cvterm([
      'id' => 'NCIT:C25693',
      'name' => 'Subgroup',
      'cv_name' => 'ncit',
      'definition' => 'A subdivision of a larger group with members often exhibiting similar characteristics. [ NCI ]',
    ]);


    // Add the rdfs:comment vocabulary.
    chado_insert_db(array(
      'name' => 'rdfs',
      'description' => 'Resource Description Framework Schema',
      'url' => 'https://www.w3.org/TR/rdf-schema/',
      'urlprefix' => 'http://www.w3.org/2000/01/rdf-schema#{accession}',
    ));
    chado_insert_cv(
      'rdfs',
      'Resource Description Framework Schema'
      );
    $name = chado_insert_cvterm(array(
      'id' => 'rdfs:comment',
      'name' => 'comment',
      'cv_name' => 'rdfs',
      'definition' => 'A human-readable description of a resource\'s name.',
    ));
  }
  catch (\PDOException $e) {
    $error = $e->getMessage();
    throw new DrupalUpdateException('Could not perform update: '. $error);
  }
}

/**
 * Renames the TContact vocabulary database entry to TCONTACT as it should be.
 */
function tripal_chado_update_7333() {
  try {
    chado_update_record('db', ['name' => 'TContact'], ['name' => 'TCONTACT']);
  }
  catch (\PDOException $e) {
    $error = $e->getMessage();
    throw new DrupalUpdateException('Could not perform update: '. $error);
  }
}

/**
 * SQL Fix for the db2cv_mview materialized view.
 */
function tripal_chado_update_7334() {

  try {
    $query = '
       SELECT DISTINCT CV.cv_id, CV.name as cvname, DB.db_id, DB.name as dbname,
         COUNT(CVT.cvterm_id) as num_terms
       FROM cv CV
         INNER JOIN cvterm CVT on CVT.cv_id = CV.cv_id
         INNER JOIN dbxref DBX on DBX.dbxref_id = CVT.dbxref_id
         INNER JOIN db DB on DB.db_id = DBX.db_id
       WHERE CVT.is_relationshiptype = 0 and CVT.is_obsolete = 0
       GROUP BY CV.cv_id, CV.name, DB.db_id, DB.name
       ORDER BY DB.name
    ';
    $mview_id = tripal_get_mview_id('db2cv_mview');
    if($mview_id) {
      $sql = "UPDATE {tripal_mviews} set query = :query WHERE mview_id = :mview_id";
      db_query($sql, [':query' => $query, ':mview_id' => $mview_id]);
    }
  }
  catch (\PDOException $e) {
    $error = $e->getMessage();
    throw new DrupalUpdateException('Could not perform update: '. $error);
  }
}
/**
 * SQL Fix for the cv_root_mview materialized view.
 */
function tripal_chado_update_7335() {
  try {
    $query = '
      SELECT DISTINCT CVT.name, CVT.cvterm_id, CV.cv_id, CV.name
      FROM cvterm CVT
        LEFT JOIN cvterm_relationship CVTR ON CVT.cvterm_id = CVTR.subject_id
        INNER JOIN cvterm_relationship CVTR2 ON CVT.cvterm_id = CVTR2.object_id
      INNER JOIN cv CV on CV.cv_id = CVT.cv_id
      WHERE CVTR.subject_id is NULL and
        CVT.is_relationshiptype = 0 and CVT.is_obsolete = 0
      ';
    $mview_id = tripal_get_mview_id('cv_root_mview');
    if($mview_id) {
      $sql = "UPDATE {tripal_mviews} set query = :query WHERE mview_id = :mview_id";
      db_query($sql, [':query' => $query, ':mview_id' => $mview_id]);
    }
  }
  catch (\PDOException $e) {
    $error = $e->getMessage();
    throw new DrupalUpdateException('Could not perform update: '. $error);
  }
}



/**
 * Use correct contact field when linked via linker table.
 */
function tripal_chado_update_7336() {

  try {
    $bundles = field_info_instances('TripalEntity');

    foreach ($bundles as $bundle_name => $fields) {

      $bundle = tripal_load_bundle_entity(['name' => $bundle_name]);
      $base = $bundle->data_table;

      $contact_table = $base . '_contact';
      if (chado_table_exists($contact_table)) {

        $field_name = $base . '_contact';
        $instance_info = field_info_instance('TripalEntity', $field_name, $bundle_name);

        if ($instance_info) {
          $instance_info['type'] = 'chado_linker__contact';
          $instance_info['widget']['type'] = 'chado_linker__contact_widget';
          $instance_info['formatter']['type'] = 'chado_linker__contact_widget';
          field_update_instance($instance_info);
        }
      }
    }
  }
  catch (\PDOException $e) {
    $error = $e->getMessage();
    throw new DrupalUpdateException('Could not perform update: '. $error);
  }
}

/**
 * Update the NCBITaxon DB entry.
 */
function tripal_chado_update_7337(){
  try {
    chado_insert_db(array(
      'name' => 'NCBITaxon',
      'description' => 'NCBI organismal classification.',
      'url' => 'http://www.berkeleybop.org/ontologies/ncbitaxon/',
      'urlprefix' => 'https://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?id={accession}',
    ));
  }
  catch (\PDOException $e) {
    $error = $e->getMessage();
    throw new DrupalUpdateException('Could not perform update: '. $error);
  }
}
