Browse Source

Done fixing bugs with MViews & Custom Tables

Stephen Ficklin 11 years ago
parent
commit
409ed7066b

+ 112 - 88
tripal_core/api/tripal_core.custom_tables.api.inc

@@ -127,35 +127,27 @@ function chado_create_custom_table($table, $schema, $skip_creation = 1, $mview_i
   $created = 0;
   $recreated = 0;
 
-  // see if the table entry already exists in the tripal_custom_tables table.
-  $sql = "SELECT * FROM {tripal_custom_tables} WHERE table_name = :table_name";
-  $results = db_query($sql, array(':table_name' => $table));
-  $centry = $results->fetchObject();
-
-  // check to see if the table already exists in the chado schema
-  $exists = chado_table_exists($table);
-
-  // if the table does not exist then create it
-  if (!$exists) {
-    try {
+  $transaction = db_transaction();
+  try {
+    // see if the table entry already exists in the tripal_custom_tables table.
+    $sql = "SELECT * FROM {tripal_custom_tables} WHERE table_name = :table_name";
+    $results = db_query($sql, array(':table_name' => $table));
+    $centry = $results->fetchObject();
+  
+    // check to see if the table already exists in the chado schema
+    $exists = chado_table_exists($table);
+  
+    // if the table does not exist then create it
+    if (!$exists) {
       $ret = db_create_table('chado.' . $table, $schema);
       $created = 1;
     }
-    catch (Exception $e) {
-      $error = $e->getMessage();
-      tripal_report_error('tripal_core', TRIPAL_ERROR,
-        "Error adding custom table: @message", array('@message' => $error));
-      drupal_set_message("Could not add custom table. $error.", "error");
-      return FALSE;
-    }
-  }
-
-  // if the table exists in Chado and in our custom table and
-  // skip creation is turned off then drop and re-create the table
-  if ($exists and is_object($centry) and !$skip_creation) {
-
-    // drop the table we'll recreate it with the new schema
-    try {
+  
+    // if the table exists in Chado and in our custom table and
+    // skip creation is turned off then drop and re-create the table
+    if ($exists and is_object($centry) and !$skip_creation) {
+  
+      // drop the table we'll recreate it with the new schema
       chado_query('DROP TABLE {' . $table . '}');
       // remove any 'referring_tables' from the array as the db_create_table doesn't use that
       $new_schema = $schema;
@@ -165,67 +157,49 @@ function chado_create_custom_table($table, $schema, $skip_creation = 1, $mview_i
       db_create_table('chado.' . $table, $new_schema);
       $recreated = 1;
     }
-    catch (Exception $e) {
-      $error = $e->getMessage();
-      tripal_report_error('tripal_core', TRIPAL_ERROR,
-        "Error adding custom table: @message",
-        array('@message' => $error));
-      drupal_set_message("Could not add custom table. $error.", "error");
-      return FALSE;
+  
+    // add an entry in the tripal_custom_table
+    $record = new stdClass();
+    $record->table_name = $table;
+    $record->schema = serialize($schema);
+    if ($mview_id) {
+      $record->mview_id = $mview_id;
     }
-  }
-
-  // add an entry in the tripal_custom_table
-  $record = new stdClass();
-  $record->table_name = $table;
-  $record->schema = serialize($schema);
-  if ($mview_id) {
-    $record->mview_id = $mview_id;
-  }
-
-  // if an entry already exists then remove it
-  if ($centry) {
-    $sql = "DELETE FROM {tripal_custom_tables} WHERE table_name = :table_name";
-    db_query($sql, array(':table_name' => $table));
-  }
-  $success = drupal_write_record('tripal_custom_tables', $record);
-  if (!$success) {
-    tripal_report_error('tripal_core', TRIPAL_ERROR, "Error adding custom table %table_name.",
-      array('%table_name' => $table));
-    drupal_set_message(t("Could not add custom table %table_name.
-      Please check the schema array.", array('%table_name' => $table)), 'error');
-    return FALSE;
-  }
-
-
-  // now add any foreign key constraints
-  if (!$skip_creation and array_key_exists('foreign keys', $schema)) {
-
-    // iterate through the foreign keys and add each one
-    $fkeys = $schema['foreign keys'];
-    foreach ($fkeys as $fktable => $fkdetails) {
-      $relations = $fkdetails['columns'];
-      foreach ($relations as $left => $right) {
-        $sql = '
-          ALTER TABLE {' . $table . '}
-            ADD CONSTRAINT ' . $table . '_' . $left . '_fkey FOREIGN KEY (' . $left . ')
-            REFERENCES  {' . $fktable . '} (' . $right . ')
-            ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED
-        ';
-        try {
+  
+    // if an entry already exists then remove it
+    if ($centry) {
+      $sql = "DELETE FROM {tripal_custom_tables} WHERE table_name = :table_name";
+      db_query($sql, array(':table_name' => $table));
+    }
+    $success = drupal_write_record('tripal_custom_tables', $record); 
+  
+    // now add any foreign key constraints
+    if (!$skip_creation and array_key_exists('foreign keys', $schema)) {
+  
+      // iterate through the foreign keys and add each one
+      $fkeys = $schema['foreign keys'];
+      foreach ($fkeys as $fktable => $fkdetails) {
+        $relations = $fkdetails['columns'];
+        foreach ($relations as $left => $right) {
+          $sql = '
+            ALTER TABLE {' . $table . '}
+              ADD CONSTRAINT ' . $table . '_' . $left . '_fkey FOREIGN KEY (' . $left . ')
+              REFERENCES  {' . $fktable . '} (' . $right . ')
+              ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED
+          ';
           chado_query($sql);
         }
-        catch (Exception $e) {
-          $error = $e->getMessage();
-          tripal_report_error('tripal_core', TRIPAL_ERROR, "Error, could not add foreign key contraint to custom table: %error",
-            array('%error' => $error));
-          drupal_set_message("Could not add foreign key contraint to table: $error", 'error');
-          return FALSE;
-        }
       }
     }
   }
-
+  catch (Exception $e) {
+    $transaction->rollback();
+    watchdog_exception('tripal_core', $e);
+    $error = _drupal_decode_exception($e);
+    drupal_set_message(t("Could not add custom table '%table_name': %message.", 
+      array('%table_name' => $table, '%message' => $error['!message'])), 'error');
+    return FALSE;
+  }
   if ($created) {
     drupal_set_message("Custom table created successfully.", 'status');
   }
@@ -237,6 +211,52 @@ function chado_create_custom_table($table, $schema, $skip_creation = 1, $mview_i
   }
   return TRUE;
 }
+
+/**
+ * This function is used to validate a Drupal Schema API array prior to 
+ * passing it ot the chado_create_custom_table_schema().  This function
+ * can be used in a form validate function or whenver a schema is provided by
+ * a user and needs validation.
+ * 
+ * @param $schema_array
+ *   the Drupal Schema API compatible array
+ *   
+ * @return
+ *   An empty string for success or a message string for failure
+ * 
+ * @ingroup tripal_custom_tables_api
+ */
+function chado_validate_custom_table_schema($schema_array) {
+
+  if (is_array($schema_array) and !array_key_exists('table', $schema_array)) {
+    return "The schema array must have key named 'table'";
+  }
+  
+  // check index length
+  if (array_key_exists('indexes', $schema_array)) {
+    foreach ($schema_array['indexes'] as $index_name => $details) {
+      if (strlen($schema_array['table'] . '_' . $index_name) > 60) {
+        return "One ore more index names appear to be too long. For example: '" .  $schema_array['table'] . '_' . $index_name .
+        ".'  Index names are created by concatenating the table name with the index name provided " .
+        "in the 'indexes' array of the schema. Please alter any indexes that when combined with the table name are " .
+        "longer than 60 characters.";
+      }
+    }
+  }
+  
+  // check unique key length
+  if (array_key_exists('unique keys', $schema_array)) {
+    foreach ($schema_array['unique keys'] as $index_name => $details) {
+      if (strlen($schema_array['table'] . '_' . $index_name) > 60) {
+        return "One ore more unique key names appear to be too long. For example: '" .  $schema_array['table'] . '_' . $index_name .
+        ".'  Unique key names are created by concatenating the table name with the key name provided " .
+        "in the 'unique keys' array of the schema. Please alter any unique keys that when combined with the table name are " .
+        "longer than 60 characters.";
+      }
+    }
+  }
+  
+}
 /**
  * Retrieve the custom table id given the name
  *
@@ -266,9 +286,9 @@ function chado_get_custom_table_id($table_name) {
  * @param $table_id
  *   The unique ID of the custom table for the action to be performed on
  *
- * @ingroup tripal_custom_tables
+ * @ingroup tripal_custom_tables_api
  */
-function tripal_delete_custom_table($table_id) {
+function chado_delete_custom_table($table_id) {
   global $user;
 
   $args = array("$table_id");
@@ -280,10 +300,10 @@ function tripal_delete_custom_table($table_id) {
   $sql = "SELECT * FROM {tripal_custom_tables} WHERE table_id = :table_id";
   $results = db_query($sql, array(':table_id' => $table_id));
   $custom_table = $results->fetchObject();
-  
+
   // if this is a materialized view then don't allow deletion with this function
   if ($custom_table->mview_id) {
-    tripal_report_error('tripal_core', TRIPAL_ERROR, "Please use the tripal_delete_mview() function to delete this custom table as it is a materialized view. Table not deleted.", array());    
+    tripal_report_error('tripal_core', TRIPAL_ERROR, "Please use the tripal_delete_mview() function to delete this custom table as it is a materialized view. Table not deleted.", array());
     drupal_set_message("This custom table is a materialized view. Please use the "  . l('Materialized View', 'admin/tripal/schema/mviews') . " interface to delete it.", 'error');
     return FALSE;
   }
@@ -294,12 +314,16 @@ function tripal_delete_custom_table($table_id) {
   if ($success) {
     drupal_set_message(t("Custom Table '%name' removed", array('%name' => $custom_table->table_name)));
   }
-  
+
   // drop the table from chado if it exists
-  if (db_table_exists($custom_table->table_name)) {
-    $success = chado_query("DROP TABLE %s", $custom_table->table_name);
+  if (chado_table_exists($custom_table->table_name)) {
+    $success = chado_query("DROP TABLE {" .  $custom_table->table_name . "}");
     if ($success) {
       drupal_set_message(t("Custom Table '%name' dropped", array('%name' => $custom_table->table_name)));
     }
+    else {
+      tripal_report_error('tripal_core', TRIPAL_ERROR, "Cannot drop the custom table: %name", array('%name' => $custom_table->table_name));
+      drupal_set_message(t("Cannot drop the custom table: '%name'", array('%name' => $custom_table->table_name)));
+    }
   }
 }

+ 37 - 29
tripal_core/api/tripal_core.mviews.api.inc

@@ -129,43 +129,51 @@ function tripal_add_mview($name, $modulename, $mv_schema, $query, $comment = NUL
     array(':name' => $name))->fetchField();
 
   if(!$mview_id) {
-
-    // Create a new record
-    $record = new stdClass();
-    $record->name = $name;
-    $record->modulename = $modulename;
-    $record->mv_table = $mv_table;
-    $record->query = $query;
-    $record->comment = $comment;
-    
-    // convert the schema into a string format
-    $str_schema = var_export($mv_schema, TRUE);
-    $str_schema = preg_replace('/=>\s+\n\s+array/', '=> array', $str_schema);
-    $record->mv_schema = $str_schema;
-
-    // add the record to the tripal_mviews table and if successful
-    // create the new materialized view in the chado schema
-    if (drupal_write_record('tripal_mviews', $record)) {
-
-      // drop the table from chado if it exists
-      if (chado_table_exists($mv_table)) {
-        $sql = 'DROP TABLE {' . $mv_table . '}';
-        chado_query($sql);
-      }
-      // create the table
-      if (!chado_create_custom_table($mv_table, $mv_schema, 0, $record->mview_id)) {
-        drupal_set_message(t("Could not create the materialized view. Check Drupal error report logs."), 'error');
-      }
-      else {
-        drupal_set_message(t("Materialized view '%name' created", array('%name' => $name)));
+    $transaction = db_transaction();
+    try {
+      // Create a new record
+      $record = new stdClass();
+      $record->name = $name;
+      $record->modulename = $modulename;
+      $record->mv_table = $mv_table;
+      $record->query = $query;
+      $record->comment = $comment;
+      
+      // convert the schema into a string format
+      $str_schema = var_export($mv_schema, TRUE);
+      $str_schema = preg_replace('/=>\s+\n\s+array/', '=> array', $str_schema);
+      $record->mv_schema = $str_schema;
+  
+      // add the record to the tripal_mviews table and if successful
+      // create the new materialized view in the chado schema
+      if (drupal_write_record('tripal_mviews', $record)) {
+  
+        // drop the table from chado if it exists
+        if (chado_table_exists($mv_table)) {
+          $sql = 'DROP TABLE {' . $mv_table . '}';
+          chado_query($sql);
+        }
+        // create the table
+        chado_create_custom_table($mv_table, $mv_schema, 0, $record->mview_id);
       }
     }
+    catch (Exception $e) {
+      $transaction->rollback();
+      watchdog_exception('tripal_core', $e);
+      $error = _drupal_decode_exception($e);
+      drupal_set_message(t("Could not create the materialized view %table_name: %message.",
+      array('%table_name' => $name, '%message' => $error['!message'])), 'error');
+      return FALSE;
+    }
+    drupal_set_message(t("Materialized view '%name' created", array('%name' => $name)));
+    return TRUE;
   }
   else {
     tripal_report_error('tripal_cv', TRIPAL_WARNING,
       "Materialized view, %vname, already exists. Cannot create.",
       array('%vname' => $name));
     drupal_set_message(t("Materialized view, $name, already exists. Cannot create.", array('%name' => $name)));
+    return FALSE;
   }
 }
 

+ 19 - 15
tripal_core/includes/tripal_core.custom_tables.inc

@@ -80,7 +80,7 @@ function tripal_custom_table_view($table_id) {
   // create a table with each row containig stats for
   // an individual job in the results set.
   $return_url = url("admin/tripal/schema/custom_tables");
-  $output .= "<p><a href=\"$return_url\">" . t("Return to list of custom tables") . "</a></p>";
+  $output = "<p><a href=\"$return_url\">" . t("Return to list of custom tables") . "</a></p>";
   $output .= "<br />";
   $output .= "<p>Details for <b>$custom_table->table_name</b>:</p>";
   $output .= "<br />";
@@ -100,8 +100,8 @@ function tripal_custom_table_view($table_id) {
 
   // build the URLs using the url function so we can handle installations where
   // clean URLs are or are not used
-  $delete_url = url("admin/tripal/custom_tables/action/delete/$custom_table->table_id");
-  $edit_url = url("admin/tripal/custom_tables/edit/$custom_table->table_id");
+  $delete_url = url("admin/tripal/schema/custom_tables/delete/$custom_table->table_id");
+  $edit_url = url("admin/tripal/schema/custom_tables/edit/$custom_table->table_id");
   $output .= "<tr><th>Actions</th>" .
             "<td>" .
             "     <a href='$edit_url'>Edit</a>, " .
@@ -184,11 +184,11 @@ function tripal_custom_tables_form($form, &$form_state = NULL, $table_id = NULL)
        These are not offically sanctioned tables but may be necessary for local data requirements.
        Avoid creating custom tables when possible as other GMOD tools may not recognize these tables
        nor the data in them.  Linker tables or property tables are often a good candidate for
-       a custom table. For example a table to link stocks and libraries (e.g. library_stock) would be
-       a good custom table. Try to model linker or propery tables after existing tables.  If the
+       a custom table. For example a table to link stocks and libraries (e.g. library_stock). 
+       Try to model linker or propery tables after existing tables.  If the
        table already exists it will not be modified.  To force dropping and recreation of the table
-       click the checkbox below.
-    '),
+       click the checkbox below.  Tables are defined usign the ' . l('Drupal Schema API', 'https://api.drupal.org/api/drupal/includes!database!schema.inc/group/schemaapi/7', array('attributes' => array('target' => '_blank')))
+    ),
   );
 
   $form['force_drop']= array(
@@ -200,7 +200,7 @@ function tripal_custom_tables_form($form, &$form_state = NULL, $table_id = NULL)
   $form['schema']= array(
     '#type'          => 'textarea',
     '#title'         => t('Schema Array'),
-    '#description'   => t('Please enter the Drupal Schema API compatible array that defines the table.'),
+    '#description'   => t('Please enter the ' . l('Drupal Schema API', 'https://api.drupal.org/api/drupal/includes!database!schema.inc/group/schemaapi/7', array('attributes' => array('target' => '_blank'))) . ' compatible array that defines the table.'),
     '#required'      => FALSE,
     '#default_value' => $default_schema,
     '#rows'          => 25,
@@ -281,8 +281,7 @@ function tripal_custom_tables_form_validate($form, &$form_state) {
   $force_drop = $form_state['values']['force_drop'];
 
   if (!$schema) {
-    form_set_error($form_state['values']['schema'],
-      t('Schema array field is required.'));
+    form_set_error($form_state['values']['schema'], t('Schema array field is required.'));
   }
 
   // make sure the array is valid
@@ -297,13 +296,18 @@ function tripal_custom_tables_form_validate($form, &$form_state) {
       $success = eval("\$schema_array = $schema;");
       if ($success === FALSE) {
         $error = error_get_last();
-        form_set_error($form_state['values']['schema'],
-          t("The schema array is improperly formatted. Parse Error : " . $error["message"]));
+        form_set_error('schema', t("The schema array is improperly formatted. Parse Error : " . $error["message"]));
       }
       if (is_array($schema_array) and !array_key_exists('table', $schema_array)) {
-        form_set_error($form_state['values']['schema'],
-          t("The schema array must have key named 'table'"));
+        form_set_error('schema', t("The schema array must have key named 'table'"));
+      }
+      
+      // validate the contents of the array
+      $error = chado_validate_custom_table_schema($schema_array);
+      if ($error) {
+        form_set_error('schema', $error);
       }
+      
       if ($action == 'Edit') {
         // see if the table name has changed. If so, then check to make sure
         // it doesn't already exists. We don't want to drop a table we didn't mean to
@@ -411,7 +415,7 @@ function tripal_custom_tables_delete_form_submit($form, &$form_state) {
   $table_id = $form_state['values']['table_id'];
     
   if (strcmp($action, 'Delete') == 0) {
-    tripal_delete_custom_table($table_id);
+    chado_delete_custom_table($table_id);
   }
   else {
     drupal_set_message(t("No action performed."));

+ 17 - 9
tripal_core/includes/tripal_core.mviews.inc

@@ -412,9 +412,9 @@ array (
     ),
   ),
   'indexes' => array (
-    'organism_feature_count_idx1' => array ('organism_id'),
-    'organism_feature_count_idx2' => array ('cvterm_id'),
-    'organism_feature_count_idx3' => array ('feature_type'),
+    'organism_id_idx'  => array ('organism_id'),
+    'cvterm_id_idx'    => array ('cvterm_id'),
+    'feature_type_idx' => array ('feature_type'),
   ),
 )
 </pre>"
@@ -433,14 +433,14 @@ function tripal_mviews_form_validate($form, &$form_state) {
   
   $action    = $form_state['values']['action'];
   $mview_id  = $form_state['values']['mview_id'];
-  $name      = $form_state['values']['name'];
+  $name      = trim($form_state['values']['name']);
   $is_legacy = $form_state['values']['is_legacy'];
   $query     = $form_state['values']['mvquery'];
   
   // if this is a legacy materialized view (no longer supported in Tripal v2.0
   // but code left just in case)
   if ($is_legacy) {
-    $mv_table = $form_state['values']['mv_table'];
+    $mv_table = trim($form_state['values']['mv_table']);
     $mv_specs = $form_state['values']['mv_specs'];
     $indexed  = $form_state['values']['indexed'];
     $special_index = '';//$form_state['values']['special_index'];
@@ -451,8 +451,16 @@ function tripal_mviews_form_validate($form, &$form_state) {
     $indexed = '';
     $special_index = '';
   }
-  $comment = $form_state['values']['comment'];
+  $comment = trim($form_state['values']['comment']);
   $schema  = $form_state['values']['schema'];
+  
+  // validate the contents of the array
+  $schema_array = array();
+  $success = eval("\$schema_array = $schema;");
+  $error = chado_validate_custom_table_schema($schema_array);
+  if ($error) {
+    form_set_error('schema', $error);
+  }
 
   // if both the schema and the older fields for the legacy view are populated then
   // this is an error and we need to let the user know.
@@ -503,12 +511,12 @@ function tripal_mviews_form_submit($form, &$form_state) {
   
   $action     = $form_state['values']['action'];
   $mview_id   = $form_state['values']['mview_id'];
-  $name       = $form_state['values']['name'];
+  $name       = trim($form_state['values']['name']);
   $is_legacy  = $form_state['values']['is_legacy'];
   $query      = $form_state['values']['mvquery'];
-  $comment    = $form_state['values']['comment'];
+  $comment    = trim($form_state['values']['comment']);
   $schema     = $form_state['values']['schema'];
-  $modulename = $form_state['values']['modulename'];
+  $modulename = trim($form_state['values']['modulename']);
   $mv_table = '';
   $mv_specs = '';
   $indexed = '';

+ 16 - 1
tripal_core/tripal_core.install

@@ -21,6 +21,14 @@ function tripal_core_install() {
     tripal_report_error('tripal_core', TRIPAL_ERROR, $message, array());
   }
 
+  // the foreign key specification doesn't really add one to the
+  // Drupal schema, it is just used internally, but we want one
+  db_query('
+      ALTER TABLE {tripal_custom_tables}
+      ADD CONSTRAINT tripal_custom_tables_fk1
+      FOREIGN KEY (mview_id) REFERENCES {tripal_mviews} (mview_id)
+      ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED
+  ');
 }
 /**
  * Implementation of hook_schema().
@@ -55,6 +63,13 @@ function tripal_core_schema() {
  * @ingroup tripal_core
  */
 function tripal_core_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 IF EXISTS tripal_custom_tables_fk1 CASCADE
+    ');
 }
 
 /**
@@ -358,7 +373,7 @@ function tripal_core_update_7200() {
     // Drupal schema, it is just used internally, but we want one
     db_query('
       ALTER TABLE {tripal_custom_tables}
-      ADD CONSTRAINT {tripal_custom_tables_fk1}
+      ADD CONSTRAINT tripal_custom_tables_fk1
       FOREIGN KEY (mview_id) REFERENCES {tripal_mviews} (mview_id)
       ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED
     ');

+ 1 - 1
tripal_core/tripal_core.module

@@ -322,7 +322,7 @@ function tripal_core_menu() {
     'title' => 'Custom Tables',
     'description' => 'Custom tables are added to Chado.',
     'page callback' => 'tripal_custom_table_view',
-    'page arguments' => array(4),
+    'page arguments' => array(5),
     'access arguments' => array('administer tripal'),
     'type' => MENU_CALLBACK,
   );

+ 12 - 3
tripal_core/tripal_core.views_default.inc

@@ -317,7 +317,7 @@ function tripal_core_admin_defaultview_custom_tables() {
   $view->core = 7;
   $view->api_version = '3.0';
   $view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */
-
+  
   /* Display: Master */
   $handler = $view->new_display('default', 'Master', 'default');
   $handler->display->display_options['title'] = 'Custom Tables';
@@ -356,7 +356,7 @@ function tripal_core_admin_defaultview_custom_tables() {
   $handler->display->display_options['fields']['table_id']['id'] = 'table_id';
   $handler->display->display_options['fields']['table_id']['table'] = 'tripal_custom_tables';
   $handler->display->display_options['fields']['table_id']['field'] = 'table_id';
-  $handler->display->display_options['fields']['table_id']['label'] = '';
+  $handler->display->display_options['fields']['table_id']['label'] = 'ID';
   $handler->display->display_options['fields']['table_id']['element_class'] = 'extra-short-column';
   $handler->display->display_options['fields']['table_id']['element_label_class'] = 'extra-short-column';
   $handler->display->display_options['fields']['table_id']['element_label_colon'] = FALSE;
@@ -368,6 +368,15 @@ function tripal_core_admin_defaultview_custom_tables() {
   $handler->display->display_options['fields']['table_name']['label'] = 'Name';
   $handler->display->display_options['fields']['table_name']['alter']['make_link'] = TRUE;
   $handler->display->display_options['fields']['table_name']['alter']['path'] = 'admin/tripal/schema/custom_tables/view/[table_id]';
+  /* Field: Tripal Custom Tables: Materialized View ID */
+  $handler->display->display_options['fields']['mview_id']['id'] = 'mview_id';
+  $handler->display->display_options['fields']['mview_id']['table'] = 'tripal_custom_tables';
+  $handler->display->display_options['fields']['mview_id']['field'] = 'mview_id';
+  $handler->display->display_options['fields']['mview_id']['label'] = 'Is MView';
+  $handler->display->display_options['fields']['mview_id']['alter']['alter_text'] = TRUE;
+  $handler->display->display_options['fields']['mview_id']['alter']['text'] = 'Yes';
+  $handler->display->display_options['fields']['mview_id']['hide_empty'] = TRUE;
+  $handler->display->display_options['fields']['mview_id']['empty_zero'] = TRUE;
   /* Field: Global: Custom text */
   $handler->display->display_options['fields']['nothing']['id'] = 'nothing';
   $handler->display->display_options['fields']['nothing']['table'] = 'views';
@@ -407,7 +416,7 @@ function tripal_core_admin_defaultview_custom_tables() {
     1 => 0,
     3 => 0,
   );
-
+  
   /* Display: Page */
   $handler = $view->new_display('page', 'Page', 'page');
   $handler->display->display_options['path'] = 'admin/tripal/schema/custom_tables/tables';