CWIS Developer Documentation
Axis--Database.php
Go to the documentation of this file.
1 <?PHP
2 
3 #
4 # Axis--Database.php
5 # A Simple SQL Database Abstraction Object
6 #
7 # Copyright 1999-2002 Axis Data
8 # This code is free software that can be used or redistributed under the
9 # terms of Version 2 of the GNU General Public License, as published by the
10 # Free Software Foundation (http://www.fsf.org).
11 #
12 # Author: Edward Almasy (almasy@axisdata.com)
13 #
14 # Part of the AxisPHP library v1.2.5
15 # For more information see http://www.axisdata.com/AxisPHP/
16 #
17 
22 class Database {
23 
24  # ---- PUBLIC INTERFACE --------------------------------------------------
25  /*@(*/
27 
40  function Database(
41  $UserName = NULL, $Password = NULL, $DatabaseName = NULL, $HostName = NULL)
42  {
43  # save DB access parameter values
44  $this->DBUserName = $UserName ? $UserName : self::$GlobalDBUserName;
45  $this->DBPassword = $Password ? $Password : self::$GlobalDBPassword;
46  $this->DBHostName = $HostName ? $HostName :
47  (isset(self::$GlobalDBHostName) ? self::$GlobalDBHostName
48  : "localhost");
49  $this->DBName = $DatabaseName ? $DatabaseName : self::$GlobalDBName;
50 
51  # if we don't already have a connection or DB access parameters were supplied
52  $HandleIndex = $this->DBHostName.":".$this->DBName;
53  if (!array_key_exists($HandleIndex, self::$ConnectionHandles)
54  || $UserName || $Password || $DatabaseName || $HostName)
55  {
56  # open connection to DB server
57  self::$ConnectionHandles[$HandleIndex] = mysql_connect(
58  $this->DBHostName, $this->DBUserName,
59  $this->DBPassword, TRUE)
60  or die("Could not connect to database: ".mysql_error());
61 
62  # set local connection handle
63  $this->Handle = self::$ConnectionHandles[$HandleIndex];
64 
65  # select DB
66  mysql_select_db($this->DBName, $this->Handle)
67  or die(mysql_error($this->Handle));
68  }
69  else
70  {
71  # set local connection handle
72  $this->Handle = self::$ConnectionHandles[$HandleIndex];
73  }
74  }
75 
80  function __sleep()
81  {
82  return array("DBUserName", "DBPassword", "DBHostName", "DBName");
83  }
87  function __wakeup()
88  {
89  # open connection to DB server
90  $this->Handle = mysql_connect(
91  $this->DBHostName, $this->DBUserName, $this->DBPassword)
92  or die("could not connect to database");
93 
94  # select DB
95  mysql_select_db($this->DBName, $this->Handle)
96  or die(mysql_error($this->Handle));
97  }
107  static function SetGlobalServerInfo($UserName, $Password, $HostName = "localhost")
108  {
109  # save default DB access parameters
110  self::$GlobalDBUserName = $UserName;
111  self::$GlobalDBPassword = $Password;
112  self::$GlobalDBHostName = $HostName;
113 
114  # clear any existing DB connection handles
115  self::$ConnectionHandles = array();
116  }
117 
122  static function SetGlobalDatabaseName($DatabaseName)
123  {
124  # save new default DB name
125  self::$GlobalDBName = $DatabaseName;
126 
127  # clear any existing DB connection handles
128  self::$ConnectionHandles = array();
129  }
130 
135  function SetDefaultStorageEngine($Engine)
136  {
137  # choose config variable to use based on server version number
138  $ConfigVar = version_compare($this->GetServerVersion(), "5.5", "<")
139  ? "storage_engine" : "default_storage_engine";
140 
141  # set storage engine in database
142  $this->Query("SET ".$ConfigVar." = ".$Engine);
143  }
144 
149  function GetServerVersion()
150  {
151  # retrieve version string
152  $Version = $this->Query("SELECT VERSION() AS ServerVer", "ServerVer");
153 
154  # strip off any build/config suffix
155  $Pieces = explode("-", $Version);
156  $Version = array_shift($Pieces);
157 
158  # return version number to caller
159  return $Version;
160  }
161 
167  function DBHostName() { return $this->DBHostName; }
168 
174  function DBName() { return $this->DBName; }
175 
181  function DBUserName() { return $this->DBUserName; }
182 
190  static function Caching($NewSetting = NULL)
191  {
192  # if cache setting has changed
193  if (($NewSetting !== NULL) && ($NewSetting != self::$CachingFlag))
194  {
195  # save new setting
196  self::$CachingFlag = $NewSetting;
197 
198  # clear any existing cached results
199  self::$QueryResultCache = array();
200  }
201 
202  # return current setting to caller
203  return self::$CachingFlag;
204  }
205 
216  static function AdvancedCaching($NewSetting = NULL)
217  {
218  if ($NewSetting !== NULL)
219  {
220  self::$AdvancedCachingFlag = $NewSetting;
221  }
222  return self::$AdvancedCachingFlag;
223  }
224 
244  function SetQueryErrorsToIgnore($ErrorsToIgnore, $NormalizeWhitespace = TRUE)
245  {
246  if ($NormalizeWhitespace && ($ErrorsToIgnore !== NULL))
247  {
248  $RevisedErrorsToIgnore = array();
249  foreach ($ErrorsToIgnore as $SqlPattern => $ErrMsgPattern)
250  {
251  $SqlPattern = preg_replace("/\\s+/", "\\s+", $SqlPattern);
252  $RevisedErrorsToIgnore[$SqlPattern] = $ErrMsgPattern;
253  }
254  $ErrorsToIgnore = $RevisedErrorsToIgnore;
255  }
256  $this->ErrorsToIgnore = $ErrorsToIgnore;
257  }
258 
264  function IgnoredError()
265  {
266  return $this->ErrorIgnored;
267  }
268 
269  /*@)*/ /* Setup/Initialization */ /*@(*/
271 
279  function Query($QueryString, $FieldName = "")
280  {
281  # clear flag that indicates whether query error was ignored
282  $this->ErrorIgnored = FALSE;
283 
284  # if caching is enabled
285  if (self::$CachingFlag)
286  {
287  # if SQL statement is read-only
288  if ($this->IsReadOnlyStatement($QueryString))
289  {
290  # if we have statement in cache
291  if (isset(self::$QueryResultCache[$QueryString]["NumRows"]))
292  {
293  if (self::$QueryDebugOutputFlag)
294  { print("DB-C: $QueryString<br>\n"); }
295 
296  # make sure query result looks okay
297  $this->QueryHandle = TRUE;
298 
299  # increment cache hit counter
300  self::$CachedQueryCounter++;
301 
302  # make local copy of results
303  $this->QueryResults = self::$QueryResultCache[$QueryString];
304  $this->NumRows = self::$QueryResultCache[$QueryString]["NumRows"];
305 
306  # set flag to indicate that results should be retrieved from cache
307  $this->GetResultsFromCache = TRUE;
308  }
309  else
310  {
311  # execute SQL statement
312  $this->QueryHandle = $this->RunQuery($QueryString);
313  if (!is_resource($this->QueryHandle)) { return FALSE; }
314 
315  # save number of rows in result
316  $this->NumRows = mysql_num_rows($this->QueryHandle);
317 
318  # if too many rows to cache
319  if ($this->NumRows >= 50)
320  {
321  # set flag to indicate that query results should not
322  # be retrieved from cache
323  $this->GetResultsFromCache = FALSE;
324  }
325  else
326  {
327  # if advanced caching is enabled
328  if (self::$AdvancedCachingFlag)
329  {
330  # save tables accessed by query
331  self::$QueryResultCache[$QueryString]["TablesAccessed"] =
332  $this->TablesAccessed($QueryString);
333  }
334 
335  # if rows found
336  if ($this->NumRows > 0)
337  {
338  # load query results
339  for ($Row = 0; $Row < $this->NumRows; $Row++)
340  {
341  $this->QueryResults[$Row] =
342  mysql_fetch_assoc($this->QueryHandle);
343  }
344 
345  # cache query results
346  self::$QueryResultCache[$QueryString] = $this->QueryResults;
347  }
348  else
349  {
350  # clear local query results
351  unset($this->QueryResults);
352  }
353 
354  # cache number of rows
355  self::$QueryResultCache[$QueryString]["NumRows"] = $this->NumRows;
356 
357  # set flag to indicate that query results should be retrieved from cache
358  $this->GetResultsFromCache = TRUE;
359  }
360  }
361  }
362  else
363  {
364  # if advanced caching is enabled
365  if (self::$AdvancedCachingFlag)
366  {
367  # if table modified by statement is known
368  $TableModified = $this->TableModified($QueryString);
369  if ($TableModified)
370  {
371  # for each cached query
372  foreach (self::$QueryResultCache
373  as $CachedQueryString => $CachedQueryResult)
374  {
375  # if we know what tables were accessed
376  if ($CachedQueryResult["TablesAccessed"])
377  {
378  # if tables accessed include the one we may modify
379  if (in_array($TableModified, $CachedQueryResult["TablesAccessed"]))
380  {
381  # clear cached query results
382  unset($GLOBALS["APDBQueryResultCache"][$CachedQueryString]);
383  }
384  }
385  else
386  {
387  # clear cached query results
388  unset($GLOBALS["APDBQueryResultCache"][$CachedQueryString]);
389  }
390  }
391  }
392  else
393  {
394  # clear entire query result cache
395  self::$QueryResultCache = array();
396  }
397  }
398  else
399  {
400  # clear entire query result cache
401  self::$QueryResultCache = array();
402  }
403 
404  # execute SQL statement
405  $this->QueryHandle = $this->RunQuery($QueryString);
406  if ($this->QueryHandle === FALSE) { return FALSE; }
407 
408  # set flag to indicate that query results should not be retrieved from cache
409  $this->GetResultsFromCache = FALSE;
410  }
411 
412  # reset row counter
413  $this->RowCounter = 0;
414 
415  # increment query counter
416  self::$QueryCounter++;
417  }
418  else
419  {
420  # execute SQL statement
421  $this->QueryHandle = $this->RunQuery($QueryString);
422  if ($this->QueryHandle === FALSE) { return FALSE; }
423  }
424 
425  if (($FieldName != "") && ($this->QueryHandle != FALSE))
426  {
427  return $this->FetchField($FieldName);
428  }
429  else
430  {
431  return $this->QueryHandle;
432  }
433  }
434 
447  function ExecuteQueriesFromFile($FileName)
448  {
449  # open file
450  $FHandle = fopen($FileName, "r");
451 
452  # if file open succeeded
453  if ($FHandle !== FALSE)
454  {
455  # while lines left in file
456  $Query = "";
457  $QueryCount = 0;
458  while (!feof($FHandle))
459  {
460  # read in line from file
461  $Line = fgets($FHandle, 32767);
462 
463  # trim whitespace from line
464  $Line = trim($Line);
465 
466  # if line is not empty and not a comment
467  if (!preg_match("/^#/", $Line)
468  && !preg_match("/^--/", $Line)
469  && strlen($Line))
470  {
471  # add line to current query
472  $Query .= " ".$Line;
473 
474  # if line completes a query
475  if (preg_match("/;$/", $Line))
476  {
477  # run query
478  $QueryCount++;
479  $Result = $this->Query($Query);
480  $Query = "";
481 
482  # if query resulted in an error that is not ignorable
483  if ($Result === FALSE)
484  {
485  # stop processing queries and set error code
486  $QueryCount = NULL;
487  break;
488  }
489  }
490  }
491  }
492 
493  # close file
494  fclose($FHandle);
495  }
496 
497  # return number of executed queries to caller
498  return $QueryCount;
499  }
500 
506  function QueryErrMsg()
507  {
508  return $this->ErrMsg;
509  }
510 
516  function QueryErrNo()
517  {
518  return $this->ErrNo;
519  }
520 
527  static function DisplayQueryErrors($NewValue = NULL)
528  {
529  if ($NewValue !== NULL) { self::$DisplayErrors = $NewValue; }
530  return self::$DisplayErrors;
531  }
532 
537  function NumRowsSelected()
538  {
539  # if caching is enabled and query was cached
540  if (self::$CachingFlag && $this->GetResultsFromCache)
541  {
542  # return cached number of rows to caller
543  return $this->NumRows;
544  }
545  else
546  {
547  # call to this method after an unsuccessful query
548  if (!is_resource($this->QueryHandle))
549  {
550  return 0;
551  }
552 
553  # retrieve number of rows and return to caller
554  return mysql_num_rows($this->QueryHandle);
555  }
556  }
557 
563  function FetchRow()
564  {
565  # if caching is enabled and query was cached
566  if (self::$CachingFlag && $this->GetResultsFromCache)
567  {
568  # if rows left to return
569  if ($this->RowCounter < $this->NumRows)
570  {
571  # retrieve row from cache
572  $Result = $this->QueryResults[$this->RowCounter];
573 
574  # increment row counter
575  $this->RowCounter++;
576  }
577  else
578  {
579  # return nothing
580  $Result = FALSE;
581  }
582  }
583  else
584  {
585  # call to this method after successful query
586  if (is_resource($this->QueryHandle))
587  {
588  $Result = mysql_fetch_assoc($this->QueryHandle);
589  }
590 
591  # call to this method after unsuccessful query
592  else
593  {
594  $Result = FALSE;
595  }
596  }
597 
598  # return row to caller
599  return $Result;
600  }
601 
608  function FetchRows($NumberOfRows = NULL)
609  {
610  # assume no rows will be returned
611  $Result = array();
612 
613  # for each available row
614  $RowsFetched = 0;
615  while ((($RowsFetched < $NumberOfRows) || ($NumberOfRows == NULL))
616  && ($Row = $this->FetchRow()))
617  {
618  # add row to results
619  $Result[] = $Row;
620  $RowsFetched++;
621  }
622 
623  # return array of rows to caller
624  return $Result;
625  }
626 
643  function FetchColumn($FieldName, $IndexFieldName = NULL)
644  {
645  $Array = array();
646  while ($Record = $this->FetchRow())
647  {
648  if ($IndexFieldName != NULL)
649  {
650  $Array[$Record[$IndexFieldName]] = $Record[$FieldName];
651  }
652  else
653  {
654  $Array[] = $Record[$FieldName];
655  }
656  }
657  return $Array;
658  }
659 
668  function FetchField($FieldName)
669  {
670  $Record = $this->FetchRow();
671  return isset($Record[$FieldName]) ? $Record[$FieldName] : NULL;
672  }
673 
680  function LastInsertId()
681  {
682  return (int)$this->Query(
683  "SELECT LAST_INSERT_ID() AS InsertId",
684  "InsertId");
685  }
686 
701  function UpdateValue(
702  $TableName, $FieldName, $NewValue, $Condition, &$CachedRecord)
703  {
704  # expand condition if supplied
705  if ($Condition != NULL) { $Condition = " WHERE ".$Condition; }
706 
707  # read cached record from database if not already loaded
708  if (!isset($CachedRecord))
709  {
710  $this->Query("SELECT * FROM `".$TableName."` ".$Condition);
711  $CachedRecord = $this->FetchRow();
712  }
713 
714  # if new value supplied
715  if ($NewValue !== DB_NOVALUE)
716  {
717  # update value in database
718  $this->Query("UPDATE `".$TableName."` SET `".$FieldName."` = "
719  .(($NewValue === NULL) ? "NULL" : "'"
720  .mysql_real_escape_string($NewValue)."'")
721  .$Condition);
722 
723  # update value in cached record
724  $CachedRecord[$FieldName] = $NewValue;
725  }
726 
727  # return value from cached record to caller
728  return isset($CachedRecord[$FieldName])
729  ? $CachedRecord[$FieldName] : NULL;
730  }
731 
748  function UpdateIntValue(
749  $TableName, $FieldName, $NewValue, $Condition, &$CachedRecord)
750  {
751  return $this->UpdateValue($TableName, $FieldName,
752  (($NewValue === DB_NOVALUE) ? DB_NOVALUE : (int)$NewValue),
753  $Condition, $CachedRecord);
754  }
755 
773  $TableName, $FieldName, $NewValue, $Condition, &$CachedRecord)
774  {
775  return $this->UpdateValue($TableName, $FieldName,
776  (($NewValue === DB_NOVALUE) ? DB_NOVALUE : (float)$NewValue),
777  $Condition, $CachedRecord);
778  }
779 
780  /*@)*/ /* Data Manipulation */ /*@(*/
782 
789  function LogComment($String)
790  {
791  $this->Query("-- ".$String);
792  }
793 
799  function TableExists($TableName)
800  {
801  $this->Query("SHOW TABLES LIKE '".addslashes($TableName)."'");
802  return $this->NumRowsSelected() ? TRUE : FALSE;
803  }
804 
811  function FieldExists($TableName, $FieldName)
812  {
813  $this->Query("DESC ".$TableName);
814  while ($CurrentFieldName = $this->FetchField("Field"))
815  {
816  if ($CurrentFieldName == $FieldName) { return TRUE; }
817  }
818  return FALSE;
819  }
820 
827  function GetFieldType($TableName, $FieldName)
828  {
829  $this->Query("DESC ".$TableName);
830  return $this->FetchField("Type");
831  }
832 
838  static function QueryDebugOutput($NewSetting)
839  {
840  self::$QueryDebugOutputFlag = $NewSetting;
841  }
842 
848  static function NumQueries()
849  {
850  return self::$QueryCounter;
851  }
852 
859  static function NumCacheHits()
860  {
861  return self::$CachedQueryCounter;
862  }
863 
869  static function CacheHitRate()
870  {
871  if (self::$QueryCounter)
872  {
873  return (self::$CachedQueryCounter / self::$QueryCounter) * 100;
874  }
875  else
876  {
877  return 0;
878  }
879  }
880 
881  /*@)*/ /* Miscellaneous */
882 
883  # ---- PRIVATE INTERFACE -------------------------------------------------
884 
885  protected $DBUserName;
886  protected $DBPassword;
887  protected $DBHostName;
888  protected $DBName;
889 
890  private $Handle;
891  private $QueryHandle;
892  private $QueryResults;
893  private $RowCounter;
894  private $NumRows;
895  private $GetResultsFromCache;
896  private $ErrorIgnored = FALSE;
897  private $ErrorsToIgnore = NULL;
898  private $ErrMsg = NULL;
899  private $ErrNo = NULL;
900 
901  private static $DisplayErrors = FALSE;
902 
903  private static $GlobalDBUserName;
904  private static $GlobalDBPassword;
905  private static $GlobalDBHostName;
906  private static $GlobalDBName;
907 
908  # debug output flag
909  private static $QueryDebugOutputFlag = FALSE;
910  # flag for whether caching is turned on
911  private static $CachingFlag = TRUE;
912  # query result advanced caching flag
913  private static $AdvancedCachingFlag = FALSE;
914  # global cache for query results
915  private static $QueryResultCache = array();
916  # stats counters
917  private static $QueryCounter = 0;
918  private static $CachedQueryCounter = 0;
919  # database connection link handles
920  private static $ConnectionHandles = array();
921 
927  private function IsReadOnlyStatement($QueryString)
928  {
929  return preg_match("/^[ ]*SELECT /i", $QueryString) ? TRUE : FALSE;
930  }
931 
938  private function TableModified($QueryString)
939  {
940  # assume we're not going to be able to determine table
941  $TableName = FALSE;
942 
943  # split query into pieces
944  $QueryString = trim($QueryString);
945  $Words = preg_split("/\s+/", $QueryString);
946 
947  # if INSERT statement
948  $WordIndex = 1;
949  if (strtoupper($Words[0]) == "INSERT")
950  {
951  # skip over modifying keywords
952  while ((strtoupper($Words[$WordIndex]) == "LOW_PRIORITY")
953  || (strtoupper($Words[$WordIndex]) == "DELAYED")
954  || (strtoupper($Words[$WordIndex]) == "IGNORE")
955  || (strtoupper($Words[$WordIndex]) == "INTO"))
956  {
957  $WordIndex++;
958  }
959 
960  # next word is table name
961  $TableName = $Words[$WordIndex];
962  }
963  # else if UPDATE statement
964  elseif (strtoupper($Words[0]) == "UPDATE")
965  {
966  # skip over modifying keywords
967  while ((strtoupper($Words[$WordIndex]) == "LOW_PRIORITY")
968  || (strtoupper($Words[$WordIndex]) == "IGNORE"))
969  {
970  $WordIndex++;
971  }
972 
973  # if word following next word is SET
974  if (strtoupper($Words[$WordIndex + 1]) == "SET")
975  {
976  # next word is table name
977  $TableName = $Words[$WordIndex];
978  }
979  }
980  # else if DELETE statement
981  elseif (strtoupper($Words[0]) == "DELETE")
982  {
983  # skip over modifying keywords
984  while ((strtoupper($Words[$WordIndex]) == "LOW_PRIORITY")
985  || (strtoupper($Words[$WordIndex]) == "IGNORE")
986  || (strtoupper($Words[$WordIndex]) == "QUICK"))
987  {
988  $WordIndex++;
989  }
990 
991  # if next term is FROM
992  if (strtoupper($Words[$WordIndex]) == "FROM")
993  {
994  # next word is table name
995  $WordIndex++;
996  $TableName = $Words[$WordIndex];
997  }
998  }
999 
1000  # discard table name if it looks at all suspicious
1001  if ($TableName)
1002  {
1003  if (!preg_match("/[a-zA-Z0-9]+/", $TableName))
1004  {
1005  $TableName = FALSE;
1006  }
1007  }
1008 
1009  # return table name (or lack thereof) to caller
1010  return $TableName;
1011  }
1012 
1019  private function TablesAccessed($QueryString)
1020  {
1021  # assume we're not going to be able to determine tables
1022  $TableNames = FALSE;
1023 
1024  # split query into pieces
1025  $QueryString = trim($QueryString);
1026  $Words = preg_split("/\s+/", $QueryString);
1027  $UQueryString = strtoupper($QueryString);
1028  $UWords = preg_split("/\s+/", $UQueryString);
1029 
1030  # if SELECT statement
1031  if ($UWords[0] == "SELECT")
1032  {
1033  # keep going until we hit FROM or last word
1034  $WordIndex = 1;
1035  while (($UWords[$WordIndex] != "FROM")
1036  && strlen($UWords[$WordIndex]))
1037  {
1038  $WordIndex++;
1039  }
1040 
1041  # if we hit FROM
1042  if ($UWords[$WordIndex] == "FROM")
1043  {
1044  # for each word after FROM
1045  $WordIndex++;
1046  while (strlen($UWords[$WordIndex]))
1047  {
1048  # if current word ends with comma
1049  if (preg_match("/,$/", $Words[$WordIndex]))
1050  {
1051  # strip off comma and add word to table name list
1052  $TableNames[] = substr($Words[$WordIndex], 0, -1);
1053  }
1054  else
1055  {
1056  # add word to table name list
1057  $TableNames[] = $Words[$WordIndex];
1058 
1059  # if next word is not comma
1060  $WordIndex++;
1061  if ($Words[$WordIndex] != ",")
1062  {
1063  # if word begins with comma
1064  if (preg_match("/^,/", $Words[$WordIndex]))
1065  {
1066  # strip off comma (NOTE: modifies $Words array!)
1067  $Words[$WordIndex] = substr($Words[$WordIndex], 1);
1068 
1069  # decrement index so we start with this word next pass
1070  $WordIndex--;
1071  }
1072  else
1073  {
1074  # stop scanning words (non-basic JOINs not yet handled)
1075  break;
1076  }
1077  }
1078  }
1079 
1080  # move to next word
1081  $WordIndex++;
1082  }
1083  }
1084  }
1085 
1086  # discard table names if they look at all suspicious
1087  if ($TableNames)
1088  {
1089  foreach ($TableNames as $Name)
1090  {
1091  if (!preg_match("/^[a-zA-Z0-9]+$/", $Name))
1092  {
1093  $TableNames = FALSE;
1094  break;
1095  }
1096  }
1097  }
1098 
1099  # return table name (or lack thereof) to caller
1100  return $TableNames;
1101  }
1102 
1109  private function RunQuery($QueryString)
1110  {
1111  # log query start time if debugging output is enabled
1112  if (self::$QueryDebugOutputFlag) { $QueryStartTime = microtime(TRUE); }
1113 
1114  # run query against database
1115  $this->QueryHandle = mysql_query($QueryString, $this->Handle);
1116 
1117  # print query and execution time if debugging output is enabled
1118  if (self::$QueryDebugOutputFlag)
1119  {
1120  print "DB: ".$QueryString." ["
1121  .sprintf("%.2f", microtime(TRUE) - $QueryStartTime)
1122  ."s]"."<br>\n";
1123  }
1124 
1125  # if query failed and there are errors that we can ignore
1126  if (($this->QueryHandle === FALSE) && $this->ErrorsToIgnore)
1127  {
1128  # for each pattern for an error that we can ignore
1129  foreach ($this->ErrorsToIgnore as $SqlPattern => $ErrMsgPattern)
1130  {
1131  # if error matches pattern
1132  $ErrorMsg = mysql_error($this->Handle);
1133  if (preg_match($SqlPattern, $QueryString)
1134  && preg_match($ErrMsgPattern, $ErrorMsg))
1135  {
1136  # set return value to indicate error was ignored
1137  $this->QueryHandle = TRUE;
1138 
1139  # set internal flag to indicate that an error was ignored
1140  $this->ErrorIgnored = $ErrorMsg;
1141 
1142  # stop looking at patterns
1143  break;
1144  }
1145  }
1146  }
1147 
1148  # if query failed
1149  if ($this->QueryHandle === FALSE)
1150  {
1151  # clear stored value for number of rows retrieved
1152  $this->NumRows = 0;
1153 
1154  # retrieve error info
1155  $this->ErrMsg = mysql_error($this->Handle);
1156  $this->ErrNo = mysql_errno($this->Handle);
1157 
1158  # if we are supposed to be displaying errors
1159  if (self::$DisplayErrors)
1160  {
1161  # print error info
1162  print("<b>SQL Error:</b> <i>".$this->ErrMsg
1163  ."</i> (".$this->ErrNo.")<br/>\n");
1164  print("<b>SQL Statement:</b> <i>"
1165  .htmlspecialchars($QueryString)."</i><br/>\n");
1166 
1167  # retrieve execution trace that got us to this point
1168  $Trace = debug_backtrace();
1169 
1170  # remove current context from trace
1171  array_shift($Trace);
1172 
1173  # make sure file name and line number are available
1174  foreach ($Trace as $Index => $Loc)
1175  {
1176  if (!array_key_exists("file", $Loc))
1177  {
1178  $Trace[$Index]["file"] = "UNKNOWN";
1179  }
1180  if (!array_key_exists("line", $Loc))
1181  {
1182  $Trace[$Index]["line"] = "??";
1183  }
1184  }
1185 
1186  # determine length of leading path common to all file names in trace
1187  $LocString = "";
1188  $OurFile = __FILE__;
1189  $PrefixLen = 9999;
1190  foreach ($Trace as $Loc)
1191  {
1192  if ($Loc["file"] != "UNKNOWN")
1193  {
1194  $Index = 0;
1195  while ($Loc["file"][$Index] == $OurFile[$Index])
1196  { $Index++; }
1197  $PrefixLen = min($PrefixLen, $Index);
1198  }
1199  }
1200 
1201  foreach ($Trace as $Loc)
1202  {
1203  $Sep = "";
1204  $ArgString = "";
1205  foreach ($Loc["args"] as $Arg)
1206  {
1207  $ArgString .= $Sep;
1208  switch (gettype($Arg))
1209  {
1210  case "boolean":
1211  $ArgString .= $Arg ? "TRUE" : "FALSE";
1212  break;
1213 
1214  case "integer":
1215  case "double":
1216  $ArgString .= $Arg;
1217  break;
1218 
1219  case "string":
1220  $ArgString .= '"<i>'.htmlspecialchars(substr($Arg, 0, 40))
1221  .((strlen($Arg) > 40) ? "..." : "").'</i>"';
1222  break;
1223 
1224  case "array":
1225  case "resource":
1226  case "NULL":
1227  $ArgString .= strtoupper(gettype($Arg));
1228  break;
1229 
1230  case "object":
1231  $ArgString .= get_class($Arg);
1232  break;
1233 
1234  case "unknown type":
1235  $ArgString .= "UNKNOWN";
1236  break;
1237  }
1238  $Sep = ",";
1239  }
1240  $Loc["file"] = substr($Loc["file"], $PrefixLen);
1241  $LocString .= "&nbsp;&nbsp;";
1242  if (array_key_exists("class", $Loc))
1243  { $LocString .= $Loc["class"]."::"; }
1244  $LocString .= $Loc["function"]."(".$ArgString.")"
1245  ." - ".$Loc["file"].":".$Loc["line"]
1246  ."<br>\n";
1247  }
1248  print("<b>Trace:</b><br>\n".$LocString);
1249  }
1250  }
1251  return $this->QueryHandle;
1252  }
1253 }
1254 
1255 # define return values (numerical values correspond to MySQL error codes)
1256 define("DB_OKAY", 0);
1257 define("DB_ERROR", 1);
1258 define("DB_ACCESSDENIED", 2);
1259 define("DB_UNKNOWNDB", 3);
1260 define("DB_UNKNOWNTABLE", 4);
1261 define("DB_SYNTAXERROR", 5);
1262 define("DB_DBALREADYEXISTS", 6);
1263 define("DB_DBDOESNOTEXIST", 7);
1264 define("DB_DISKFULL", 8);
1265 
1266 # define value to designate omitted arguments (so DB values can be set to NULL)
1267 define("DB_NOVALUE", "!-_-_-DB_NOVALUE-_-_-!");
1268 
1269 # MySQL error code mapping
1271  1045 => DB_ACCESSDENIED,
1272  1049 => DB_UNKNOWNDB,
1273  1046 => DB_UNKNOWNTABLE,
1274  1064 => DB_SYNTAXERROR,
1275  1007 => DB_DBALREADYEXISTS, # ? (not sure)
1276  1008 => DB_DBDOESNOTEXIST, # ? (not sure)
1277  1021 => DB_DISKFULL, # ? (not sure)
1278  );
1279 
1280 # date() format for SQL dates
1281 define("DATE_SQL", "Y-m-d H:i:s");
1282 
QueryErrMsg()
Get most recent error message text set by Query().
static Caching($NewSetting=NULL)
Get or set whether query result caching is currently enabled.
const DB_UNKNOWNDB
static SetGlobalDatabaseName($DatabaseName)
Set default database name.
SetDefaultStorageEngine($Engine)
Set default database storage engine.
ExecuteQueriesFromFile($FileName)
Execute queries from specified file.
UpdateIntValue($TableName, $FieldName, $NewValue, $Condition, &$CachedRecord)
A convenience function to get or set an integer value in the database.
const DB_SYNTAXERROR
SQL database abstraction object with smart query caching.
GetServerVersion()
Get database server version number.
SetQueryErrorsToIgnore($ErrorsToIgnore, $NormalizeWhitespace=TRUE)
Set query errors to ignore.
const DB_NOVALUE
DBUserName()
Get name used to connect with database server.
Database($UserName=NULL, $Password=NULL, $DatabaseName=NULL, $HostName=NULL)
Object constructor.
FetchRow()
Get next database row retrieved by most recent query.
LastInsertId()
Get ID of row added by the last SQL "INSERT" statement.
TableExists($TableName)
Get whether specified table exists.
static SetGlobalServerInfo($UserName, $Password, $HostName="localhost")
const DB_DBALREADYEXISTS
PHP
Definition: OAIClient.php:39
GetFieldType($TableName, $FieldName)
Get field (column) type.
NumRowsSelected()
Get number of rows returned by last query.
FetchRows($NumberOfRows=NULL)
Get specified number of database rows retrieved by most recent query.
static QueryDebugOutput($NewSetting)
Enable or disable debugging output for queries.
Query($QueryString, $FieldName="")
Query database (with caching if enabled).
FetchField($FieldName)
Pull next row from last DB query and get a specific value from that row.
FieldExists($TableName, $FieldName)
Get whether specified field exists in specified table.
static NumCacheHits()
Get the number of queries that have resulted in cache hits since program execution began...
FetchColumn($FieldName, $IndexFieldName=NULL)
Get all available values for specified database field retrieved by most recent query.
DBHostName()
Get host name of system on which database server resides.
const DB_ACCESSDENIED
UpdateFloatValue($TableName, $FieldName, $NewValue, $Condition, &$CachedRecord)
A convenience function to get or set a float value in the database.
QueryErrNo()
Get most recent error code set by Query().
$APDBErrorCodeMappings
UpdateValue($TableName, $FieldName, $NewValue, $Condition, &$CachedRecord)
A convenience function to get or set a value in the database.
static AdvancedCaching($NewSetting=NULL)
Get or set whether advanced query result cachine is currently enabled.
static DisplayQueryErrors($NewValue=NULL)
Get/set whether Query() errors will be displayed.
static CacheHitRate()
Get the ratio of query cache hits to queries as a percentage.
IgnoredError()
Check whether an error was ignored by the most recent query.
DBName()
Get current database name.
LogComment($String)
Peform query that consists of SQL comment statement.
__wakeup()
Restore database connection when unserialized.
static NumQueries()
Get the number of queries that have been run since program execution began.
const DB_DBDOESNOTEXIST
const DB_UNKNOWNTABLE
const DB_DISKFULL