mviews.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546
  1. <?php
  2. /**
  3. * @defgroup tripal_mviews_api Core Module Materalized Views API
  4. * @{
  5. * Provides an application programming interface (API) to manage materialized views in Chado.
  6. * The Perl-based chado comes with an interface for managing materialzed views. This
  7. * API provides an alternative Drupal-based method.
  8. * @}
  9. * @ingroup tripal_api
  10. */
  11. /**
  12. * Add a materialized view to the chado database to help speed data access.
  13. *
  14. * @param $name
  15. * The name of the materialized view.
  16. * @param $modulename
  17. * The name of the module submitting the materialized view (e.g. 'tripal_library')
  18. * @param $mv_table
  19. * The name of the table to add to chado. This is the table that can be queried.
  20. * @param $mv_specs
  21. * The table definition
  22. * @param $indexed
  23. * The columns that are to be indexed
  24. * @param $query
  25. * The SQL query that loads the materialized view with data
  26. * @param $special_index
  27. * function
  28. *
  29. * @ingroup tripal_mviews_api
  30. */
  31. function tripal_add_mview ($name,$modulename,$mv_table,$mv_specs,$indexed,$query,$special_index,$comment=NULL){
  32. $record = new stdClass();
  33. $record->name = $name;
  34. $record->modulename = $modulename;
  35. $record->mv_schema = 'DUMMY';
  36. $record->mv_table = $mv_table;
  37. $record->mv_specs = $mv_specs;
  38. $record->indexed = $indexed;
  39. $record->query = $query;
  40. $record->special_index = $special_index;
  41. $record->comment = $comment;
  42. // add the record to the tripal_mviews table and if successful
  43. // create the new materialized view in the chado schema
  44. if(drupal_write_record('tripal_mviews',$record)){
  45. // drop the table from chado if it exists
  46. $previous_db = tripal_db_set_active('chado'); // use chado database
  47. if (db_table_exists($mv_table)) {
  48. $sql = "DROP TABLE $mv_table";
  49. db_query($sql);
  50. }
  51. tripal_db_set_active($previous_db); // now use drupal database
  52. // now add the table for this view
  53. $index = '';
  54. if($indexed){
  55. $index = ", CONSTRAINT ". $mv_table . "_index UNIQUE ($indexed) ";
  56. }
  57. $sql = "CREATE TABLE {$mv_table} ($mv_specs $index)";
  58. $previous_db = tripal_db_set_active('chado'); // use chado database
  59. $results = db_query($sql);
  60. tripal_db_set_active($previous_db); // now use drupal database
  61. if($results){
  62. drupal_set_message(t("View '$name' created"));
  63. } else {
  64. // if we failed to create the view in chado then
  65. // remove the record from the tripal_jobs table
  66. $sql = "DELETE FROM {tripal_mviews} ".
  67. "WHERE mview_id = $record->mview_id";
  68. db_query($sql);
  69. }
  70. }
  71. }
  72. /**
  73. * Edits a materialized view to the chado database to help speed data access.
  74. *
  75. * @param $mview_id
  76. * The mview_id of the materialized view to edit
  77. * @param $name
  78. * The name of the materialized view.
  79. * @param $modulename
  80. * The name of the module submitting the materialized view (e.g. 'tripal_library')
  81. * @param $mv_table
  82. * The name of the table to add to chado. This is the table that can be queried.
  83. * @param $mv_specs
  84. * The table definition
  85. * @param $indexed
  86. * The columns that are to be indexed
  87. * @param $query
  88. * The SQL query that loads the materialized view with data
  89. * @param $special_index
  90. * function
  91. *
  92. * @ingroup tripal_mviews_api
  93. */
  94. function tripal_edit_mview ($mview_id,$name,$modulename,$mv_table,$mv_specs,$indexed,$query,$special_index,$comment){
  95. $record = new stdClass();
  96. $record->mview_id = $mview_id;
  97. $record->name = $name;
  98. $record->modulename = $modulename;
  99. $record->mv_schema = 'DUMMY';
  100. $record->mv_table = $mv_table;
  101. $record->mv_specs = $mv_specs;
  102. $record->indexed = $indexed;
  103. $record->query = $query;
  104. $record->special_index = $special_index;
  105. $record->last_update = 0;
  106. $record->status = '';
  107. $record->comment = $comment;
  108. // drop the table from chado if it exists
  109. $sql = "SELECT * FROM {tripal_mviews} WHERE mview_id = $mview_id ";
  110. $mview = db_fetch_object(db_query($sql));
  111. $previous_db = tripal_db_set_active('chado'); // use chado database
  112. if (db_table_exists($mview->mv_table)) {
  113. $sql = "DROP TABLE $mview->mv_table";
  114. db_query($sql);
  115. }
  116. tripal_db_set_active($previous_db); // now use drupal database
  117. // update the record to the tripal_mviews table and if successful
  118. // create the new materialized view in the chado schema
  119. if(drupal_write_record('tripal_mviews',$record,'mview_id')){
  120. // drop the table from chado if it exists
  121. $previous_db = tripal_db_set_active('chado'); // use chado database
  122. if (db_table_exists($mv_table)) {
  123. $sql = "DROP TABLE $mv_table";
  124. db_query($sql);
  125. }
  126. tripal_db_set_active($previous_db); // now use drupal database
  127. // now add the table for this view
  128. $index = '';
  129. if($indexed){
  130. $index = ", CONSTRAINT ". $mv_table . "_index UNIQUE ($indexed) ";
  131. }
  132. $sql = "CREATE TABLE {$mv_table} ($mv_specs $index)";
  133. $previous_db = tripal_db_set_active('chado'); // use chado database
  134. $results = db_query($sql);
  135. tripal_db_set_active($previous_db); // now use drupal database
  136. if($results){
  137. drupal_set_message(t("View '$name' updated. All results cleared. Please re-populate the view."));
  138. } else {
  139. // if we failed to create the view in chado then
  140. // remove the record from the tripal_jobs table
  141. $sql = "DELETE FROM {tripal_mviews} ".
  142. "WHERE mview_id = $record->mview_id";
  143. db_query($sql);
  144. }
  145. }
  146. }
  147. /**
  148. * Retrieve the materialized view_id given the name
  149. *
  150. * @param $view_name
  151. * The name of the materialized view
  152. *
  153. * @return
  154. * The unique identifier for the given view
  155. *
  156. * @ingroup tripal_mviews_api
  157. */
  158. function tripal_mviews_get_mview_id ($view_name){
  159. $sql = "SELECT * FROM {tripal_mviews} ".
  160. "WHERE name = '%s'";
  161. if(db_table_exists('tripal_mviews')){
  162. $mview = db_fetch_object(db_query($sql,$view_name));
  163. if($mview){
  164. return $mview->mview_id;
  165. }
  166. }
  167. return 0;
  168. }
  169. /**
  170. *
  171. *
  172. * @ingroup tripal_core
  173. */
  174. function tripal_mviews_action ($op,$mview_id,$redirect=0){
  175. global $user;
  176. $args = array("$mview_id");
  177. if(!$mview_id){
  178. return '';
  179. }
  180. // get this mview details
  181. $sql = "SELECT * FROM {tripal_mviews} WHERE mview_id = $mview_id ";
  182. $mview = db_fetch_object(db_query($sql));
  183. // add a job or perform the action based on the given operation
  184. if($op == 'update'){
  185. tripal_add_job("Populate materialized view '$mview->name'",'tripal_core',
  186. 'tripal_update_mview',$args,$user->uid);
  187. }
  188. if($op == 'delete'){
  189. // remove the mview from the tripal_mviews table
  190. $sql = "DELETE FROM {tripal_mviews} ".
  191. "WHERE mview_id = $mview_id";
  192. db_query($sql);
  193. // drop the table from chado if it exists
  194. $previous_db = tripal_db_set_active('chado'); // use chado database
  195. if (db_table_exists($mview->mv_table)) {
  196. $sql = "DROP TABLE $mview->mv_table";
  197. db_query($sql);
  198. }
  199. tripal_db_set_active($previous_db); // now use drupal database
  200. }
  201. if($redirect){
  202. drupal_goto("admin/tripal/mviews");
  203. }
  204. }
  205. /**
  206. * Update a Materialized View
  207. *
  208. * @param $mview_id
  209. * The unique identifier for the materialized view to be updated
  210. *
  211. * @return
  212. * True if successful, false otherwise
  213. *
  214. * @ingroup tripal_mviews_api
  215. */
  216. function tripal_update_mview ($mview_id){
  217. $sql = "SELECT * FROM {tripal_mviews} WHERE mview_id = %d ";
  218. $mview = db_fetch_object(db_query($sql,$mview_id));
  219. if($mview){
  220. $previous_db = tripal_db_set_active('chado'); // use chado database
  221. $results = db_query("DELETE FROM {$mview->mv_table}");
  222. $results = db_query("INSERT INTO $mview->mv_table ($mview->query)");
  223. tripal_db_set_active($previous_db); // now use drupal database
  224. if($results){
  225. $sql = "SELECT count(*) as cnt FROM $mview->mv_table";
  226. $count = db_fetch_object(db_query($sql));
  227. $record = new stdClass();
  228. $record->mview_id = $mview_id;
  229. $record->last_update = time();
  230. $record->status = "Populated with " . $count->cnt . " rows";
  231. drupal_write_record('tripal_mviews',$record,'mview_id');
  232. return 1;
  233. } else {
  234. # print and save the error message
  235. $record = new stdClass();
  236. $record->mview_id = $mview_id;
  237. $record->status = "ERROR populating. See Drupal's recent log entries for details.";
  238. print $record->status . "\n";
  239. drupal_write_record('tripal_mviews',$record,'mview_id');
  240. return 0;
  241. }
  242. }
  243. }
  244. /**
  245. *
  246. *
  247. * @ingroup tripal_mviews_api
  248. */
  249. function tripal_mview_report ($mview_id) {
  250. // get this mview details
  251. $sql = "SELECT * FROM {tripal_mviews} WHERE mview_id = $mview_id ";
  252. $mview = db_fetch_object(db_query($sql));
  253. // create a table with each row containig stats for
  254. // an individual job in the results set.
  255. $return_url = url("admin/tripal/mviews/");
  256. $output .= "<p><a href=\"$return_url\">Return to table of materialized views.</a></p>";
  257. $output .= "<br />";
  258. $output .= "<p>Details for <b>$mview->name</b>:</p>";
  259. $output .= "<br />";
  260. $output .= "<table class=\"border-table\">";
  261. if($mview->name){
  262. $output .= " <tr>".
  263. " <th>View Name</th>".
  264. " <td>$mview->name</td>".
  265. " </tr>";
  266. }
  267. if($mview->modulename){
  268. $output .= " <tr>".
  269. " <th>Module Name</th>".
  270. " <td>$mview->modulename</td>".
  271. " </tr>";
  272. }
  273. if($mview->mv_table){
  274. $output .= " <tr>".
  275. " <th>Table Name</th>".
  276. " <td>$mview->mv_table</td>".
  277. " </tr>";
  278. }
  279. if($mview->mv_specs){
  280. $output .= " <tr>".
  281. " <th>Table Field Definitions</th>".
  282. " <td>$mview->mv_specs</td>".
  283. " </tr>";
  284. }
  285. if($mview->query){
  286. $output .= " <tr>".
  287. " <th>Query</th>".
  288. " <td><pre>$mview->query</pre></td>".
  289. " </tr>";
  290. }
  291. if($mview->indexed){
  292. $output .= " <tr>".
  293. " <th>Indexed Fields</th>".
  294. " <td>$mview->indexed</td>".
  295. " </tr>";
  296. }
  297. if($mview->special_index){
  298. $output .= " <tr>".
  299. " <th>Special Indexed Fields</th>".
  300. " <td>$mview->speical_index</td>".
  301. " </tr>";
  302. }
  303. if($mview->last_update > 0){
  304. $update = format_date($mview->last_update);
  305. } else {
  306. $update = 'Not yet populated';
  307. }
  308. $output .= " <tr>".
  309. " <th>Last Update</th>".
  310. " <td>$update</td>".
  311. " </tr>";
  312. // build the URLs using the url function so we can handle installations where
  313. // clean URLs are or are not used
  314. $update_url = url("admin/tripal/mviews/action/update/$mview->mview_id");
  315. $delete_url = url("admin/tripal/mviews/action/delete/$mview->mview_id");
  316. $edit_url = url("admin/tripal/mviews/edit/$mview->mview_id");
  317. $output .= "<tr><th>Actions</th>".
  318. "<td> <a href='$update_url'>Populate</a>, ".
  319. " <a href='$edit_url'>Edit</a>, ".
  320. " <a href='$delete_url'>Delete</a></td></tr>";
  321. $output .= "</table>";
  322. return $output;
  323. }
  324. /**
  325. *
  326. *
  327. * @ingroup tripal_mviews_api
  328. */
  329. function tripal_mviews_report () {
  330. $header = array('','MView Name','Last Update','Status','Description','');
  331. $rows = array();
  332. $mviews = db_query("SELECT * FROM {tripal_mviews} ORDER BY name");
  333. while($mview = db_fetch_object($mviews)){
  334. if($mview->last_update > 0){
  335. $update = format_date($mview->last_update);
  336. } else {
  337. $update = 'Not yet populated';
  338. }
  339. $rows[] = array(
  340. l('View',"admin/tripal/mviews/report/$mview->mview_id") ." | ".
  341. l('Edit',"admin/tripal/mviews/edit/$mview->mview_id") ." | ".
  342. l('Populate',"admin/tripal/mviews/action/update/$mview->mview_id"),
  343. $mview->name,
  344. $update,
  345. $mview->status,
  346. $mview->comment,
  347. l('Delete',"admin/tripal/mviews/action/delete/$mview->mview_id"),
  348. );
  349. }
  350. $rows[] = array(
  351. 'data' => array(
  352. array('data' => l('Create a new materialized view.',"admin/tripal/mviews/new"),
  353. 'colspan' => 6),
  354. )
  355. );
  356. $page = theme('table', $header, $rows);
  357. return $page;
  358. }
  359. /**
  360. *
  361. *
  362. * @ingroup tripal_core
  363. */
  364. function tripal_mviews_form(&$form_state = NULL,$mview_id = NULL){
  365. if(!$mview_id){
  366. $action = 'Add';
  367. } else {
  368. $action = 'Edit';
  369. }
  370. // get this requested view
  371. if(strcmp($action,'Edit')==0){
  372. $sql = "SELECT * FROM {tripal_mviews} WHERE mview_id = $mview_id ";
  373. $mview = db_fetch_object(db_query($sql));
  374. # set the default values. If there is a value set in the
  375. # form_state then let's use that, otherwise, we'll pull
  376. # the values from the database
  377. $default_name = $form_state['values']['name'];
  378. $default_mv_table = $form_state['values']['mv_table'];
  379. $default_mv_specs = $form_state['values']['mv_specs'];
  380. $default_indexed = $form_state['values']['indexed'];
  381. $default_mvquery = $form_state['values']['mvquery'];
  382. $default_special_index = $form_state['values']['special_index'];
  383. $default_comment = $form_state['values']['cpmment'];
  384. if(!$default_name){
  385. $default_name = $mview->name;
  386. }
  387. if(!$default_mv_table){
  388. $default_mv_table = $mview->mv_table;
  389. }
  390. if(!$default_mv_specs){
  391. $default_mv_specs = $mview->mv_specs;
  392. }
  393. if(!$default_indexed){
  394. $default_indexed = $mview->indexed;
  395. }
  396. if(!$default_mvquery){
  397. $default_mvquery = $mview->query;
  398. }
  399. if(!$default_special_index){
  400. $default_special_index = $mview->special_index;
  401. }
  402. if(!$default_comment){
  403. $default_comment = $mview->comment;
  404. }
  405. }
  406. // Build the form
  407. $form['action'] = array(
  408. '#type' => 'value',
  409. '#value' => $action
  410. );
  411. $form['mview_id'] = array(
  412. '#type' => 'value',
  413. '#value' => $mview_id
  414. );
  415. $form['name']= array(
  416. '#type' => 'textfield',
  417. '#title' => t('View Name'),
  418. '#description' => t('Please enter the name for this materialized view.'),
  419. '#required' => TRUE,
  420. '#default_value' => $default_name,
  421. '#weight' => 1
  422. );
  423. $form['mv_table']= array(
  424. '#type' => 'textfield',
  425. '#title' => t('Table Name'),
  426. '#description' => t('Please enter the Postgres table name that this view will generate in the database. You can use the schema and table name for querying the view'),
  427. '#required' => TRUE,
  428. '#default_value' => $default_mv_table,
  429. '#weight' => 3
  430. );
  431. $form['mv_specs']= array(
  432. '#type' => 'textarea',
  433. '#title' => t('Table Definition'),
  434. '#description' => t('Please enter the field definitions for this view. Each field should be separated by a comma or enter each field definition on each line.'),
  435. '#required' => TRUE,
  436. '#default_value' => $default_mv_specs,
  437. '#weight' => 4
  438. );
  439. $form['indexed']= array(
  440. '#type' => 'textarea',
  441. '#title' => t('Indexed Fields'),
  442. '#description' => t('Please enter the field names (as provided in the table definition above) that will be indexed for this view. Separate by a comma or enter each field on a new line.'),
  443. '#required' => FALSE,
  444. '#default_value' => $default_indexed,
  445. '#weight' => 5
  446. );
  447. $form['mvquery']= array(
  448. '#type' => 'textarea',
  449. '#title' => t('Query'),
  450. '#description' => t('Please enter the SQL statement used to populate the table.'),
  451. '#required' => TRUE,
  452. '#default_value' => $default_mvquery,
  453. '#weight' => 6
  454. );
  455. $form['comment']= array(
  456. '#type' => 'textarea',
  457. '#title' => t('MView Description'),
  458. '#description' => t('Optional. Please provide a description of the purpose for this materialized vieww.'),
  459. '#required' => FALSE,
  460. '#default_value' => $default_comment,
  461. '#weight' => 6
  462. );
  463. /**
  464. $form['special_index']= array(
  465. '#type' => 'textarea',
  466. '#title' => t('View Name'),
  467. '#description' => t('Please enter the name for this materialized view.'),
  468. '#required' => TRUE,
  469. '#default_value' => $default_special_index,
  470. '#weight' => 7
  471. );
  472. */
  473. if($action == 'Edit'){
  474. $value = 'Save';
  475. }
  476. if($action == 'Add'){
  477. $value = 'Add';
  478. }
  479. $form['submit'] = array (
  480. '#type' => 'submit',
  481. '#value' => t($value),
  482. '#weight' => 8,
  483. '#executes_submit_callback' => TRUE,
  484. );
  485. $form['#redirect'] = 'admin/tripal/mviews';
  486. return $form;
  487. }
  488. /**
  489. *
  490. *
  491. * @ingroup tripal_core
  492. */
  493. function tripal_mviews_form_submit($form, &$form_state){
  494. $action = $form_state['values']['action'];
  495. $mview_id = $form_state['values']['mview_id'];
  496. $name = $form_state['values']['name'];
  497. $mv_table = $form_state['values']['mv_table'];
  498. $mv_specs = $form_state['values']['mv_specs'];
  499. $indexed = $form_state['values']['indexed'];
  500. $query = $form_state['values']['mvquery'];
  501. $special_index = $form_state['values']['special_index'];
  502. $comment = $form_state['values']['comment'];
  503. if(strcmp($action,'Edit')==0){
  504. tripal_edit_mview($mview_id,$name, 'tripal_core',$mv_table, $mv_specs,$indexed,$query,$special_index,$comment);
  505. }
  506. else if(strcmp($action,'Add')==0){
  507. tripal_add_mview ($name, 'tripal_core',$mv_table, $mv_specs,$indexed,$query,$special_index,$comment);
  508. }
  509. else {
  510. drupal_set_message("No action performed.");
  511. }
  512. return '';
  513. }