Browse Source

Merge branch '6.x-dev' of git.drupal.org:sandbox/spficklin/1337878 into 6.x-dev

Stephen Ficklin 12 years ago
parent
commit
43bf50c6f5

+ 1 - 1
tripal_bulk_loader/tripal_bulk_loader.module

@@ -62,7 +62,7 @@ function tripal_bulk_loader_menu() {
     'type' => MENU_NORMAL_ITEM,
   );
   $items['admin/tripal/tripal_bulk_loader_template/jobs'] = array(
-    'title' => 'Jobs',
+    'title' => 'Bulk Loader Jobs',
     'description' => 'Listing of Bulk Loading Jobs',
     'page callback' => 'tripal_bulk_loader_admin_jobs',
     'access arguments' => array('administer site configuration'),

+ 187 - 42
tripal_core/api/tripal_core.api.inc

@@ -85,9 +85,13 @@ require_once "tripal_core.schema_v1.11.api.inc";
  *  - skip_validation: TRUE or FALSE. If TRUE will skip all the validation steps and
  *     just try to insert as is. This is much faster but results in unhandled
  *     non user-friendly errors if the insert fails.
+ *  - return_record: by default, the function will return the record but with
+ *     the primary keys added after insertion.  To simply return TRUE on success
+ *     set this option to FALSE
  *
  * @return
- *  On success this function returns TRUE. On failure, it returns FALSE.
+ *  On success this function returns the inserted record with the new primary keys
+ *  add to the returned array. On failure, it returns FALSE.
  *
  * Example usage:
  * @code
@@ -131,6 +135,9 @@ function tripal_core_chado_insert($table, $values, $options = array()) {
   if (!array_key_exists('skip_validation', $options)) {
     $options['skip_validation'] = FALSE;
   }
+  if (!array_key_exists('return_record', $options)) {
+    $options['return_record'] = TRUE;
+  }
 
   $insert_values = array();
 
@@ -343,15 +350,26 @@ function tripal_core_chado_insert($table, $values, $options = array()) {
   }
 
   // if we have a result then add primary keys to return array
-  if ($result) {
+  if ($options['return_record'] == TRUE and $result) {
     if (array_key_exists('primary key', $table_desc) and is_array($table_desc['primary key'])) {
       foreach ($table_desc['primary key'] as $field) {
-        $value =  db_result(chado_query("SELECT CURRVAL('" . $table . "_" . $field . "_seq')"));
+        $psql = "PREPARE currval_" . $table . "_" . $field . " AS SELECT CURRVAL('" . $table . "_" . $field . "_seq')";
+        $is_prepared = tripal_core_chado_prepare("currval_" . $table . "_" . $field, $psql, array());
+        if ($is_prepared) {
+           $value = db_result(chado_query("EXECUTE currval_". $table . "_" . $field));
+        }
+        else {
+          $sql = "SELECT CURRVAL('" . $table . "_" . $field . "_seq')";
+          $value =  db_result(chado_query($sql));
+        }
         $values[$field] = $value;
       }
     }
     return $values;
   }
+  elseif ($options['return_record'] == FALSE and $result) {
+    return TRUE;
+  }
   else {
     watchdog('tripal_core', "tripal_core_chado_insert: Cannot insert record into $table table: " . print_r($values, 1), array(), 'WATCHDOG_ERROR');
     return FALSE;
@@ -539,8 +557,8 @@ function tripal_core_chado_update($table, $match, $values, $options = NULL) {
   foreach ($update_values as $field => $value) {
 
     if (strcasecmp($table_desc['fields'][$field]['type'], 'serial')==0 OR
-    strcasecmp($table_desc['fields'][$field]['type'], 'int')==0 OR
-    strcasecmp($table_desc['fields'][$field]['type'], 'integer')==0) {
+        strcasecmp($table_desc['fields'][$field]['type'], 'int')==0 OR
+        strcasecmp($table_desc['fields'][$field]['type'], 'integer')==0) {
       if (strcmp($value, '__NULL__') == 0) {
         $sql .= " $field = %s, ";
         $ivalues[] = 'NULL';
@@ -608,8 +626,8 @@ function tripal_core_chado_update($table, $match, $values, $options = NULL) {
   foreach ($update_matches as $field => $value) {
 
     if (strcasecmp($table_desc['fields'][$field]['type'], 'serial')==0 OR
-    strcasecmp($table_desc['fields'][$field]['type'], 'int')==0 OR
-    strcasecmp($table_desc['fields'][$field]['type'], 'integer')==0) {
+        strcasecmp($table_desc['fields'][$field]['type'], 'int')==0 OR
+        strcasecmp($table_desc['fields'][$field]['type'], 'integer')==0) {
       if (strcmp($value, '__NULL__')==0) {
         $sql .= " $field = %s AND ";
         $ivalues[] = 'NULL';
@@ -698,7 +716,7 @@ function tripal_core_chado_update($table, $match, $values, $options = NULL) {
     return TRUE;
   }
   else {
-    watchdog('tripal_core', "Cannot update record in $table table.  Match:" . print_r($match, 1) . ". Values: ". print_r($values, 1), array(), 'WATCHDOG_ERROR');
+    watchdog('tripal_core', "Cannot update record in $table table.  \nMatch:" . print_r($match, 1) . "\nValues: ". print_r($values, 1), array(), 'WATCHDOG_ERROR');
     return FALSE;
   }
 
@@ -716,35 +734,44 @@ function tripal_core_chado_update($table, $match, $values, $options = NULL) {
  *  The name of the chado table for inserting
  * @param $match
  *  An associative array containing the values for locating a record to update.
- *
+ * @param $options
+ *  An array of options such as:
+ *  - statement_name: the name of the prepared statement to use. If the statement
+ *     has not yet been prepared it will be prepared automatically. On subsequent
+ *     calls with the same statement_name only an execute on the previously
+ *     prepared statement will occur.
+ *  - is_prepared: TRUE or FALSE. Whether or not the statement is prepared. By
+ *     default if the statement is not prepared it will be automatically.
+ *     However to avoid this check, which requires a database query you can
+ *     set this value to true and the check will not be performed.
  * @return
  *   On success this function returns TRUE. On failure, it returns FALSE.
  *
  * Example usage:
  * @code
  $umatch = array(
- 'organism_id' => array(
- 'genus' => 'Citrus',
- 'species' => 'sinensis',
- ),
- 'uniquename' => 'orange1.1g000034m.g7',
- 'type_id' => array (
- 'cv_id' => array (
- 'name' => 'sequence',
- ),
- 'name' => 'gene',
- 'is_obsolete' => 0
- ),
+   'organism_id' => array(
+     'genus' => 'Citrus',
+     'species' => 'sinensis',
+   ),
+   'uniquename' => 'orange1.1g000034m.g7',
+   'type_id' => array (
+     'cv_id' => array (
+       'name' => 'sequence',
+     ),
+     'name' => 'gene',
+     'is_obsolete' => 0
+   ),
  );
  $uvalues = array(
- 'name' => 'orange1.1g000034m.g',
- 'type_id' => array (
- 'cv_id' => array (
- 'name' => 'sequence',
- ),
- 'name' => 'mRNA',
- 'is_obsolete' => 0
- ),
+   'name' => 'orange1.1g000034m.g',
+   'type_id' => array (
+     'cv_id' => array (
+       'name' => 'sequence',
+     ),
+     'name' => 'mRNA',
+     'is_obsolete' => 0
+   ),
  );
  *   $result = tripal_core_chado_update('feature',$umatch,$uvalues);
  * @endcode
@@ -758,11 +785,45 @@ function tripal_core_chado_update($table, $match, $values, $options = NULL) {
  *
  * @ingroup tripal_chado_api
  */
-function tripal_core_chado_delete($table, $match) {
+function tripal_core_chado_delete($table, $match, $options = NULL) {
+  // set defaults for options. If we don't set defaults then
+  // we get memory leaks when we try to access the elements
+  if (!is_array($options)) {
+    $options = array();
+  }
+  if (!array_key_exists('is_prepared', $options)) {
+    $options['is_prepared'] = FALSE;
+  }
+  if (!array_key_exists('statement_name', $options)) {
+    $options['statement_name'] = FALSE;
+  }
+
+  // Determine plan of action
+  if ($options['statement_name']) {
+    // we have a prepared statment (or want to create one) so set $prepared = TRUE
+    $prepared = TRUE;
+
+    // we need to get a persistent connection.  If one exists this function
+    // will not recreate it, but if not it will create one and store it in
+    // a Drupal variable for reuse later.
+    $connection = tripal_db_persistent_chado();
+
+    // if we cannot get a connection the abandon the prepared statement
+    if (!$connection ) {
+       $prepared = FALSE;
+       unset($options['statement_name']);
+    }
+  }
+  else {
+    //print "NO STATEMENT (update): $table\n";
+    //debug_print_backtrace();
+  }
+
   $delete_matches = array();  // contains the values for the where clause
 
   // get the table description
   $table_desc = tripal_core_get_chado_table_schema($table);
+  $fields = $table_desc['fields'];
 
   // get the values needed for matching in the SQL statement
   foreach ($match as $field => $value) {
@@ -792,34 +853,117 @@ function tripal_core_chado_delete($table, $match) {
 
   // now build the SQL statement
   $sql = "DELETE FROM {$table} WHERE ";
+  $psql = $sql;
+  $uargs = array();
+  $idatatypes = array();
+  $pvalues = array();
+  $ivalues = array();
   $dargs = array();
+  $void_prepared = 0;
+  $i = 1;
   foreach ($delete_matches as $field => $value) {
+
+    // if we have an array values then this is an "IN" clasue.
+    // we cannot use prepared statements with these
     if (count($value) > 1) {
       $sql .= "$field IN (" . db_placeholders($value, 'varchar') . ") AND ";
       foreach ($value as $v) {
         $dargs[] = $v;
       }
+      $void_prepared = 1;
+      continue;
     }
-    else {
+
+    if (strcasecmp($table_desc['fields'][$field]['type'], 'serial') == 0 OR
+        strcasecmp($table_desc['fields'][$field]['type'], 'int') == 0 OR
+        strcasecmp($table_desc['fields'][$field]['type'], 'integer') == 0) {
       if (strcmp($value, '__NULL__') == 0) {
         $sql .= " $field = NULL AND ";
+        $ivalues[] = 'NULL';
+        $pvalues[] = '%s';
+        $uargs[] = 'NULL';
       }
-      elseif (strcmp($fields[$field]['type'], 'serial') == 0 or
-      strcmp($fields[$field]['type'], 'int') == 0) {
+      else {
         $sql .= " $field = %d AND ";
+        $ivalues[] = $value;
+        $pvalues[] = '%d';
+        $uargs[] = $value;
+      }
+      $idatatypes[] = 'int';
+    }
+    elseif (strcasecmp($table_desc['fields'][$field]['type'], 'boolean')==0) {
+      $sql .= " $field = %s AND ";
+      $pvalues[] = '%s';
+      if (strcmp($value, '__NULL__')==0) {
+        $ivalues[] = 'NULL';
+        $uargs[] = 'NULL';
+      }
+      else {
+        $ivalues[] = $value;
+        $uargs[] = $value;
+      }
+      $idatatypes[] = 'bool';
+    }
+    elseif (strcasecmp($table_desc['fields'][$field]['type'], 'float')==0) {
+      $sql .= " $field = %s AND ";
+      $pvalues[] = '%s';
+      if (strcmp($value, '__NULL__')==0) {
+        $ivalues[] = 'NULL';
+        $uargs[] = 'NULL';
+      }
+      else {
+        $ivalues[] = $value;
+        $uargs[] = $value;
+      }
+      $idatatypes[] = 'numeric';
+    }
+    else {
+      if (strcmp($value, '__NULL__')==0) {
+        $sql .= " $field = %s AND ";
+        $ivalues[] = 'NULL';
+        $uargs[] = 'NULL';
+        $pvalues[] = '%s';
       }
       else {
         $sql .= " $field = '%s' AND ";
+        $ivalues[] = $value;
+        $uargs[] = $value;
+        $pvalues[] = "'%s'";
       }
-      array_push($dargs, $value);
+      $idatatypes[] = 'text';
     }
+    array_push($dargs, $value);
+    $psql .= "$field = \$" . $i . " AND ";
+    $i++;
   }
   $sql = drupal_substr($sql, 0, -4);  // get rid of the trailing 'AND'
+  $psql = drupal_substr($psql, 0, -4);  // get rid of the trailing 'AND'
+
+  // finish constructing the prepared SQL statement
+  $psql =  "PREPARE " . $options['statement_name'] . " (" . implode(', ', $idatatypes) . ") AS " . $psql;
+
+  // finally perform the update.  If successful, return the updated record
+  if ($prepared and !$void_prepared) {
+    // if this is the first time we've run this query
+    // then we need to do the prepare, otherwise just execute
+    if ($options['is_prepared'] != TRUE and
+    !tripal_core_is_sql_prepared($options['statement_name'])) {
+      $status = chado_query($psql);
+      if (!$status) {
+        watchdog('tripal_core', "tripal_core_chado_delete: not able to prepare '%name' statement for: %sql", array('%name' => $options['statement_name'], '%sql' => $sql), 'WATCHDOG ERROR');
+        return FALSE;
+      }
+    }
+    $sql = "EXECUTE " . $options['statement_name'] . "(" . implode(", ", $pvalues) . ")";
+    $resource = chado_query($sql, $ivalues);
+  }
+  // if it's not a prepared statement then insert normally
+  else {
+    $resource = chado_query($sql, $uargs);
+  }
 
   // finally perform the delete.  If successful, return the updated record
-  $previous_db = tripal_db_set_active('chado');  // use chado database
-  $result = db_query($sql, $dargs);
-  tripal_db_set_active($previous_db);  // now use drupal database
+  $result = chado_query($sql, $dargs);
   if ($result) {
     return TRUE;
   }
@@ -875,7 +1019,7 @@ function tripal_core_chado_delete($table, $match) {
  *     However to avoid this check, which requires a database query you can
  *     set this value to true and the check will not be performed.
  *  - is_duplicate: TRUE or FALSE.  Checks the values submited to see if
- *     they violoate any of the unique constraints. If so, the record
+ *     they violate any of the unique constraints. If so, the record
  *     is returned, if not, FALSE is returned.
  *
  *
@@ -2608,7 +2752,8 @@ function tripal_core_is_sql_prepared($statement_name) {
   // @coder-ignore: acting on postgres tables rather then drupal schema therefore, table prefixing does not apply
   $sql = "SELECT name FROM pg_prepared_statements WHERE name = '%s'";
   // do not use 'chado_query' here or it causes memory-leaks
-  $result = db_fetch_object(db_query($sql, $statement_name));
+  //$result = db_fetch_object(db_query($sql, $statement_name));
+  $result = db_fetch_object(chado_query($sql, $statement_name));
 
   if ($result) {
     $_SESSION[$connection][] = $statement_name;
@@ -2651,9 +2796,9 @@ function tripal_core_chado_prepare($statement_name, $psql, $args) {
     }
     else {
       // Although a statement with this name is already prepared it is not the same!
-      watchdog('tripal_core', "chado_prepare: '%name' statement already prepared with different arguments! You want to prepare %sql with %values and the existing statement is %esql with %existing",
-        array('%name' => $statement_name, '%sql' => $psql, '%values' => print_r($args, TRUE), '%esql' => $prepared_sql,
-          '%existing' => print_r($prepared_args, TRUE)), WATCHDOG_ERROR);
+      watchdog('tripal_core', "chado_prepare: statement, '%name', is already prepared with different arguments! The current statement: \n%sql. The current arguments: \n%args. The already prepared statement: \n%esql\nThe current arguments: \n%existing. ",
+        array('%name' => $statement_name, '%sql' => $psql, '%esql' => $prepared_sql,
+          '%existing' => print_r($prepared_args, TRUE), '%args' => print_r($args, TRUE)), WATCHDOG_ERROR);
       return FALSE;
     }
   }

+ 39 - 25
tripal_cv/api/tripal_cv.api.inc

@@ -260,6 +260,7 @@ function tripal_cv_get_cvterm_options($cv_id = 0) {
  */
 function tripal_cv_add_cv($name, $definition) {
   
+  // insert/update values
   $ins_values = array(
     'name'       => $name,
     'definition' => $definition
@@ -339,16 +340,30 @@ function tripal_cv_add_cv($name, $definition) {
  */
 function tripal_cv_add_cvterm($term, $defaultcv = '_global', $is_relationship = 0, 
   $update = 1, $dbname = 'internal') {
-    
+   
   $connection = tripal_db_persistent_chado();
     
   // get the term properties
   $id = $term['id'];
-  $name = $term['name'];
-  $cvname = $term['namespace'];
-  $definition = preg_replace('/^\"(.*)\"/', '\1', $term['def']);
-  $is_obsolete = 0;
-  
+  if (isset($term['name'])) {
+    $name = $term['name'];  
+  }
+  else {
+    $name = $id;  
+  }  
+  if (isset($term['namespace'])) {
+    $cvname = $term['namespace'];
+  } 
+  else {
+    $cvname = $defaultcv;
+  }
+  if (isset($term['def'])) {
+    $definition = preg_replace('/^\"(.*)\"/', '\1', $term['def']);
+  }
+  else {
+    $definition = '';
+  }
+  $is_obsolete = 0;  
   if (isset($term['is_obsolete']) and strcmp($term['is_obsolete'], 'true') == 0) {
     $is_obsolete = 1;
   }  
@@ -359,12 +374,7 @@ function tripal_cv_add_cvterm($term, $defaultcv = '_global', $is_relationship =
   if (!$id) {
     $id = $name;
   }
-  if (!$name) {
-    $name = $id;
-  }
-  if (!$cvname) {
-    $cvname = $defaultcv;
-  }
+
   
   // get the accession and the database from the cvterm id
   if ($dbname) {
@@ -439,7 +449,7 @@ function tripal_cv_add_cvterm($term, $defaultcv = '_global', $is_relationship =
   if (count($result) == 1) {
     $cvterm = $result[0];
     
-    // get the dbxref
+    // get the dbxref record
     $values = array('dbxref_id' => $cvterm->dbxref_id);
     $options = array('statement_name' => 'sel_dbxref_id');
     $result = tripal_core_chado_select('dbxref', array('*'), $values, $options);
@@ -456,17 +466,17 @@ function tripal_cv_add_cvterm($term, $defaultcv = '_global', $is_relationship =
     // wouldn't have made it this far. So, let's swap the database for
     // this term
     if ($db_check->name != $db->name) {
-      
-      // look to see if the correct dbxref record already exists for 
-      // this database
+
+      // look to see if the correct dbxref record already exists for this database
       $values = array(
         'db_id' => $db->db_id,
         'accession' => $accession,       
       );
-      $options = array('staement_name' => 'sel_dbxref_idac');
+      $options = array('statement_name' => 'sel_dbxref_idac');
       $result = tripal_core_chado_select('dbxref', array('*'), $values, $options);
-      
-      // if we already have a good dbxref then we want to update our cvterm to use this dbxref
+
+      // if we already have a good dbxref then we want to update our cvterm 
+      // to use this dbxref
       if (count($result) > 0) {
         $dbxref = $result[0];
         $match = array('cvterm_id' => $cvterm->cvterm_id);
@@ -474,16 +484,17 @@ function tripal_cv_add_cvterm($term, $defaultcv = '_global', $is_relationship =
         $options = array('statement_name' => 'upd_cvterm_db');
         $success = tripal_core_chado_update('cvterm', $match, $values, $options); 
         if (!$success) {
-          watchdog('tripal_cv', "Failed to correct the dbxref id for the $cvterm, " .
-            "$name (id: $accession), for database $dbname", NULL, WATCHDOG_WARNING);
+          watchdog('tripal_cv', "Failed to correct the dbxref id for the cvterm " .
+            "'$name' (id: $accession), for database $dbname", NULL, WATCHDOG_WARNING);
           return 0;
         }
       }
       // if we don't have the record then we want to delete our cvterm and let the code
       // below recreate it with the correct info 
-      else {
+      else {          
         $match = array('cvterm_id' => $cvterm->cvterm_id);
-        tripal_core_chado_delete('cvterm', $match);
+        $options = array('statement_name' => 'del_cvterm_cv');
+        tripal_core_chado_delete('cvterm', $match, $options);
       }      
     }
     
@@ -512,7 +523,10 @@ function tripal_cv_add_cvterm($term, $defaultcv = '_global', $is_relationship =
       
       // if the cvterm_dbxref record does not exists then add it 
       if (count($result)==0) {
-        $options = array('statement_name' => 'ins_cvtermdbxref_cvdbis');
+        $options = array(
+          'statement_name' => 'ins_cvtermdbxref_cvdbis',
+          'return_record' => FALSE,
+        );
         $success = tripal_core_chado_insert('cvterm_dbxref', $values, $options);
         if (!$success) {
           watchdog('tripal_cv', "Failed to find or insert the cvterm_dbxref record for a " . 
@@ -592,7 +606,7 @@ function tripal_cv_add_cvterm($term, $defaultcv = '_global', $is_relationship =
     $success = tripal_core_chado_update('cvterm', $match, $upd_values, $upd_options);    
     if (!$success) {
       watchdog('tripal_cv', "Failed to update the term: $name", NULL, WATCHDOG_WARNING);
-      return FALSE;
+      return 0;
     }
     $cvterm = db_fetch_object(chado_query($cvtermsql, $accession, $dbname));
   } 

+ 194 - 92
tripal_cv/includes/obo_loader.inc

@@ -156,14 +156,10 @@ function tripal_cv_load_obo_v1_2($file, $jobid = NULL, &$newcvs) {
   $newcvs[$header['default-namespace'][0]] = $defaultcv->cv_id;
 
   // add any typedefs to the vocabulary first
+  
   $typedefs = $obo['Typedef'];
   foreach ($typedefs as $typedef) {
-    $t = array();
-    $t['id']     = $typedef['id'][0];
-    $t['name']   = $typedef['name'][0];
-    $t['def']    = $typedef['def'][0];
-    $t['subset'] = $typedef['subset'][0];
-    tripal_cv_obo_process_term($t, $defaultcv->name, $obo, 1, $newcvs, $default_db);
+    tripal_cv_obo_process_term($typedef, $defaultcv->name, $obo, 1, $newcvs, $default_db);
   }
   
   // next add terms to the vocabulary
@@ -193,9 +189,18 @@ function tripal_cv_obo_quiterror($message) {
 function tripal_cv_obo_process_terms($terms, $defaultcv, $obo, $jobid = NULL, &$newcvs, $default_db) {
 
   $i = 0;
-  $count = sizeof($terms);
-  $interval = intval($count * 0.01);
-  if ($interval > 1) {
+  $count = count($terms);
+  
+  // if the number of terms is zero then simply return.
+  // this can happen when an OBO file simply has typedef
+  // entries and no actual terms.
+  if($count == 0) {
+    return 1;
+  }
+  
+  // calculate the interval for updates
+  $interval = intval($count * 0.0001);
+  if ($interval < 1) {
     $interval = 1;
   }
 
@@ -207,18 +212,11 @@ function tripal_cv_obo_process_terms($terms, $defaultcv, $obo, $jobid = NULL, &$
     if ($jobid and $i % $interval == 0) {
       $complete = ($i / $count) * 100;
       tripal_job_set_progress($jobid, intval($complete)); 
-      printf("%d of %d records. (%0.2f%%) memory: %d\r", $i, $count, $complete, memory_get_usage());                                                             
+      printf("%d of %d records. (%0.2f%%) memory: %s bytes\r", $i, $count, $complete, number_format(memory_get_usage()));                                                             
     }                                 
     
     // add/update this term
-    $t = array();
-    $t['id']          = $term['id'][0];
-    $t['name']        = $term['name'][0];
-    $t['def']         = $term['def'][0];
-    $t['subset']      = $term['subset'][0];
-    $t['namespace']   = $term['namespace'][0];
-    $t['is_obsolete'] = $term['is_obsolete'][0];    
-    if (!tripal_cv_obo_process_term($t, $defaultcv, $obo, 0, $newcvs, $default_db)) {
+    if (!tripal_cv_obo_process_term($term, $defaultcv, $obo, 0, $newcvs, $default_db)) {
       tripal_cv_obo_quiterror("Failed to process terms from the ontology");
     }
 
@@ -240,16 +238,33 @@ function tripal_cv_obo_process_terms($terms, $defaultcv, $obo, $jobid = NULL, &$
  * @ingroup tripal_obo_loader
  */
 function tripal_cv_obo_process_term($term, $defaultcv, $obo, $is_relationship = 0, &$newcvs, $default_db) {
-
+  // construct the term array for sending to the tripal_cv_add_cvterm function
+  // for adding a new cvterm
+  $t = array(); 
+  $t['id']            = $term['id'][0];
+  $t['name']          = $term['name'][0];
+  $t['def']           = $term['def'][0];
+  if (isset($term['subset'])) {
+    $t['subset']      = $term['subset'][0];  
+  }  
+  if (isset($term['namespace'])) {
+    $t['namespace']   = $term['namespace'][0];
+  }
+  if (isset($term['is_obsolete'])) {
+    $t['is_obsolete'] = $term['is_obsolete'][0];
+  } 
+  
   // add the cvterm
-  $cvterm = tripal_cv_add_cvterm($term, $defaultcv, $is_relationship, 1, $default_db);
+  $cvterm = tripal_cv_add_cvterm($t, $defaultcv, $is_relationship, 1, $default_db);
   if (!$cvterm) {
     tripal_cv_obo_quiterror("Cannot add the term " . $term['id']);
   }
-  if ($term['namespace']) {
-    $newcvs[$term['namespace']] = $cvterm->cv_id;
+  
+  
+  if (isset($term['namespace'])) {
+    $newcvs[$term['namespace'][0]] = $cvterm->cv_id;
   }
-
+  
   // now handle other properites
   if (isset($term['is_anonymous'])) {
     //print "WARNING: unhandled tag: is_anonymous\n";
@@ -261,11 +276,12 @@ function tripal_cv_obo_process_term($term, $defaultcv, $obo, $is_relationship =
       }
     }
   }
+  
   if (isset($term['subset'])) {
     //print "WARNING: unhandled tag: subset\n";
   }
   // add synonyms for this cvterm
-  if (isset($term['synonym'])) {
+  if (isset($term['synonym'])) {    
     if (!tripal_cv_obo_add_synonyms($term, $cvterm)) {
       tripal_cv_obo_quiterror("Cannot add synonyms");
     }
@@ -297,6 +313,7 @@ function tripal_cv_obo_process_term($term, $defaultcv, $obo, $is_relationship =
       tripal_cv_obo_quiterror("Cannot add/update synonyms");
     }
   }
+  
   // add the comment to the cvtermprop table
   if (isset($term['comment'])) {
     $comments = $term['comment'];
@@ -308,6 +325,7 @@ function tripal_cv_obo_process_term($term, $defaultcv, $obo, $is_relationship =
       $j++;
     }
   }
+  
   // add any other external dbxrefs
   if (isset($term['xref'])) {
     foreach ($term['xref'] as $xref) {
@@ -316,6 +334,7 @@ function tripal_cv_obo_process_term($term, $defaultcv, $obo, $is_relationship =
       }
     }
   }
+  
   if (isset($term['xref_analog'])) {
     foreach ($term['xref_analog'] as $xref) {
       if (!tripal_cv_obo_add_cvterm_dbxref($cvterm, $xref)) {
@@ -334,11 +353,12 @@ function tripal_cv_obo_process_term($term, $defaultcv, $obo, $is_relationship =
   // add is_a relationships for this cvterm
   if (isset($term['is_a'])) {
     foreach ($term['is_a'] as $is_a) {
-      if (!tripal_cv_obo_add_relationship($cvterm, $defaultcv, $obo, 'is_a', $is_a, $is_relationship)) {
+      if (!tripal_cv_obo_add_relationship($cvterm, $defaultcv, $obo, 'is_a', $is_a, $is_relationship, $default_db)) {
         tripal_cv_obo_quiterror("Cannot add relationship is_a: $is_a");
       }
     }
   }
+  
   if (isset($term['intersection_of'])) {
     //print "WARNING: unhandled tag: intersection_of\n";
   }
@@ -352,7 +372,7 @@ function tripal_cv_obo_process_term($term, $defaultcv, $obo, $is_relationship =
     foreach ($term['relationship'] as $value) {
       $rel = preg_replace('/^(.+?)\s.+?$/', '\1', $value);
       $object = preg_replace('/^.+?\s(.+?)$/', '\1', $value);
-      if (!tripal_cv_obo_add_relationship($cvterm, $defaultcv, $obo, $rel, $object, $is_relationship)) {
+      if (!tripal_cv_obo_add_relationship($cvterm, $defaultcv, $obo, $rel, $object, $is_relationship, $default_db)) {
         tripal_cv_obo_quiterror("Cannot add relationship $rel: $object");
       }
     }
@@ -377,28 +397,55 @@ function tripal_cv_obo_process_term($term, $defaultcv, $obo, $is_relationship =
  *
  * @ingroup tripal_obo_loader
  */
-function tripal_cv_obo_add_relationship($cvterm, $defaultcv, $obo, $rel, $objname, $object_is_relationship = 0) {
+function tripal_cv_obo_add_relationship($cvterm, $defaultcv, $obo, $rel, 
+  $objname, $object_is_relationship = 0, $default_db = 'OBO_REL') {
 
   // make sure the relationship cvterm exists
   $term = array(
-    'name' => array($rel),
-    'id' => array($rel),
-    'definition' => array(''),
-    'is_obsolete' => array(0),
+    'name' => $rel,
+    'id' => "$default_db:$rel",
+    'definition' => '',
+    'is_obsolete' => 0,
   );
-  $relcvterm = tripal_cv_add_cvterm($term, $defaultcv, 1, 0);
+  $relcvterm = tripal_cv_add_cvterm($term, $defaultcv, 1, 0, $default_db);
+  
   if (!$relcvterm) {
-    tripal_cv_obo_quiterror("Cannot find or insert the relationship term: $rel\n");
+    // if the relationship term couldn't be found in the default_db provided 
+    // then do on more check to find it in the relationship ontology
+    $term = array(
+      'name' => $rel,
+      'id' => "OBO_REL:$rel",
+      'definition' => '',
+      'is_obsolete' => 0,
+    ); 
+    $relcvterm = tripal_cv_add_cvterm($term, $defaultcv, 1, 0, 'OBO_REL');
+    if (!$relcvterm) {
+      tripal_cv_obo_quiterror("Cannot find the relationship term in the current ontology or in the relationship ontology: $rel\n");
+    }
   }
 
   // get the object term
-  $objterm = tripal_cv_obo_get_term($obo, $objname);
-  if (!$objterm) {
+  $oterm = tripal_cv_obo_get_term($obo, $objname);
+  if (!$oterm) {
     tripal_cv_obo_quiterror("Could not find object term $objname\n");
   }
-  $objcvterm = tripal_cv_add_cvterm($objterm, $defaultcv, $object_is_relationship, 1);
+  
+  $objterm = array(); 
+  $objterm['id']            = $oterm['id'][0];
+  $objterm['name']          = $oterm['name'][0];
+  $objterm['def']           = $oterm['def'][0];
+  if (isset($oterm['subset'])) {
+    $objterm['subset']      = $oterm['subset'][0];  
+  }  
+  if (isset($oterm['namespace'])) {
+    $objterm['namespace']   = $oterm['namespace'][0];
+  }
+  if (isset($oterm['is_obsolete'])) {
+    $objterm['is_obsolete'] = $oterm['is_obsolete'][0];
+  }
+  $objcvterm = tripal_cv_add_cvterm($objterm, $defaultcv, $object_is_relationship, 1, $default_db);  
   if (!$objcvterm) {
-    tripal_cv_obo_quiterror("Cannot add/find cvterm");
+    tripal_cv_obo_quiterror("Cannot add cvterm " . $oterm['name'][0]);
   }
 
   // check to see if the cvterm_relationship already exists, if not add it
@@ -410,9 +457,10 @@ function tripal_cv_obo_add_relationship($cvterm, $defaultcv, $obo, $rel, $objnam
   $options = array('statement_name' => 'sel_cvtermrelationship_tysuob');
   $result = tripal_core_chado_select('cvterm_relationship', array('*'), $values, $options);
   if (count($result) == 0) {
-    $options = array('statement_name' => 'ins_cvtermrelationship_tysuob');
-    $sql = "INSERT INTO {cvterm_relationship} ".
-           "(type_id,subject_id,object_id) VALUES (%d,%d,%d)";
+    $options = array(
+      'statement_name' => 'ins_cvtermrelationship_tysuob',
+      'return_record' => FALSE
+    );
     $success = tripal_core_chado_insert('cvterm_relationship', $values, $options);
     if (!$success) {
       tripal_cv_obo_quiterror("Cannot add term relationship: '$cvterm->name' $rel '$objcvterm->name'");
@@ -427,6 +475,7 @@ function tripal_cv_obo_add_relationship($cvterm, $defaultcv, $obo, $rel, $objnam
  * @ingroup tripal_obo_loader
  */
 function tripal_cv_obo_get_term($obo, $id) {
+  /*
   foreach ($obo as $type) {
     foreach ($type as $term) {
       $accession = $term['id'][0];
@@ -434,6 +483,14 @@ function tripal_cv_obo_get_term($obo, $id) {
         return $term;
       }
     }
+  } */
+  // iterate through each of the types in the
+  // obo file (parsed into memory) and look
+  // for this term.  If found, return it.
+  foreach ($obo as $type) {
+    if (array_key_exists($id, $type)) {
+      return $type[$id];
+    }
   }
 
   return FALSE;
@@ -446,7 +503,7 @@ function tripal_cv_obo_get_term($obo, $id) {
 function tripal_cv_obo_add_synonyms($term, $cvterm) {
 
   // make sure we have a 'synonym_type' vocabulary
-  $syncv = tripal_cv_add_cv('synonym_type');
+  $syncv = tripal_cv_add_cv('synonym_type', 'A vocabulary added by the Tripal CV module OBO loader for storing synonym types.');
 
   // now add the synonyms
   if (isset($term['synonym'])) {
@@ -454,32 +511,39 @@ function tripal_cv_obo_add_synonyms($term, $cvterm) {
       
       // separate out the synonym definition and the synonym type
       $def = preg_replace('/^\s*"(.*)"\s*.*$/', '\1', $synonym);
-      $type = drupal_strtolower(preg_replace('/^.*"\s+(.*?)\s+.*$/', '\1', $synonym));
+      // the scope will be 'EXACT', etc...
+      $scope = drupal_strtolower(preg_replace('/^.*"\s+(.*?)\s+.*$/', '\1', $synonym));
+      if (!$scope) {  // if no scope then default to 'exact'
+        $scope = 'exact'; 
+      } 
 
       // make sure the synonym type exists in the 'synonym_type' vocabulary
       $values = array(
-        'name' => $type,
+        'name' => $scope,
         'cv_id' => array(
           'name' => 'synonym_type',
         ),
       );
-      $options = array('statement_name' => 'sel_cvterm_nacv');
+      $options = array('statement_name' => 'sel_cvterm_nacv', 'is_updlicate' => 1);
       $results = tripal_core_chado_select('cvterm', array('*'), $values, $options);
 
       // if it doesn't exist then add it
-      if (count($results) == 0) {
+      if (!$results) {
         // build a 'term' object so we can add the missing term
         $term = array(
-           'name' => array($type),
-           'id' => array("internal:$type"),
-           'definition' => array(''),
-           'is_obsolete' => array(0),
+           'name' => $scope,
+           'id' => "internal:$scope",
+           'definition' => '',
+           'is_obsolete' => 0,
         );
-        $syntype = tripal_cv_add_cvterm($term, $syncv, 0, 1);
+        $syntype = tripal_cv_add_cvterm($term, $syncv->name, 0, 1);
         if (!$syntype) {
-          tripal_cv_obo_quiterror("Cannot add synonym type: internal:$type");
+          tripal_cv_obo_quiterror("Cannot add synonym type: internal:$scope");
         }
       }
+      else {
+        $syntype = $results[0];
+      }
 
       // make sure the synonym doesn't already exists
       $values = array(
@@ -494,7 +558,10 @@ function tripal_cv_obo_add_synonyms($term, $cvterm) {
           'synonym' => $def,
           'type_id' => $syntype->cvterm_id
         );
-        $options = array('statement_name' => 'ins_cvtermsynonym_cvsy');
+        $options = array(
+          'statement_name' => 'ins_cvtermsynonym_cvsy',
+          'return_record' => FALSE
+        );
         $success = tripal_core_chado_insert('cvtermsynonym', $values, $options);
         if (!$success) {
           tripal_cv_obo_quiterror("Failed to insert the synonym for term: $name ($def)");
@@ -553,7 +620,7 @@ function tripal_cv_obo_parse($obo_file, &$obo, &$header) {
 
     if (preg_match('/^\s*\[/', $line)) {  // at the first stanza we're out of header
       $in_header = 0;
-      // load the stanza we just finished reading
+      // store the stanza we just finished reading
       if (sizeof($stanza) > 0) {
         if (!isset($obo[$type])) {
           $obo[$type] = array();
@@ -578,7 +645,7 @@ function tripal_cv_obo_parse($obo_file, &$obo, &$header) {
     $tag = $pair[0];
     $value = ltrim(rtrim($pair[1]));// remove surrounding spaces
     
-    // look for the default DB
+    // if this is the ID then look for the default DB
     $matches = array();
     if ($tag == 'id' and preg_match('/^(.+?):.*$/', $value, $matches)) {
        $default_db = $matches[1];
@@ -651,12 +718,21 @@ function tripal_cv_obo_add_cvterm_dbxref($cvterm, $xref) {
   }
 
   // finally add the cvterm_dbxref but first check to make sure it exists
-  $sql = "SELECT * from {cvterm_dbxref} WHERE cvterm_id = %d and dbxref_id = %d";
-  if (!db_fetch_object(db_query($sql, $cvterm->cvterm_id, $dbxref->dbxref_id))) {
-    $sql = "INSERT INTO {cvterm_dbxref} (cvterm_id,dbxref_id)".
-           "VALUES (%d,%d)";
-    if (!db_query($sql, $cvterm->cvterm_id, $dbxref->dbxref_id)) {
+  $values = array(
+    'cvterm_id' => $cvterm->cvterm_id,
+    'dbxref_id' => $dbxref->dbxref_id,
+  );
+  $options = array('statement_name' => 'sel_cvtermdbxref_cvdb');
+  $result = tripal_core_chado_select('cvterm_dbxref', array('*'), $values, $options);
+  if (count($result) == 0) {    
+    $ins_options = array(
+      'statement_name' => 'ins_cvtermdbxref_cvdb',
+      'return_record' => FALSE
+    );
+    $result = tripal_core_chado_insert('cvterm_dbxref', $values, $ins_options);
+    if (!$result){
       tripal_cv_obo_quiterror("Cannot add cvterm_dbxref: $xref");
+      return FALSE;
     }
   }
 
@@ -676,41 +752,57 @@ function tripal_cv_obo_add_cvterm_prop($cvterm, $property, $value, $rank) {
   }
 
   // get the property type cvterm.  If it doesn't exist then we want to add it
-  $sql = "
-      SELECT *
-      FROM {cvterm} CVT INNER JOIN {cv} CV on CVT.cv_id = CV.cv_id
-      WHERE CVT.name = '%s' and CV.name = '%s'
-  ";
-  $cvproptype = db_fetch_object(db_query($sql, $property, 'cvterm_property_type'));
-  if (!$cvproptype) {
+  $values = array(
+    'name' => $property,
+    'cv_id' => $cv->cv_id,
+  );
+  $options = array('statement_name' => 'sel_cvterm_nacv_na');
+  $results = tripal_core_chado_select('cvterm', array('*'), $values, $options);
+  if (count($results) == 0) {    
     $term = array(
-      'name' => array($property),
-      'id' => array("internal:$property"),
-      'definition' => array(''),
-      'is_obsolete' => array(0),
+      'name' => $property,
+      'id' => "internal:$property",
+      'definition' => '',
+      'is_obsolete' => 0,
     );
-    $cvproptype = tripal_cv_add_cvterm($term, $cv, 0, 0);
+    $cvproptype = tripal_cv_add_cvterm($term, $cv->name, 0, 0);
     if (!$cvproptype) {
       tripal_cv_obo_quiterror("Cannot add cvterm property: internal:$property");
+      return FALSE;
     }
   }
-
+  else {
+    $cvproptype = $results[0];
+  }
 
   // remove any properties that currently exist for this term.  We'll reset them
   if ($rank == 0) {
-    $sql = "DELETE FROM {cvtermprop} WHERE cvterm_id = %d";
-    db_query($sql, $cvterm->cvterm_id);
+    $values = array('cvterm_id' => $cvterm->cvterm_id);
+    $options = array('statement_name' => 'del_cvtermprop_cv');
+    $success = tripal_core_chado_delete('cvtermprop', $values, $options);
+    if (!$success) {
+       tripal_cv_obo_quiterror("Could not remove existing properties to update property $property for term\n");
+       return FALSE;
+    }    
   }
 
   // now add the property
-  $sql = "INSERT INTO {cvtermprop} (cvterm_id,type_id,value,rank) ".
-        "VALUES (%d, %d, '%s',%d)";
-  if (!db_query($sql, $cvterm->cvterm_id, $cvproptype->cvterm_id, $value, $rank)) {
+  $values = array(
+    'cvterm_id' => $cvterm->cvterm_id,
+    'type_id' => $cvproptype->cvterm_id,
+    'value' => $value,
+    'rank' => $rank,
+  );
+  $options = array(
+    'statement_name' => 'ins_cvtermprop_cvtyvara',
+    'return_record' => FALSE,
+  );
+  $result = tripal_core_chado_insert('cvtermprop', $values, $options);
+  if (!$result) {
     tripal_cv_obo_quiterror("Could not add property $property for term\n");
+    return FALSE;
   }
-
   return TRUE;
-
 }
 
 
@@ -721,20 +813,30 @@ function tripal_cv_obo_add_cvterm_prop($cvterm, $property, $value, $rank) {
 function tripal_cv_obo_add_dbxref($db_id, $accession, $version='', $description='') {
 
   // check to see if the dbxref exists if not, add it
-  $dbxsql = "SELECT dbxref_id FROM {dbxref} WHERE db_id = %d and accession = '%s'";
-  $dbxref = db_fetch_object(db_query($dbxsql, $db_id, $accession));
-  if (!$dbxref) {
-    $sql = "
-       INSERT INTO {dbxref} (db_id, accession, version, description)
-       VALUES (%d,'%s','%s','%s')
-    ";
-    if (!db_query($sql, $db_id, $accession, $version, $description)) {
+  $values = array(
+    'db_id' => $db_id,
+    'accession' => $accession,
+  );
+  $options = array('statement_name' => 'sel_dbxref_idac');
+  $result = tripal_core_chado_select('dbxref', array('dbxref_id'), $values, $options);
+  if (count($result) == 0){
+    $ins_values = array(
+      'db_id'       => $db_id,
+      'accession'   => $accession,
+      'version'     => $version,
+      'description' => $description,
+    );
+    $ins_options = array(
+      'statement_name' => 'ins_dbxref_idacvede',
+      'return_record' => FALSE
+    );
+    $result = tripal_core_chado_insert('dbxref', $ins_values, $ins_options);
+    if (!$result) {
       tripal_cv_obo_quiterror("Failed to insert the dbxref record $accession");
-    }
-    print "Added Dbxref accession: $accession\n";
-    $dbxref = db_fetch_object(db_query($dbxsql, $db_id, $accession));
+      return FALSE;
+    } 
+    $result = tripal_core_chado_select('dbxref', array('dbxref_id'), $values, $options);    
   }
-  return $dbxref;
-
+  return $result[0];
 }
 

+ 1 - 1
tripal_cv/tripal_cv.module

@@ -89,7 +89,7 @@ function tripal_cv_menu() {
   );
 
   $items['admin/tripal/tripal_cv/obo_loader'] = array(
-    'title' => 'Add/Update Ontology With OBO File',
+    'title' => 'Load Ontology With OBO File',
     'page callback' => 'drupal_get_form',
     'page arguments' => array('tripal_cv_obo_form'),
     'access arguments' => array('access administration pages'),

+ 2 - 2
tripal_db/tripal_db.api.inc

@@ -358,11 +358,11 @@ function tripal_db_add_dbxref($db_id, $accession, $version = '', $description =
     'db_id'     => $db_id,
     'accession' => $accession,
   );
-  $sel_options = array('statement_name' => 'sel_dbxref_dbacve');
+  $sel_options = array('statement_name' => 'sel_dbxref_dbacve', 'is_duplicate' => 1);
   $result = tripal_core_chado_select('dbxref', array('*'), $sel_values, $sel_options);
   
   // if it doesn't already exist then add it
-  if (count($result) == 0) {
+  if (!$result) {
     $ins_options = array('statement_name' => 'ins_dbxref_dbacvede');
     $success = tripal_core_chado_insert('dbxref', $ins_values, $ins_options);
     if (!$success) {

+ 4 - 4
tripal_feature/includes/gff_loader.inc

@@ -381,8 +381,8 @@ function tripal_feature_load_gff3($gff_file, $organism_id, $analysis_id,
     }
 
     // get the type record
-    if (!tripal_core_is_sql_prepared('sel_cvterm_cvid_cvtname_synonym')) {
-      $psql = "PREPARE sel_cvterm_cvid_cvtname_synonym (int, text, text) AS
+    if (!tripal_core_is_sql_prepared('sel_cvterm_idnasy')) {
+      $psql = "PREPARE sel_cvterm_idnasy (int, text, text) AS
                SELECT CVT.cvterm_id, CVT.cv_id, CVT.name, CVT.definition,
                   CVT.dbxref_id, CVT.is_obsolete, CVT.is_relationshiptype
                FROM {cvterm} CVT
@@ -391,14 +391,14 @@ function tripal_feature_load_gff3($gff_file, $organism_id, $analysis_id,
                WHERE CV.cv_id = $1 and (CVT.name = $2 or CVTS.synonym = $3)";
        $status = chado_query($psql);
        if (!$status) {
-         watchdog('T_gff3_loader', 'cannot prepare statement \'sel_cvterm_cvid_cvtname_synonym\' for ontology term %line_num', 
+         watchdog('T_gff3_loader', 'cannot prepare statement \'sel_cvterm_idnasy\' for ontology term %line_num', 
            array('%line_num' => $line_num), WATCHDOG_ERROR);
          return '';
       }
       
     } 
   
-    $result = chado_query("EXECUTE sel_cvterm_cvid_cvtname_synonym (%d, '%s', '%s')", $cv->cv_id, $type, $type);
+    $result = chado_query("EXECUTE sel_cvterm_idnasy (%d, '%s', '%s')", $cv->cv_id, $type, $type);
    
     $cvterm = db_fetch_object($result);
     if (!$cvterm) {

+ 13 - 2
tripal_feature/tripal_feature.module

@@ -346,6 +346,9 @@ function tripal_feature_block($op = 'list', $delta = 0, $edit=array()) {
       $blocks['properties']['info'] = t('Tripal Feature Properties');
       $blocks['properties']['cache'] = BLOCK_NO_CACHE;;
 
+      $blocks['terms']['info'] = t('Tripal Annotated Terms');
+      $blocks['terms']['cache'] = BLOCK_NO_CACHE;;
+
       $blocks['alignments']['info'] = t('Tripal Feature Alignments');
       $blocks['alignments']['cache'] = BLOCK_NO_CACHE;
 
@@ -382,7 +385,11 @@ function tripal_feature_block($op = 'list', $delta = 0, $edit=array()) {
         case 'properties':
           $block['subject'] = t('Properties');
           $block['content'] = theme('tripal_feature_properties', $node);
-          break;;
+          break;
+        case 'terms':
+          $block['subject'] = t('Annotated Terms');
+          $block['content'] = theme('tripal_feature_terms', $node);
+          break;
         case 'sequence':
           $block['subject'] = t('Sequence');
           $block['content'] = theme('tripal_feature_sequence', $node);
@@ -1944,6 +1951,10 @@ function tripal_feature_theme() {
        'arguments' => array('node' => NULL),
        'template' => 'tripal_feature_properties',
     ),
+    'tripal_feature_terms' => array(
+       'arguments' => array('node' => NULL),
+       'template' => 'tripal_feature_terms',
+    ),
     'tripal_feature_alignments' => array(
        'arguments' => array('node' => NULL),
        'template' => 'tripal_feature_alignments',
@@ -2827,4 +2838,4 @@ function tripal_feature_match_features_page($id) {
   $output = "<p>The following features match the name '$id'.</p>";
   $output .= theme_table($header, $rows, $table_attrs, $caption);
   return $output;
-}
+}