Odyssey
db.postgres.i
1 <?php
2 /**
3  * Plugin script for Postgres functions
4  *
5  * This file will contain the homecu database functions in relation to a postgres connection
6  *
7  */
8 
9 /**
10  * DEFINE CONSTANTS FOR DATATYPES
11  * serial
12  * integer
13  * smallint
14  * bigint
15  * numeric
16  * boolean
17  * char
18  * varchar
19  * date
20  * timestamptz
21  * timestamp
22  */
23  define("DBTYPE_INTEGER", "integer");
24  define("DBTYPE_SERIAL", "serial");
25  define("DBTYPE_SMALLINT", "smallint");
26  define("DBTYPE_BIGINT", "bigint");
27  define("DBTYPE_NUMERIC", "numeric");
28  define("DBTYPE_BOOLEAN", "boolean");
29  define("DBTYPE_CHAR", "char");
30  define("DBTYPE_VARCHAR", "varchar");
31  define("DBTYPE_DATE", "date");
32  define("DBTYPE_TIMESTAMPTZ", "timestamptz");
33  define("DBTYPE_TIMESTAMP", "timestamp");
34  // ** this can be used to pass custom expressions as values (eg. function
35  // calls, short expressions to evaluate column values on the fly, etc.)
36  define("DBTYPE_CUSTOM_EXPRESSION", "expression");
37  // ** These functions return the start time of the current transaction.
38  define("DBTIMESTAMP_USENOW", "now");
39  // ** Returns the actual current time, and therefore its value changes
40  define("DBTIMESTAMP_USETS", "current_timestamp");
41  define("DBNULL", "null");
42 
43  define ("HOMECU_WORK_BEGIN", "BEGIN");
44  define ("HOMECU_WORK_COMMIT", "COMMIT");
45  define ("HOMECU_WORK_ROLLBACK", "ROLLBACK");
46 
47 //
48 
49 function db_connect($pDbEnvSettings) {
50 
51  $connString = "user=" . HCU_array_key_value('user', $pDbEnvSettings) .
52  " password=" . HCU_array_key_value('password', $pDbEnvSettings) .
53  " port=" . HCU_array_key_value('port', $pDbEnvSettings) .
54  " dbname=" . HCU_array_key_value('dbname', $pDbEnvSettings) .
55  " host=" . HCU_array_key_value('host', $pDbEnvSettings) ;
56 
57  // See if it works if localhost is specified, if not use this
58  //(HCU_array_key_value('user', $pDbEnvSettings) !== 'localhost' ? " host=" . HCU_array_key_value('host', $pDbEnvSettings) : "");
59 
60  $retConn = @pg_connect($connString);
61 
62  return $retConn;
63 
64 }
65 
66 /**
67  *
68  *
69  * @param array $pDbEnvSettings This should be the working environment
70  * array as returned from the function LoadSystemEnv
71  * [
72  * 'host' => GetEnvSetting('DATABASE_HOST', 'localhost'),
73  * 'port' => GetEnvSetting('DATABASE_PORT', 5342),
74  * 'dbname' => GetEnvSetting('DATABASE_NAME', 'homecu_prod1'),
75  * 'user' => GetEnvSetting('DATABASE_USER', 'postgres'),
76  * 'password' => GetEnvSetting('DATABASE_PASSWORD'),
77  * 'connect_timeout' => GetEnvSetting('DATABASE_CONNECT_TIMEOUT'),
78  * 'platform' => GetEnvSetting('DATABASE_PLATFORM')
79  * ],
80  *
81  * @return mixed Database connection reference or false
82  *
83  */
84 function db_pconnect($pDbEnvSettings) {
85 
86  $connString = "user=" . HCU_array_key_value('user', $pDbEnvSettings) .
87  " password=" . HCU_array_key_value('password', $pDbEnvSettings) .
88  " port=" . HCU_array_key_value('port', $pDbEnvSettings) .
89  " dbname=" . HCU_array_key_value('dbname', $pDbEnvSettings) .
90  " host=" . HCU_array_key_value('host', $pDbEnvSettings) ;
91 
92  // See if it works if localhost is specified, if not use this
93  //(HCU_array_key_value('user', $pDbEnvSettings) !== 'localhost' ? " host=" . HCU_array_key_value('host', $pDbEnvSettings) : "");
94  $retConn = @pg_pconnect($connString);
95 
96  return $retConn;
97 }
98 
99 function db_query($qstring,$qhandle) {
100  if ($qhandle) {
101  return @pg_query ($qhandle, $qstring);
102  } else {
103  return 0;
104  }
105 }
106 
107 function db_num_rows($qhandle) {
108  if ($qhandle) {
109  return @pg_num_rows($qhandle);
110  } else {
111  return 0;
112  }
113 }
114 
115 function db_result($qhandle,$row,$field) {
116  if ($qhandle) {
117  return @pg_result($qhandle,$row,$field);
118  } else {
119  return 0;
120  }
121 }
122 
123 function db_num_fields($qhandle) {
124  if ($qhandle) {
125  return @pg_numfields($qhandle);
126  } else {
127  return 0;
128  }
129 }
130 
131 function db_fieldname($qhandle,$fnumber) {
132  if ($qhandle) {
133  return @pg_fieldname($qhandle,$fnumber);
134  } else {
135  return 0;
136  }
137 }
138 
139 function db_affected_rows($qhandle) {
140 
141  if ($qhandle) {
142  return @pg_affected_rows($qhandle);
143  } else {
144  return 0;
145  }
146 }
147 
148 function db_fetch_array($qhandle, $row=null) {
149  if ($qhandle) {
150  return @pg_fetch_array($qhandle,$row);
151  } else {
152  return 0;
153  }
154 }
155 function db_fetch_assoc($qhandle, $row=null) {
156 
157  if ($qhandle) {
158  return @pg_fetch_assoc($qhandle,$row);
159  } else {
160  return 0;
161  }
162 }
163 
164 
165 function db_fetch_object($qhandle,$row=null) {
166  if ($qhandle) {
167  return @pg_fetch_object($qhandle,$row);
168  } else {
169  return 0;
170  }
171 }
172 
173 function db_fetch_row($qhandle,$row=null) {
174  if ($qhandle) {
175  return @pg_fetch_row($qhandle,$row);
176  } else {
177  return 0;
178  }
179 }
180 
181 function db_fetch_all($qhandle) {
182  global $dbplat;
183  if ($qhandle) {
184  return @pg_fetch_all($qhandle);
185  }
186 }
187 
188 function db_insert_id($qhandle) {
189  if ($qhandle) {
190  // ** I don't believe this function will return what we want.
191  // * this returns the record oid, not the identity column
192  return @pg_getlastoid($qhandle);
193  } else {
194  return 0;
195  }
196 }
197 
198 function db_error() {
199  return @pg_errormessage();
200 }
201 
202 function db_last_error() {
203  return @pg_last_error();
204 }
205 
206 function db_free_result($qhandle) {
207  if ($qhandle) {
208  return @pg_freeresult($qhandle);
209  } else {
210  return 0;
211  }
212 }
213 
214 function db_cant_exist($sql, $qhandle) {
215  global $dbplat;
216  $result=0;
217  $keycheck=db_query($sql, $qhandle);
218 
219  if(@pg_num_rows($keycheck) == 0) {$result = 1;}
220 
221  return $result;
222 }
223 
224 /**
225  * Test the current status of the database connection
226  *
227  * @param resource $connection This is the current database connection that is being tested
228  *
229  * @return integer PGSQL_CONNECTION_OK or PGSQL_CONNECTION_BAD
230  */
231 function db_connection_status($qhandle) {
232  $retStatus;
233 
234  $retStatus = pg_connection_status($qhandle);
235 
236  return $retStatus;
237 }
238 
239 
240 /**
241  * What is the current connections transction status
242  *
243  * @param integer $pDbh - The current dB connection
244  *
245  * @return integer - This will return the standard php postgres constants
246  * **
247  * ** PGSQL_TRANSACTION_IDLE (currently idle)
248  * ** PGSQL_TRANSACTION_ACTIVE (a command is in progress)
249  * ** PGSQL_TRANSACTION_INTRANS (idle, in a valid transaction block)
250  * ** PGSQL_TRANSACTION_INERROR (idle, in a failed transaction block)
251  * ** PGSQL_TRANSACTION_UNKNOWN is reported if the connection is bad
252  * ** PGSQL_TRANSACTION_ACTIVE is reported only when a query has been sent to the server and not yet completed.
253  * **
254  */
255 function db_transaction_status($pDbh) {
256 
257 
258  if (db_connection_status($pDbh) === PGSQL_CONNECTION_OK) {
259  return pg_transaction_status($pDbh);
260  } else {
261  return false;
262  }
263 }
264 
265 /* *** TRANSACTION FUNCTION *** */
266 /**
267  * Send a WORK statement to the database connection
268  * This function will be used for BEGIN, ROLLBACK, COMMIT
269  * The calling code must be smart enough to rollback if commit fails
270  * The purpose of this function is to encapsulate the WORK queries,
271  * BUT not to add logic to handle failures
272  *
273  * @param integer $pDbh -- The current database connection
274  * @param constant $pWorkType -- The work query options are:
275  * HOMECU_WORK_BEGIN -- BEGIN a transaction work block
276  * HOMECU_COMMIT_BEGIN -- COMMIT a transaction work block (only if currently in transaction)
277  * HOMECU_ROLLBACK_BEGIN -- ROLLBACK a transaction work block (only if currently in transaction)
278  * @return boolean -- {true if request successful, false if fail}
279  */
280 function db_work ($pDbh, $pWorkType) {
281  $retVal = false; // Start with failure
282  switch ($pWorkType) {
283  case HOMECU_WORK_BEGIN:
284  $sql = "BEGIN WORK;";
285  break;
286  case HOMECU_WORK_COMMIT:
287  $sql = "COMMIT WORK;";
288  break;
289  case HOMECU_WORK_ROLLBACK:
290  $sql = "ROLLBACK WORK;";
291  break;
292  default:
293  // ** ERROR -- return false now
294  return $retVal;
295  }
296 
297  if ($pWorkType == HOMECU_WORK_BEGIN) {
298  $workRs = db_query($sql, $pDbh);
299 
300  if ($workRs) {
301  $retVal = true;
302  }
303  } else {
304  // * For COMMIT/ROLLBACK, slightly different - be sure we are in a transaction prior
305  $transStatus = db_transaction_status($pDbh);
306  if ($transStatus === PGSQL_TRANSACTION_ACTIVE || $transStatus === PGSQL_TRANSACTION_INTRANS) {
307  $workRs = db_query($sql, $pDbh);
308 
309  if ($workRs) {
310  $retVal = true;
311  }
312  } else {
313  // ** Since there was no active transaction all queries were committed, so this
314  // ** COMMIT
315  // * This function will return true in this state because the queries are being committed
316  // * So the subsequent queries should act like the commit was successful, since they can't be rolled back
317 
318  // * ROLLBACK
319  // * *should return false, since the rollback was not successful
320  $retVal = ($pWorkType == HOMECU_WORK_COMMIT ? true : false);
321 
322  }
323  }
324 
325  return $retVal;
326 }
327 
328 function db_must_exist($sql, $qhandle) {
329  $result=0;
330  $keycheck = db_query($sql, $qhandle);
331 
332  if(@pg_num_rows($keycheck) > 0) {$result = 1;}
333 
334  return $result;
335 }
336 
337 function prep_save($text, $msize=0) {
338  // Currently this is ONLY setup for POSTGRES
339  // What will need to be done is double up the ' or ", depending on
340  // which is used to define the string
341 
342  // Before modifying the text, make sure it does NOT go past the maximum
343  // NOTE: if msize is 0, then that is the same as unlimited
344  if ($msize > 0) {
345  $text = substr($text, 0, $msize);
346  }
347  $text = pg_escape_string(trim($text));
348  return $text;
349 }
350 
351 /**
352  *
353  * This will build the expression value for a value based on it's column data type
354  *
355  * @param string $pValue - This is the value that will be evaluated
356  * @param array[] $pColAttr - This is the array of column attributes for the columns
357  *
358  * @return string The returned string will be escaped for input into postgres
359  *
360  *
361  */
362 function db_build_expr_value($pValue, $pColAttr) {
363  $retStr = '';
364 
365  if (is_array($pColAttr)) {
366  // ** be sure the column attr is an array
367  switch (HCU_array_key_value('type', $pColAttr)) {
368  case DBTYPE_SERIAL:
369  $retStr = intval($pValue);
370  if ($retStr == 0)
371  $retStr= "default"; // Get the next in the sequence.
372  break;
373  case DBTYPE_INTEGER:
374  case DBTYPE_SMALLINT:
375  case DBTYPE_BIGINT:
376  $retStr = (is_null($pValue) || trim($pValue) == "") && HCU_array_key_value('nullable', $pColAttr) ? DBNULL : intval($pValue);
377  break;
378  case DBTYPE_NUMERIC:
379  // Evalute for the precision.
380  // ** Precision attribute is optional..
381  // ** If it is not there then assume 0 lenght for decimals
382  $precision = explode(',', HCU_array_key_value('precision', $pColAttr));
383  $decimals = ((count($precision) > 1) ? intval($precision[1]) : 0);
384  $retStr = (is_null($pValue) || trim($pValue) == "") && HCU_array_key_value('nullable', $pColAttr) ? DBNULL : number_format(floatval($pValue), $decimals, '.', '');
385  break;
386  case DBTYPE_VARCHAR:
387  case DBTYPE_CHAR:
388  $retStr = "'" . prep_save($pValue, intval(HCU_array_key_value('maxlength', $pColAttr))) . "'";
389  break;
390  case DBTYPE_CUSTOM_EXPRESSION:
391  $retStr = prep_save($pValue);
392  break;
393  case DBTYPE_TIMESTAMP:
394  case DBTYPE_TIMESTAMPTZ:
395  /**
396  * If the value is set to NOW, then use the postgresql function now
397  */
398  if ($pValue == DBTIMESTAMP_USENOW) {
399  $retStr = " now() ";
400  } elseif ($pValue == DBTIMESTAMP_USETS) {
401  $retStr = " clock_timestamp() ";
402  } elseif ($pValue == '') {
403  // ** If the value is empty, then the value saved is NULL
404  $retStr = " NULL ";
405  } else {
406  $retStr = "'" . prep_save($pValue) . "'";
407  }
408  break;
409  case DBTYPE_BOOLEAN:
410  $retStr= $pValue === true ? "TRUE" : ($pValue === false ? "FALSE" : ""); // Simplest case is if there is already a boolean in the value.
411  if ($retStr == "")
412  {
413  $nullable= HCU_array_key_value('nullable', $pColAttr);
414  $pValue= is_null($pValue) ? "" : trim(strtolower($pValue));
415  $retStr= $pValue == "" ? ($nullable ? DBNULL : "FALSE")
416  : (in_array($pValue, array("true", "t", "y", "yes", "1")) ? "TRUE" :
417  (in_array($pValue, array("false", "f", "n", "no", "0")) ? "FALSE" : ($nullable ? DBNULL : "FALSE")));
418  }
419  break;
420  }
421  }
422  return $retStr;
423 }
424 
425 
426 /**
427  * This function will return all the rows found in the sql.
428  * If any errors are encountered, it will return empty array
429  *
430  *
431  * @param object $pDbh - the current database handle
432  * @param string $pSql - The SQL string to execute
433  *
434  * @return mixed[] - return value is an array of rows from the query
435  * ON ERROR this will return FALSE ( === false)
436  */
437 function GetAllRowsFromSql($pDbh, $pSql) {
438 
439  $retRows = array();
440 
441  try {
442  /**
443  * TEST DB CONNECTION
444  */
445  if (db_connection_status($pDbh) == PGSQL_CONNECTION_BAD) {
446  throw new exception("Database Status Error", "901");
447  }
448 
449  $dbResults = db_query($pSql, $pDbh);
450 
451  if ($dbResults !== false) {
452  $retRows = db_fetch_all($dbResults);
453  } else {
454  throw new exception(db_last_error(), "902");
455  }
456 
457 
458  } catch (exception $e) {
459  $retRows = false;
460  }
461 
462  return $retRows;
463 }