mviews.php 18 KB

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