PageRenderTime 55ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/db/library/dbscript/postgresql.php

https://github.com/tjgillies/openmicroblogger
PHP | 778 lines | 674 code | 56 blank | 48 comment | 162 complexity | 5ef61d71c12c6809f0c0dcd0c3535fcd MD5 | raw file
Possible License(s): LGPL-2.1
  1. <?php
  2. /**
  3. * dbscript -- restful openid framework
  4. * @version 0.6.0 -- 22-October-2008
  5. * @author Brian Hendrickson <brian@dbscript.net>
  6. * @link http://dbscript.net/
  7. * @copyright Copyright 2009 Brian Hendrickson
  8. * @license http://www.opensource.org/licenses/mit-license.php MIT License
  9. * @package dbscript
  10. */
  11. /**
  12. * PostgreSQL
  13. *
  14. * adapter for the PostgreSQL database system
  15. *
  16. * Usage:
  17. * <code>
  18. * $db = new PostgreSQL ( 'hostname', 'database_name', 'username', 'password' );
  19. * </code>
  20. *
  21. * More info...
  22. * {@link http://dbscript.net/postgresql}
  23. *
  24. * @package dbscript
  25. * @author Brian Hendrickson <brian@dbscript.net>
  26. * @access public
  27. * @version 0.6.0 -- 22-October-2008
  28. * @todo support array datatypes
  29. */
  30. class PostgreSQL extends Database {
  31. var $connstr;
  32. var $oid;
  33. var $host;
  34. var $user;
  35. var $pass;
  36. var $dbname;
  37. var $prefix;
  38. function PostgreSQL() {
  39. global $prefix;
  40. $prefix = '';
  41. $this->prefix = $prefix;
  42. $this->db_open = false;
  43. $this->models = array();
  44. $this->recordsets = array();
  45. $this->max_blob_length = 6144000; // default max blob file size is 6MB
  46. $this->max_string_length = 1024000; // default max string length is 1MB
  47. $this->datatype_map = array(
  48. 'real' => 'float',
  49. 'double precision' => 'float',
  50. 'int' => 'int',
  51. 'integer' => 'int',
  52. 'smallint' => 'int',
  53. 'bigint' => 'int',
  54. 'serial' => 'int',
  55. 'serial primary key' => 'int',
  56. 'bigserial' => 'int',
  57. 'numeric' => 'int',
  58. 'text' => 'text',
  59. 'char' => 'char',
  60. 'varchar' => 'char',
  61. 'character' => 'char',
  62. 'character varying' => 'char',
  63. 'timestamp' => 'time',
  64. 'timestamp without time zone' => 'time',
  65. 'timestamp with time zone' => 'time',
  66. 'time' => 'time',
  67. 'time without time zone' => 'time',
  68. 'time with time zone' => 'time',
  69. 'date' => 'date',
  70. 'boolean' => 'bool',
  71. 'oid' => 'blob'
  72. );
  73. $func_args = func_get_args();
  74. $argnames = array('host','dbname','user','password','port');
  75. $this->true_values = array('t','true','1',true);
  76. $this->alias_array = array();
  77. for ($i = 0; $i < count($argnames); $i++) {
  78. if (isset($func_args[$i]))
  79. $this->$argnames[$i] = $func_args[$i];
  80. else
  81. $this->$argnames[$i] = "";
  82. }
  83. for ($i = 0; $i < count($func_args); $i++) {
  84. if (strlen($func_args[$i]) > 0)
  85. $this->connstr .= $argnames[$i] . '=' . $func_args[$i] . ' ';
  86. }
  87. $this->connect();
  88. }
  89. function connect() { // establish a connection to the database
  90. trigger_before( 'connect', $this, $this );
  91. $this->conn = @pg_connect($this->connstr);
  92. if (!$this->conn) {
  93. $this->db_open = false;
  94. trigger_error("Sorry, the database connection failed. Please check your database connection settings.".@pg_last_error($this->conn), E_USER_ERROR );
  95. } else {
  96. $this->db_open = true;
  97. }
  98. return $this->db_open;
  99. }
  100. function escape_string($string) {
  101. trigger_before( 'escape_string', $this, $this );
  102. if (!(strlen($string) > 0)) { return ""; }
  103. $result = @pg_escape_string($string);
  104. if (!$result && !(is_numeric($string)))
  105. trigger_error("error in escape_string in postgresql.php".@pg_last_error($this->conn), E_USER_ERROR );
  106. return $result;
  107. }
  108. function get_result( $sql, $returnfalse = NULL ) { /* run an SQL query */
  109. trigger_before( 'get_result', $this, $this );
  110. global $request;
  111. if (isset($request->params)) {
  112. trigger_before( 'get_result', $request, $this );
  113. }
  114. $result = @pg_query( $this->conn, $sql );
  115. if (!$result && $returnfalse === NULL)
  116. trigger_error("error in get_result in postgresql.php".@pg_last_error($this->conn)." ".$sql, E_USER_ERROR );
  117. elseif (!$result && $returnfalse)
  118. return true;
  119. else
  120. return $result;
  121. }
  122. function next_primary_key( $table, $pkfield, $sequence_name=NULL ) {
  123. trigger_before( 'next_primary_key', $this, $this );
  124. global $prefix;
  125. if ($sequence_name == NULL) {
  126. $sql = "SELECT relname FROM pg_class WHERE relkind='S' and substr(relname,1,".strlen($prefix.$table).")='".$prefix."$table'";
  127. $result = $this->get_result($sql);
  128. if ($this->num_rows($result) > 0) {
  129. $seq = $this->result_value($result,0,"relname");
  130. } else {
  131. return '';
  132. }
  133. } else {
  134. $seq = $sequence_name;
  135. }
  136. $pk_result = $this->get_result("SELECT nextval('$seq')");
  137. if ($this->num_rows($result) > 0)
  138. $pkvalue = $this->result_value( $pk_result, 0, "nextval" );
  139. else
  140. trigger_error("error selecting nexval in next_primary_key in postgresql.php".@pg_last_error($this->conn), E_USER_ERROR );
  141. return $pkvalue;
  142. }
  143. function last_insert_id(&$result,$pkfield,$table) { // returns the id of the most recently modified record
  144. trigger_before( 'last_insert_id', $this, $this );
  145. global $prefix;
  146. $oid = @pg_last_oid($result);
  147. if (!$oid)
  148. trigger_error(@pg_last_error($this->conn), E_USER_ERROR );
  149. $sql = "SELECT ". $pkfield . " FROM " . $prefix.$table . " WHERE oid = " . $oid;
  150. $res = $this->get_result($sql);
  151. if (!$res)
  152. trigger_error("error in last_insert_id in postgresql.php".@pg_last_error($this->conn), E_USER_ERROR );
  153. else
  154. return $this->result_value($res,0,$pkfield);
  155. }
  156. function result_value(&$result,$resultindex,$field) { // get a single value from a result set
  157. trigger_before( 'result_value', $this, $this );
  158. $return = pg_fetch_result($result,$resultindex,$field);
  159. if (!$return && $return != 0)
  160. trigger_error("error in result_value in postgresql.php".@pg_last_error($this->conn), E_USER_ERROR );
  161. else
  162. return $return;
  163. }
  164. function close() {
  165. trigger_before( 'close', $this, $this );
  166. $args = func_get_args();
  167. pg_close( $this->conn );
  168. if ( isset( $args[0] ) ) {
  169. if ( strlen($args[0]) > 0 ) {
  170. header( "Location:" . $args[0] );
  171. exit;
  172. }
  173. }
  174. }
  175. function &get_table($table) {
  176. trigger_before( 'get_table', $this, $this );
  177. if ( isset( $this->models[$table] ) )
  178. if ($this->models[$table]->exists)
  179. return $this->models[$table];
  180. $custom_class = classify($table);
  181. if (!isset($this->models[$table]) && class_exists($custom_class)) {
  182. $this->models[$table] = new $custom_class();
  183. } elseif (!isset($this->models[$table])) {
  184. $this->models[$table] = new Model($table, $this);
  185. }
  186. if (!($this->models[$table]->exists))
  187. $this->models[$table]->register($table);
  188. return $this->models[$table];
  189. }
  190. function &model($model) {
  191. trigger_before( 'model', $this, $this );
  192. return $this->get_table(tableize($model));
  193. }
  194. function fetch_array( &$result, $row=NULL ) {
  195. trigger_before( 'fetch_array', $this, $this );
  196. if (is_numeric($row))
  197. $this->seek_row( $result, $row );
  198. return pg_fetch_array( $result, $row, PGSQL_ASSOC );
  199. }
  200. function fetch_row( &$result, $row=NULL ) {
  201. trigger_before( 'fetch_row', $this, $this );
  202. if ( ( is_numeric( $row ) ) )
  203. return pg_fetch_row( $result, $row );
  204. return pg_fetch_row( $result );
  205. }
  206. function seek_row(&$result,$row) {
  207. trigger_before( 'seek_row', $this, $this );
  208. return true;
  209. }
  210. function query_limit($limit,$offset) {
  211. trigger_before( 'query_limit', $this, $this );
  212. return " LIMIT " . $limit . " OFFSET " . $offset;
  213. }
  214. function blob_value( &$rec, $field, &$value ) {
  215. trigger_before( 'blob_value', $this, $this );
  216. return $value;
  217. }
  218. function sql_insert_for( &$rec ) {
  219. trigger_before( 'sql_insert_for', $this, $this );
  220. $sql = "INSERT INTO " . $this->prefix.$rec->table . " (";
  221. $comma = '';
  222. $fields = '';
  223. $values = '';
  224. foreach (array_unique($rec->modified_fields) as $modified_field) {
  225. $datatype = $this->get_mapped_datatype($this->models[$rec->table]->field_array[$modified_field]);
  226. $this->pre_insert( $rec, $modified_field, $datatype );
  227. if ( !( $datatype == 'blob' && ( !(strlen( $rec->attributes[$modified_field] ) > 0 ) ) ) ) {
  228. $fields .= $comma . $modified_field;
  229. $values .= $comma . $this->quoted_insert_value( $rec, $modified_field );;
  230. $comma = ',';
  231. }
  232. }
  233. $sql .= $fields . ") VALUES (" . $values . ")";
  234. return $sql;
  235. }
  236. function sql_update_for( &$rec ) {
  237. trigger_before( 'sql_update_for', $this, $this );
  238. $sql = "UPDATE ";
  239. $sql .= $this->prefix.$rec->table . ' SET ';
  240. $comma = '';
  241. foreach (array_unique($rec->modified_fields) as $modified_field) {
  242. $datatype = $this->get_mapped_datatype($this->models[$rec->table]->field_array[$modified_field]);
  243. $this->pre_update( $rec, $modified_field, $datatype );
  244. if ( !( $datatype == 'blob' && ( !(strlen( $rec->attributes[$modified_field] ) > 0 ) ) ) ) {
  245. $sql .= $comma . $this->quoted_update_value( $rec, $modified_field );
  246. $comma = ',';
  247. }
  248. }
  249. $sql .= " WHERE " . $rec->primary_key . "='" . $rec->attributes[$rec->primary_key] . "'";
  250. return $sql;
  251. }
  252. function sql_select_for( &$rec, $id ) {
  253. trigger_before( 'sql_select_for', $this, $this );
  254. return "SELECT ".$rec->selecttext." FROM ".$this->prefix.$rec->table." WHERE ".$rec->primary_key." = '".$id."'";
  255. }
  256. function sql_delete_for( &$rec ) {
  257. trigger_before( 'sql_delete_for', $this, $this );
  258. $pkfield = $rec->primary_key;
  259. foreach ($rec->attributes as $key=>$value) {
  260. $datatype = $this->get_mapped_datatype($this->models[$rec->table]->field_array[$key]);
  261. if ($datatype == 'blob' && strlen($rec->attributes[$rec->primary_key]) > 0) {
  262. $oid_result = $this->get_result("select ".$key." from ".$this->prefix.$rec->table." where ".$rec->primary_key." = '".$rec->attributes[$rec->primary_key]."'");
  263. $prev_oid = $this->fetch_array($oid_result,0,$key);
  264. if (isset($prev_oid[0]) && $prev_oid[0] > 0)
  265. $result = $this->large_object_delete($prev_oid[0]);
  266. }
  267. }
  268. $sql = 'DELETE FROM ' . $this->prefix.$rec->table . ' WHERE ' . $pkfield . ' = ' . $rec->$pkfield;
  269. return $sql;
  270. }
  271. function select_distinct( $field, $table, $orderby ) {
  272. trigger_before( 'select_distinct', $this, $this );
  273. return "SELECT DISTINCT $field, " . $this->models[$table]->primary_key . " FROM $this->prefix.$table ORDER BY $orderby DESC";
  274. }
  275. function quoted_update_value( &$rec, $modified_field ) {
  276. trigger_before( 'quoted_update_value', $this, $this );
  277. return $modified_field . "='" . $this->escape_string($rec->attributes[$modified_field]) . "'";
  278. }
  279. function quoted_insert_value( &$rec, $modified_field ) {
  280. trigger_before( 'quoted_insert_value', $this, $this );
  281. return "'" . $this->escape_string($rec->attributes[$modified_field]) . "'";
  282. }
  283. function pre_insert( &$rec, $modified_field, $datatype ) {
  284. trigger_before( 'pre_insert', $rec, $this );
  285. if (isset($this->models[$rec->table]->field_attrs[$modified_field]['required'])) {
  286. if (!(strlen( $rec->attributes[$modified_field] ) > 0))
  287. trigger_error( "$modified_field is a required field", E_USER_ERROR );
  288. }
  289. if (isset($this->models[$rec->table]->field_attrs[$modified_field]['unique'])) {
  290. $result = $this->get_result("select ".$modified_field." from ".$this->prefix.$rec->table." where ".$modified_field." = '".$rec->attributes[$modified_field]."'");
  291. if ($result && $this->num_rows($result) > 0)
  292. trigger_error( "Sorry, that $modified_field has already been taken.", E_USER_ERROR );
  293. }
  294. if ($datatype == 'time' && !(strlen($rec->attributes[$modified_field]) > 0))
  295. $rec->attributes[$modified_field] = date("Y-m-d H:i:s",strtotime("now"));
  296. if ($datatype == 'blob' && strlen($rec->attributes[$modified_field]) > 0) {
  297. if (environment('max_upload_mb')) {
  298. $max = 1048576*environment('max_upload_mb');
  299. $size = filesize($rec->attributes[$modified_field]);
  300. if ($size >$max)
  301. trigger_error('Sorry but that file is too big, the limit is '.environment('max_upload_mb').' megabytes', E_USER_ERROR);
  302. }
  303. $coll = environment('collection_cache');
  304. if (isset($coll[$request->resource]) && $coll[$request->resource]['location'] == 'aws') {
  305. $this->file_upload = array($modified_field,$rec->attributes[$modified_field]);
  306. $rec->set_value($modified_field,'');
  307. } elseif (isset($coll[$request->resource]) && $coll[$request->resource]['location'] == 'uploads') {
  308. $this->file_upload = $rec->attributes[$modified_field];
  309. $rec->set_value($modified_field,'');
  310. } else {
  311. $oid = $this->large_object_create($this->prefix.$rec->table,$rec->attributes[$modified_field]);
  312. if ($oid > 0)
  313. $rec->attributes[$modified_field] = $oid;
  314. }
  315. }
  316. if ($datatype == 'bool') {
  317. if ( in_array( $rec->attributes[$modified_field], $this->true_values, true ) )
  318. $rec->attributes[$modified_field] = "true";
  319. else
  320. $rec->attributes[$modified_field] = "false";
  321. }
  322. if ($modified_field == $rec->primary_key) {
  323. if ( in_array( $rec->attributes[$rec->primary_key], array( '', 0, '0' ), true ))
  324. $rec->attributes[$modified_field] = $this->next_primary_key( $this->prefix.$rec->table, $modified_field);
  325. }
  326. }
  327. function pre_update( &$rec, $modified_field, $datatype ) {
  328. trigger_before( 'pre_update', $rec, $this );
  329. if (isset($this->models[$rec->table]->field_attrs[$modified_field]['required'])) {
  330. if (!(strlen( $rec->attributes[$modified_field] ) > 0))
  331. trigger_error( "Sorry, you must provide a value for $modified_field", E_USER_ERROR );
  332. }
  333. if (isset($this->models[$rec->table]->field_attrs[$modified_field]['unique'])) {
  334. $result = $this->get_result("select ".$modified_field." from ".$this->prefix.$rec->table." where ".$modified_field." = '".$rec->attributes[$modified_field]."' and ".$rec->primary_key." != '".$rec->attributes[$rec->primary_key]."'");
  335. if ($this->num_rows($result) > 0)
  336. trigger_error( "Sorry, that $modified_field has already been taken.", E_USER_ERROR );
  337. }
  338. if ($datatype == 'blob' && (strlen( $rec->attributes[$modified_field] ) > 0 )) {
  339. if (environment('max_upload_mb')) {
  340. $max = 1048576*environment('max_upload_mb');
  341. $size = filesize($rec->attributes[$modified_field]);
  342. if ($size >$max)
  343. trigger_error('Sorry but that file is too big, the limit is '.environment('max_upload_mb').' megabytes', E_USER_ERROR);
  344. }
  345. global $request;
  346. $coll = environment('collection_cache');
  347. if (isset($coll[$request->resource]) && $coll[$request->resource]['location'] == 'aws') {
  348. $this->file_upload = array($modified_field,$rec->attributes[$modified_field]);
  349. $this->aws_delfile($rec,$rec->id);
  350. $this->aws_putfile($rec,$rec->id);
  351. $rec->set_value($modified_field,'');
  352. } elseif (isset($coll[$request->resource]) && $coll[$request->resource]['location'] == 'uploads') {
  353. update_uploadsfile($this->prefix.$rec->table,$rec->id,$rec->attributes[$modified_field]);
  354. $rec->set_value($modified_field,'');
  355. } else {
  356. unlink_cachefile($this->prefix.$rec->table,$rec->id,$coll);
  357. $oid_result = $this->get_result("select ".$modified_field." from ".$this->prefix.$rec->table." where ".$rec->primary_key." = '".$rec->attributes[$rec->primary_key]."'");
  358. if ($this->num_rows($oid_result) > 0) {
  359. $prev_oid = $this->fetch_array($oid_result);
  360. if (isset($prev_oid[0]) && $prev_oid[0] > 0)
  361. $result = $this->large_object_delete($prev_oid);
  362. }
  363. $oid = $this->large_object_create($this->prefix.$rec->table,$rec->attributes[$modified_field]);
  364. if ($oid > 0)
  365. $rec->attributes[$modified_field] = $oid;
  366. }
  367. }
  368. }
  369. function post_insert( &$rec, &$result ) {
  370. trigger_before( 'post_insert', $this, $this );
  371. if (is_array($this->file_upload))
  372. $this->aws_putfile($rec,$rec->id);
  373. elseif (!empty($this->file_upload))
  374. update_uploadsfile($this->prefix.$rec->table,$rec->id,$this->file_upload);
  375. if (!$result) { trigger_error("Sorry, the record could not be saved due to a database error.", E_USER_ERROR ); }
  376. }
  377. function affected_rows(&$result) {
  378. trigger_before( 'affected_rows', $this, $this );
  379. return @pg_affected_rows($result);
  380. }
  381. function fetch_object(&$result) {
  382. trigger_before( 'fetch_object', $this, $this );
  383. return @pg_fetch_object($result);
  384. }
  385. function fetch_field(&$result,$i) {
  386. trigger_before( 'fetch_field', $this, $this );
  387. $field = new dbfield();
  388. $field->name = pg_field_name($result,$i);
  389. $field->type = pg_field_type($result,$i);
  390. $field->size = pg_field_size($result,$i);
  391. return $field;
  392. }
  393. function num_rows(&$result) {
  394. trigger_before( 'num_rows', $this, $this );
  395. return @pg_num_rows($result);
  396. }
  397. function num_fields(&$result) {
  398. trigger_before( 'num_fields', $this, $this );
  399. return @pg_num_fields($result);
  400. }
  401. function field_name(&$result, $index) {
  402. trigger_before( 'field_name', $this, $this );
  403. return @pg_field_name($result, $index);
  404. }
  405. function large_object_create($table,$file) {
  406. trigger_before( 'large_object_create', $this, $this );
  407. $return = false;
  408. if (!(file_exists($file)))
  409. return $return;
  410. $filename = basename($file);
  411. if (!$filename) { trigger_error("Error determining base name of large object file $filename", E_USER_ERROR ); }
  412. $handle = fopen($file,"r");
  413. if (!$handle) { trigger_error("Error opening large object file $file", E_USER_ERROR ); }
  414. $buffer = fread($handle,filesize($file));
  415. if (!$buffer) { trigger_error("Error reading large object file $file", E_USER_ERROR ); }
  416. $result = fclose($handle);
  417. $result = @pg_query($this->conn, "BEGIN");
  418. if (!$result) { trigger_error("error starting l_o_c transaction: ".@pg_last_error($this->conn), E_USER_ERROR ); }
  419. $oid = @pg_lo_create($this->conn);
  420. if (!$oid) { trigger_error("error in pg_l_o_c: ".@pg_last_error($this->conn), E_USER_ERROR ); }
  421. #$result = pg_query($this->conn,"UPDATE $table SET $field = $oid WHERE $pkfield = '$pkvalue'");
  422. #if (!$result) { trigger_error("Error updating file OID", E_USER_ERROR ); }
  423. $handle = @pg_lo_open($this->conn, $oid, "w");
  424. if (!$handle) { trigger_error("error in pg_l_o_o: ".@pg_last_error($this->conn), E_USER_ERROR ); }
  425. $result = @pg_lo_write($handle, $buffer);
  426. if (!$result) { trigger_error("error in l_o_w: ".@pg_last_error($this->conn), E_USER_ERROR ); }
  427. $result = @pg_lo_close($handle);
  428. if (!$result) { trigger_error("error in l_o_close: ".@pg_last_error($this->conn), E_USER_ERROR ); }
  429. $result = @pg_query($this->conn, "COMMIT");
  430. if (!$result) { trigger_error("error committing l_o_c transaction: ".@pg_last_error($this->conn), E_USER_ERROR ); }
  431. else {
  432. $return = $oid;
  433. }
  434. return $return;
  435. }
  436. function large_object_fetch($oid, $return = false) {
  437. trigger_before( 'large_object_fetch', $this, $this );
  438. //$result = pg_query($this->conn,"SELECT $field FROM $table WHERE $");
  439. //if (!$result) { trigger_error("Error in select file OID", E_USER_ERROR ); }
  440. //$oid = pg_result($result,0,$fieldname);
  441. //if (!$oid) { trigger_error("Error in file OID result", E_USER_ERROR ); }
  442. $result = @pg_query($this->conn,"BEGIN");
  443. if (!$result) { trigger_error("error starting l_o_f transaction: ".@pg_last_error($this->conn), E_USER_ERROR ); }
  444. $handle = @pg_lo_open($this->conn, $oid, "r");
  445. if (!$handle) { trigger_error("error in l_o_f/l_o_o: ".@pg_last_error($this->conn), E_USER_ERROR ); }
  446. if ($return === true)
  447. return @pg_lo_read($handle,$this->max_blob_length);
  448. else
  449. @pg_lo_read_all($handle);
  450. if (!$buffer) { trigger_error("error in l_o_read_all: ".@pg_last_error($this->conn), E_USER_ERROR ); }
  451. $result = @pg_lo_close($handle);
  452. if (!$result) { trigger_error("error in l_o_close: ".@pg_last_error($this->conn), E_USER_ERROR ); }
  453. $result = @pg_query($this->conn,"COMMIT");
  454. if (!$result) { trigger_error("error committing l_o_f transaction: ".@pg_last_error($this->conn), E_USER_ERROR ); }
  455. return $return;
  456. }
  457. function large_object_delete($oid) {
  458. trigger_before( 'large_object_delete', $this, $this );
  459. $return = false;
  460. #$result = pg_query($this->conn,"SELECT $field FROM $table WHERE $pkfield = '$pkvalue'");
  461. #if (!$result) { trigger_error("Error in select file OID", E_USER_ERROR ); }
  462. #$oid = pg_result($result,0,$field);
  463. #if (!$oid) { trigger_error("Error in file OID result", E_USER_ERROR ); }
  464. $result = @pg_query($this->conn,"BEGIN");
  465. if (!$result) { trigger_error("error starting l_o_d transaction: ".@pg_last_error($this->conn), E_USER_ERROR ); }
  466. $result = @pg_lo_unlink($this->conn, $oid);
  467. if (!$result) { trigger_error("error in l_o_unlink: ".@pg_last_error($this->conn), E_USER_ERROR ); }
  468. $result = @pg_query($this->conn,"COMMIT");
  469. if (!$result) { trigger_error("error committing l_o_d transaction: ".@pg_last_error($this->conn), E_USER_ERROR ); }
  470. #$result = pg_query($this->conn,"DELETE FROM $table WHERE lo_oid = $oid");
  471. #if (!$result) { trigger_error("Error deleting file OID", E_USER_ERROR ); }
  472. else {
  473. $return = true;
  474. }
  475. return $return;
  476. }
  477. function add_table( $table, $field_array ) {
  478. trigger_before( 'add_table', $this, $this );
  479. $exists = $this->get_tables();
  480. if (in_array($this->prefix.$table,$exists))
  481. return true;
  482. if (!(count($field_array)>0)) trigger_error( "Error creating table. No fields are defined. Use \$model->auto_field and \$model->text_field etc.", E_USER_ERROR );
  483. $sql = "CREATE TABLE ". $this->prefix ."$table (";
  484. $comma = "";
  485. foreach ( $field_array as $field => $data_type ) {
  486. $sql .= "$comma $field $data_type";
  487. $comma = ",";
  488. }
  489. $sql .= ")";
  490. $result = $this->get_result($sql);
  491. if ($result)
  492. $this->tables[] = $table;
  493. }
  494. function add_field( $table, $field, $data_type ) {
  495. trigger_before( 'add_field', $this, $this );
  496. $sql = "ALTER TABLE " . $this->prefix ."$table ADD COLUMN $field $data_type";
  497. echo $sql."<br />";
  498. $result = $this->get_result($sql);
  499. }
  500. function has_table($t) {
  501. trigger_before( 'has_table', $this, $this );
  502. return in_array( $this->prefix.$t, $this->get_tables(), true );
  503. }
  504. function get_tables() {
  505. trigger_before( 'get_tables', $this, $this );
  506. $tables = array();
  507. #$sql = "SELECT a.relname AS Name FROM pg_class a, pg_user b ";
  508. #$sql .= "WHERE ( relkind = 'r') and relname !~ '^pg_' AND relname !~ '^sql_' ";
  509. #$sql .= "AND relname !~ '^xin[vx][0-9]+' AND b.usesysid = a.relowner ";
  510. #$sql .= "AND NOT (EXISTS (SELECT viewname FROM pg_views WHERE viewname=a.relname))";
  511. $sql = "SELECT tablename AS relname FROM pg_catalog.pg_tables";
  512. $sql .= " WHERE schemaname NOT IN ('pg_catalog', 'information_schema',";
  513. $sql .= " 'pg_toast') ORDER BY tablename";
  514. $result = $this->get_result($sql);
  515. while ($arr = $this->fetch_array($result)) {
  516. foreach($arr as $key=>$value) {
  517. if (!(in_array($value, array('db_sessions'))))
  518. $tables[] = $value;
  519. }
  520. }
  521. return $tables;
  522. }
  523. function get_fields($table) {
  524. trigger_before( 'get_fields', $this, $this );
  525. $datatypes = array();
  526. $fieldindex = array();
  527. $fieldindex[] = "";
  528. #$sql = "SELECT column_name, data_type FROM information_schema.columns ";
  529. #$sql .= "WHERE table_schema = 'public' AND table = '$table'";
  530. $sql = "SELECT a.attname, pg_catalog.format_type(a.atttypid, a.atttypmod)";
  531. $sql .= " as type FROM pg_catalog.pg_attribute a LEFT JOIN";
  532. $sql .= " pg_catalog.pg_attrdef adef ON a.attrelid=adef.adrelid AND";
  533. $sql .= " a.attnum=adef.adnum LEFT JOIN pg_catalog.pg_type t ON";
  534. $sql .= " a.atttypid=t.oid WHERE a.attrelid = (SELECT oid FROM";
  535. $sql .= " pg_catalog.pg_class WHERE relname='".$this->prefix."$table')";
  536. $sql .= " and a.attname != 'tableoid' and a.attname != 'oid'";
  537. $sql .= " and a.attname != 'xmax' and a.attname != 'xmin'";
  538. $sql .= " and a.attname != 'cmax' and a.attname != 'cmin'";
  539. $sql .= " and a.attname != 'ctid' and a.attname != 'otre'";
  540. $sql .= " and a.attname not ilike '%..%' order by a.attnum ASC";
  541. $result = $this->get_result($sql,true);
  542. if (!$result) return $datatypes;
  543. while ($arr = $this->fetch_array($result)) {
  544. foreach($arr as $key=>$value) {
  545. if ($key == "attname") {
  546. $field = $value;
  547. $fieldindex[] = $value;
  548. } elseif ($key == "type") {
  549. $type = $value;
  550. }
  551. }
  552. $datatypes[$field] = $type;
  553. }
  554. global $prefix;
  555. $sql = "SELECT idx.indkey, idx.indisunique, idx.indisprimary";
  556. $sql .= " FROM pg_catalog.pg_class c, pg_catalog.pg_class c2,";
  557. $sql .= " pg_catalog.pg_index idx";
  558. $sql .= " WHERE c.oid = idx.indrelid";
  559. $sql .= " AND idx.indexrelid = c2.oid";
  560. $sql .= " AND c.relname = '".$prefix."$table'";
  561. #$sql .= " AND idx.isprimary = true";
  562. $result = $this->get_result($sql);
  563. while ($row = pg_fetch_row($result)) {
  564. if (!(strstr($row[0], ' ')))
  565. $datatypes[$table."_primary_key"] = $fieldindex[$row[0]];
  566. }
  567. return $datatypes;
  568. }
  569. function create_openid_tables() {
  570. if (in_array('openid_identities',$this->tables))
  571. return;
  572. $result = $this->get_result("CREATE TABLE openid_identities ( uurl_id int NOT NULL, user_id int NOT NULL default '0', url text, hash char(32) )");
  573. $result = $this->get_result("CREATE TABLE oauth_consumers (consumer_key CHAR(255) PRIMARY KEY, secret CHAR(40), description CHAR(40))");
  574. $result = $this->get_result("CREATE TABLE oauth_tokens (consumer_key CHAR(255), token CHAR(40), secret CHAR(40), token_type CHAR(7), nonce CHAR(40), user_id INT DEFAULT 0, expires INT DEFAULT 0)");
  575. $result = $this->get_result("INSERT INTO oauth_consumers (consumer_key, secret, description) VALUES ('DUMMYKEY', '', 'Unidentified Consumer')");
  576. //;
  577. $result = $this->get_result("CREATE TABLE openid_nonces (server_url VARCHAR(255), timestamp INTEGER, ".
  578. "salt CHAR(40), UNIQUE (server_url, timestamp, salt))");
  579. $result = $this->get_result("CREATE TABLE openid_associations (server_url VARCHAR(255), handle VARCHAR(255), ".
  580. "secret BYTEA, issued INTEGER, lifetime INTEGER, ".
  581. "assoc_type VARCHAR(64), PRIMARY KEY (server_url, handle), ".
  582. "CONSTRAINT secret_length_constraint CHECK ".
  583. "(LENGTH(secret) <= 128))");
  584. }
  585. function auto_field( $field, &$model ) {
  586. $model->set_field( $field, "serial primary key" );
  587. $model->set_primary_key( $field );
  588. }
  589. function enum_field( $field, $values, &$model ) {
  590. $model->set_field( $field, $values );
  591. }
  592. function float_field( $field, &$model ) {
  593. $model->set_field( $field, "double precision" );
  594. }
  595. function bool_field( $field, &$model ) {
  596. $model->set_field( $field, "boolean" );
  597. }
  598. function char_field( $field, &$model, $options ) {
  599. if (!(isset($options['len'])))
  600. $options = array('len'=>255);
  601. $model->set_field( $field, "varchar(".$options['len'].")" );
  602. }
  603. function date_field( $field, &$model ) {
  604. $model->set_field( $field, "date" );
  605. }
  606. function file_field( $field, &$model ) {
  607. $model->set_field( $field, "oid" );
  608. }
  609. function int_field( $field, &$model ) {
  610. $model->set_field( $field, "int" );
  611. }
  612. function text_field( $field, &$model ) {
  613. $model->set_field( $field, "text" );
  614. }
  615. function time_field( $field, &$model ) {
  616. $model->set_field( $field, "timestamp with time zone" );
  617. }
  618. function get_query( $id=NULL, $find_by=NULL, &$model ) {
  619. if (isset($model->query)) {
  620. $q = $model->query;
  621. unset($model->query);
  622. return $q;
  623. }
  624. $model->set_param('id',$id);
  625. $model->set_param('find_by',$find_by);
  626. trigger_before( 'get_query', $model, $this );
  627. $pkfield = $model->primary_key;
  628. if ($model->find_by == NULL)
  629. $model->set_param('find_by', $model->primary_key);
  630. $relfields = array();
  631. $relfields = $model->relations;
  632. $table = $this->prefix.$model->table;
  633. $fieldstring = '';
  634. $sql = "SELECT " . "\n";
  635. if (!array_key_exists($pkfield,$model->field_array))
  636. $sql .= "$table.$pkfield as \"$table.$pkfield\", " . "\n";
  637. foreach ($model->field_array as $fieldname=>$datatypename) {
  638. if (strpos($fieldname,".") === false)
  639. $fieldname = $table . "." . $fieldname;
  640. $fieldstring .= "$fieldname as \"$fieldname\", " . "\n";
  641. }
  642. $leftsql = "";
  643. $first = true;
  644. if (count($relfields) > 0) {
  645. foreach ($relfields as $key=>$val) {
  646. $spl = split("\.",$val["fkey"]);
  647. if (!($this->models[$spl[0]]->exists))
  648. $$spl[0] =& $this->get_table($spl[0]);
  649. $leftsql .= "(";
  650. }
  651. foreach ($relfields as $key=>$val) {
  652. $spl = split("\.",$val["fkey"]);
  653. if (($val["type"] == 'child-many')) {
  654. $join =& $this->get_table($model->join_table_for($table, $val['tab']));
  655. $spl[0] = $this->prefix.$join->table;
  656. $val["fkey"] = $this->prefix.$join->table.'.'.strtolower(classify($table))."_".$model->foreign_key_for( $table);
  657. }else{
  658. foreach ($this->models[$spl[0]]->field_array as $fieldname=>$datatypename) {
  659. $fieldstring .= $this->prefix.$spl[0].".".$fieldname." as \"".$this->prefix.$spl[0].".".$fieldname."\", " . "\n";
  660. }
  661. }
  662. if ($first)
  663. $leftsql .= $table;
  664. $leftsql .= " left join " . $this->prefix.$spl[0] . " on ".$table.".".$val["col"]." = " . $val["fkey"];
  665. $leftsql .= ")";
  666. $first = false;
  667. }
  668. }
  669. $fieldstring = substr($fieldstring,0,-3) . " " . "\n";
  670. $sql .= $fieldstring;
  671. $sql .= "FROM ";
  672. $sql .= $leftsql;
  673. if (!(strlen($leftsql) > 1))
  674. $sql .= $table;
  675. if (is_array($model->find_by)) {
  676. $findfirst = true;
  677. $op = "AND";
  678. $eq = '=';
  679. foreach( $model->find_by as $col=>$val ) {
  680. if (is_array($val))
  681. list($col,$val) = each($val);
  682. if ($col == 'op') {
  683. $op = $val;
  684. } elseif ($col =='eq') {
  685. $eq = $val;
  686. } else {
  687. if (strpos($col,".") === false)
  688. $field = "$table.$col";
  689. else
  690. $field = $this->prefix.$col;
  691. if ($findfirst) {
  692. $sql .= " WHERE $field $eq '$val' ";
  693. } else {
  694. $sql .= " $op $field $eq '$val' ";
  695. }
  696. $findfirst = false;
  697. }
  698. }
  699. } elseif ($model->id != NULL) {
  700. if (strpos($model->find_by,".") === false)
  701. $field = $table.".".$model->find_by;
  702. else
  703. $field = $model->find_by;
  704. $sql .= " WHERE $field = '".$model->id."' ";
  705. }
  706. if (!(isset($model->orderby)))
  707. $model->orderby = $table . "." . $pkfield;
  708. if (!(isset($model->order)))
  709. $model->order = "DESC";
  710. if (!(isset($model->offset)))
  711. $model->offset = 0;
  712. if (!(isset($model->limit)))
  713. $model->limit = 20;
  714. if (isset($model->groupby))
  715. $sql .= " GROUP BY " . $model->groupby . " ";
  716. $sql .= " ORDER BY " . $model->orderby . " ";
  717. $sql .= $model->order . $this->query_limit($model->limit,$model->offset);
  718. trigger_after( 'get_query', $model, $this );
  719. return $sql;
  720. }
  721. }
  722. ?>