mviews.php 16 KB

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