5 # A Simple SQL Database Abstraction Object
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).
12 # Author: Edward Almasy (almasy@axisdata.com)
14 # Part of the AxisPHP library v1.2.5
15 # For more information see http://www.axisdata.com/AxisPHP/
24 # ---- PUBLIC INTERFACE --------------------------------------------------
41 $UserName = NULL, $Password = NULL, $DatabaseName = NULL, $HostName = NULL)
43 # save DB access parameter values
44 $this->
DBUserName = $UserName ? $UserName : self::$GlobalDBUserName;
45 $this->DBPassword = $Password ? $Password : self::$GlobalDBPassword;
47 (isset(self::$GlobalDBHostName) ? self::$GlobalDBHostName
49 $this->
DBName = $DatabaseName ? $DatabaseName : self::$GlobalDBName;
51 # if we don't already have a connection or DB access parameters were supplied
53 if (!array_key_exists($HandleIndex, self::$ConnectionHandles)
54 || $UserName || $Password || $DatabaseName || $HostName)
56 # open connection to DB server
57 self::$ConnectionHandles[$HandleIndex] = mysqli_connect(
60 or die(
"Could not connect to database: ".mysqli_connect_error());
62 # set local connection handle
63 $this->Handle = self::$ConnectionHandles[$HandleIndex];
66 mysqli_select_db($this->Handle, $this->
DBName)
67 or die(mysqli_error($this->Handle));
71 # set local connection handle
72 $this->Handle = self::$ConnectionHandles[$HandleIndex];
82 return array(
"DBUserName",
"DBPassword",
"DBHostName",
"DBName");
89 # open connection to DB server
90 $this->Handle = mysqli_connect(
92 or die(
"could not connect to database");
95 mysqli_select_db($this->Handle, $this->
DBName)
96 or die(mysqli_error($this->Handle));
109 # save default DB access parameters
110 self::$GlobalDBUserName = $UserName;
111 self::$GlobalDBPassword = $Password;
112 self::$GlobalDBHostName = $HostName;
114 # clear any existing DB connection handles
115 self::$ConnectionHandles = array();
124 # save new default DB name
125 self::$GlobalDBName = $DatabaseName;
127 # clear any existing DB connection handles
128 self::$ConnectionHandles = array();
137 # choose config variable to use based on server version number
139 ?
"storage_engine" :
"default_storage_engine";
141 # set storage engine in database
142 $this->
Query(
"SET ".$ConfigVar.
" = ".$Engine);
153 # retrieve version string
154 $Version = $this->
Query(
"SELECT VERSION() AS ServerVer",
"ServerVer");
158 # strip off any build/config suffix
159 $Pieces = explode(
"-", $Version);
160 $Version = array_shift($Pieces);
163 # return version number to caller
177 return mysqli_get_client_info();
187 return mysqli_get_host_info($this->Handle);
220 # if cache setting has changed
221 if (($NewSetting !== NULL) && ($NewSetting != self::$CachingFlag))
224 self::$CachingFlag = $NewSetting;
226 # clear any existing cached results
227 self::$QueryResultCache = array();
230 # return current setting to caller
231 return self::$CachingFlag;
246 if ($NewSetting !== NULL)
248 self::$AdvancedCachingFlag = $NewSetting;
250 return self::$AdvancedCachingFlag;
274 if ($NormalizeWhitespace && ($ErrorsToIgnore !== NULL))
276 $RevisedErrorsToIgnore = array();
277 foreach ($ErrorsToIgnore as $SqlPattern => $ErrMsgPattern)
279 $SqlPattern = preg_replace(
"/\\s+/",
"\\s+", $SqlPattern);
280 $RevisedErrorsToIgnore[$SqlPattern] = $ErrMsgPattern;
282 $ErrorsToIgnore = $RevisedErrorsToIgnore;
284 $this->ErrorsToIgnore = $ErrorsToIgnore;
294 return $this->ErrorIgnored;
307 function Query($QueryString, $FieldName =
"")
309 # clear flag that indicates whether query error was ignored
310 $this->ErrorIgnored = FALSE;
312 # if caching is enabled
313 if (self::$CachingFlag)
315 # if SQL statement is read-only
316 if ($this->IsReadOnlyStatement($QueryString))
318 # if we have statement in cache
319 if (isset(self::$QueryResultCache[$QueryString][
"NumRows"]))
321 if (self::$QueryDebugOutputFlag)
322 { print(
"DB-C: $QueryString<br>\n"); }
324 # make sure query result looks okay
325 $this->QueryHandle = TRUE;
327 # increment cache hit counter
328 self::$CachedQueryCounter++;
330 # make local copy of results
331 $this->QueryResults = self::$QueryResultCache[$QueryString];
332 $this->NumRows = self::$QueryResultCache[$QueryString][
"NumRows"];
334 # set flag to indicate that results should be retrieved from cache
335 $this->GetResultsFromCache = TRUE;
339 # execute SQL statement
340 $this->QueryHandle = $this->RunQuery($QueryString);
341 if (!$this->QueryHandle instanceof mysqli_result) {
return FALSE; }
343 # save number of rows in result
344 $this->NumRows = mysqli_num_rows($this->QueryHandle);
346 # if too many rows to cache
347 if ($this->NumRows >= 50)
349 # set flag to indicate that query results should not
350 # be retrieved from cache
351 $this->GetResultsFromCache = FALSE;
355 # if advanced caching is enabled
356 if (self::$AdvancedCachingFlag)
358 # save tables accessed by query
359 self::$QueryResultCache[$QueryString][
"TablesAccessed"] =
360 $this->TablesAccessed($QueryString);
364 if ($this->NumRows > 0)
367 for ($Row = 0; $Row < $this->NumRows; $Row++)
369 $this->QueryResults[$Row] =
370 mysqli_fetch_assoc($this->QueryHandle);
373 # cache query results
374 self::$QueryResultCache[$QueryString] = $this->QueryResults;
378 # clear local query results
379 unset($this->QueryResults);
382 # cache number of rows
383 self::$QueryResultCache[$QueryString][
"NumRows"] = $this->NumRows;
385 # set flag to indicate that query results should be retrieved from cache
386 $this->GetResultsFromCache = TRUE;
392 # if advanced caching is enabled
393 if (self::$AdvancedCachingFlag)
395 # if table modified by statement is known
396 $TableModified = $this->TableModified($QueryString);
399 # for each cached query
400 foreach (self::$QueryResultCache
401 as $CachedQueryString => $CachedQueryResult)
403 # if we know what tables were accessed
404 if ($CachedQueryResult[
"TablesAccessed"])
406 # if tables accessed include the one we may modify
407 if (in_array($TableModified, $CachedQueryResult[
"TablesAccessed"]))
409 # clear cached query results
410 unset($GLOBALS[
"APDBQueryResultCache"][$CachedQueryString]);
415 # clear cached query results
416 unset($GLOBALS[
"APDBQueryResultCache"][$CachedQueryString]);
422 # clear entire query result cache
423 self::$QueryResultCache = array();
428 # clear entire query result cache
429 self::$QueryResultCache = array();
432 # execute SQL statement
433 $this->QueryHandle = $this->RunQuery($QueryString);
434 if ($this->QueryHandle === FALSE) {
return FALSE; }
436 # set flag to indicate that query results should not be retrieved from cache
437 $this->GetResultsFromCache = FALSE;
441 $this->RowCounter = 0;
443 # increment query counter
444 self::$QueryCounter++;
448 # execute SQL statement
449 $this->QueryHandle = $this->RunQuery($QueryString);
450 if ($this->QueryHandle === FALSE) {
return FALSE; }
453 if (($FieldName !=
"") && ($this->QueryHandle != FALSE))
459 return $this->QueryHandle;
478 $FHandle = fopen($FileName,
"r");
480 # if file open succeeded
481 if ($FHandle !== FALSE)
483 # while lines left in file
486 while (!feof($FHandle))
488 # read in line from file
489 $Line = fgets($FHandle, 32767);
491 # trim whitespace from line
494 # if line is not empty and not a comment
495 if (!preg_match(
"/^#/", $Line)
496 && !preg_match(
"/^--/", $Line)
499 # add line to current query
502 # if line completes a query
503 if (preg_match(
"/;$/", $Line))
507 $Result = $this->
Query($Query);
510 # if query resulted in an error that is not ignorable
511 if ($Result === FALSE)
513 # stop processing queries and set error code
525 # return number of executed queries to caller
536 return $this->ErrMsg;
557 if ($NewValue !== NULL) { self::$DisplayErrors = $NewValue; }
558 return self::$DisplayErrors;
567 # if caching is enabled and query was cached
568 if (self::$CachingFlag && $this->GetResultsFromCache)
570 # return cached number of rows to caller
571 return $this->NumRows;
575 # call to this method after an unsuccessful query
576 if (!$this->QueryHandle instanceof mysqli_result)
581 # retrieve number of rows and return to caller
582 return mysqli_num_rows($this->QueryHandle);
593 # call to this method after an unsuccessful query
594 if (!$this->QueryHandle instanceof mysqli_result)
599 # retrieve number of rows and return to caller
600 return mysqli_affected_rows($this->Handle);
610 # if caching is enabled and query was cached
611 if (self::$CachingFlag && $this->GetResultsFromCache)
613 # if rows left to return
614 if ($this->RowCounter < $this->NumRows)
616 # retrieve row from cache
617 $Result = $this->QueryResults[$this->RowCounter];
619 # increment row counter
630 # call to this method after successful query
631 if ($this->QueryHandle instanceof mysqli_result)
633 $Result = mysqli_fetch_assoc($this->QueryHandle);
634 if ($Result === NULL) { $Result = FALSE; }
637 # call to this method after unsuccessful query
644 # return row to caller
656 # assume no rows will be returned
659 # for each available row
661 while ((($RowsFetched < $NumberOfRows) || ($NumberOfRows == NULL))
669 # return array of rows to caller
694 if ($IndexFieldName != NULL)
696 $Array[$Record[$IndexFieldName]] = $Record[$FieldName];
700 $Array[] = $Record[$FieldName];
717 return isset($Record[$FieldName]) ? $Record[$FieldName] : NULL;
728 return (
int)$this->
Query(
729 "SELECT LAST_INSERT_ID() AS InsertId",
748 $TableName, $FieldName, $NewValue, $Condition, &$CachedRecord)
750 # expand condition if supplied
751 if ($Condition != NULL) { $Condition =
" WHERE ".$Condition; }
753 # read cached record from database if not already loaded
754 if (!isset($CachedRecord))
756 $this->
Query(
"SELECT * FROM `".$TableName.
"` ".$Condition);
760 # if new value supplied
763 # update value in database
764 $this->
Query(
"UPDATE `".$TableName.
"` SET `".$FieldName.
"` = "
765 .(($NewValue === NULL) ?
"NULL" :
"'"
766 .mysqli_real_escape_string($this->Handle, $NewValue).
"'")
769 # update value in cached record
770 $CachedRecord[$FieldName] = $NewValue;
773 # return value from cached record to caller
774 return isset($CachedRecord[$FieldName])
775 ? $CachedRecord[$FieldName] : NULL;
795 $TableName, $FieldName, $NewValue, $Condition, &$CachedRecord)
799 $Condition, $CachedRecord);
819 $TableName, $FieldName, $NewValue, $Condition, &$CachedRecord)
823 $Condition, $CachedRecord);
839 return mysqli_real_escape_string($this->Handle, $String);
850 $this->
Query(
"-- ".$String);
860 $this->
Query(
"SHOW TABLES LIKE '".addslashes($TableName).
"'");
872 $this->
Query(
"DESC ".$TableName);
873 while ($CurrentFieldName = $this->
FetchField(
"Field"))
875 if ($CurrentFieldName == $FieldName) {
return TRUE; }
888 $this->
Query(
"DESC ".$TableName);
890 return $AllTypes[$FieldName];
900 self::$QueryDebugOutputFlag = $NewSetting;
910 return self::$QueryCounter;
921 return self::$CachedQueryCounter;
931 if (self::$QueryCounter)
933 return (self::$CachedQueryCounter / self::$QueryCounter) * 100;
943 # ---- PRIVATE INTERFACE -------------------------------------------------
951 private $QueryHandle;
952 private $QueryResults;
955 private $GetResultsFromCache;
956 private $ErrorIgnored = FALSE;
957 private $ErrorsToIgnore = NULL;
958 private $ErrMsg = NULL;
959 private $ErrNo = NULL;
961 private static $DisplayErrors = FALSE;
963 private static $GlobalDBUserName;
964 private static $GlobalDBPassword;
965 private static $GlobalDBHostName;
966 private static $GlobalDBName;
969 private static $QueryDebugOutputFlag = FALSE;
970 # flag for whether caching is turned on
971 private static $CachingFlag = TRUE;
972 # query result advanced caching flag
973 private static $AdvancedCachingFlag = FALSE;
974 # global cache for query results
975 private static $QueryResultCache = array();
977 private static $QueryCounter = 0;
978 private static $CachedQueryCounter = 0;
979 # database connection link handles
980 private static $ConnectionHandles = array();
987 private function IsReadOnlyStatement($QueryString)
989 return preg_match(
"/^[ ]*SELECT /i", $QueryString) ? TRUE : FALSE;
998 private function TableModified($QueryString)
1000 # assume we're not going to be able to determine table
1003 # split query into pieces
1004 $QueryString = trim($QueryString);
1005 $Words = preg_split(
"/\s+/", $QueryString);
1007 # if INSERT statement
1009 if (strtoupper($Words[0]) ==
"INSERT")
1011 # skip over modifying keywords
1012 while ((strtoupper($Words[$WordIndex]) ==
"LOW_PRIORITY")
1013 || (strtoupper($Words[$WordIndex]) ==
"DELAYED")
1014 || (strtoupper($Words[$WordIndex]) ==
"IGNORE")
1015 || (strtoupper($Words[$WordIndex]) ==
"INTO"))
1020 # next word is table name
1021 $TableName = $Words[$WordIndex];
1023 # else if UPDATE statement
1024 elseif (strtoupper($Words[0]) ==
"UPDATE")
1026 # skip over modifying keywords
1027 while ((strtoupper($Words[$WordIndex]) ==
"LOW_PRIORITY")
1028 || (strtoupper($Words[$WordIndex]) ==
"IGNORE"))
1033 # if word following next word is SET
1034 if (strtoupper($Words[$WordIndex + 1]) ==
"SET")
1036 # next word is table name
1037 $TableName = $Words[$WordIndex];
1040 # else if DELETE statement
1041 elseif (strtoupper($Words[0]) ==
"DELETE")
1043 # skip over modifying keywords
1044 while ((strtoupper($Words[$WordIndex]) ==
"LOW_PRIORITY")
1045 || (strtoupper($Words[$WordIndex]) ==
"IGNORE")
1046 || (strtoupper($Words[$WordIndex]) ==
"QUICK"))
1051 # if next term is FROM
1052 if (strtoupper($Words[$WordIndex]) ==
"FROM")
1054 # next word is table name
1056 $TableName = $Words[$WordIndex];
1060 # discard table name if it looks at all suspicious
1063 if (!preg_match(
"/[a-zA-Z0-9]+/", $TableName))
1069 # return table name (or lack thereof) to caller
1079 private function TablesAccessed($QueryString)
1081 # assume we're not going to be able to determine tables
1082 $TableNames = FALSE;
1084 # split query into pieces
1085 $QueryString = trim($QueryString);
1086 $Words = preg_split(
"/\s+/", $QueryString);
1087 $UQueryString = strtoupper($QueryString);
1088 $UWords = preg_split(
"/\s+/", $UQueryString);
1090 # if SELECT statement
1091 if ($UWords[0] ==
"SELECT")
1093 # keep going until we hit FROM or last word
1095 while (($UWords[$WordIndex] !=
"FROM")
1096 && strlen($UWords[$WordIndex]))
1102 if ($UWords[$WordIndex] ==
"FROM")
1104 # for each word after FROM
1106 while (strlen($UWords[$WordIndex]))
1108 # if current word ends with comma
1109 if (preg_match(
"/,$/", $Words[$WordIndex]))
1111 # strip off comma and add word to table name list
1112 $TableNames[] = substr($Words[$WordIndex], 0, -1);
1116 # add word to table name list
1117 $TableNames[] = $Words[$WordIndex];
1119 # if next word is not comma
1121 if ($Words[$WordIndex] !=
",")
1123 # if word begins with comma
1124 if (preg_match(
"/^,/", $Words[$WordIndex]))
1126 # strip off comma (NOTE: modifies $Words array!)
1127 $Words[$WordIndex] = substr($Words[$WordIndex], 1);
1129 # decrement index so we start with this word next pass
1134 # stop scanning words (non-basic JOINs not yet handled)
1146 # discard table names if they look at all suspicious
1149 foreach ($TableNames as $Name)
1151 if (!preg_match(
"/^[a-zA-Z0-9]+$/", $Name))
1153 $TableNames = FALSE;
1159 # return table name (or lack thereof) to caller
1169 private function RunQuery($QueryString)
1171 # log query start time if debugging output is enabled
1172 if (self::$QueryDebugOutputFlag) { $QueryStartTime = microtime(TRUE); }
1174 # run query against database
1175 $this->QueryHandle = mysqli_query($this->Handle, $QueryString) ;
1177 # print query and execution time if debugging output is enabled
1178 if (self::$QueryDebugOutputFlag)
1180 print
"DB: ".$QueryString.
" ["
1181 .sprintf(
"%.2f", microtime(TRUE) - $QueryStartTime)
1185 # if query failed and there are errors that we can ignore
1186 if (($this->QueryHandle === FALSE) && $this->ErrorsToIgnore)
1188 # for each pattern for an error that we can ignore
1189 foreach ($this->ErrorsToIgnore as $SqlPattern => $ErrMsgPattern)
1191 # if error matches pattern
1192 $ErrorMsg = mysqli_error($this->Handle);
1193 if (preg_match($SqlPattern, $QueryString)
1194 && preg_match($ErrMsgPattern, $ErrorMsg))
1196 # set return value to indicate error was ignored
1197 $this->QueryHandle = TRUE;
1199 # set internal flag to indicate that an error was ignored
1200 $this->ErrorIgnored = $ErrorMsg;
1202 # stop looking at patterns
1209 if ($this->QueryHandle === FALSE)
1211 # clear stored value for number of rows retrieved
1214 # retrieve error info
1215 $this->ErrMsg = mysqli_error($this->Handle);
1216 $this->ErrNo = mysqli_errno($this->Handle);
1218 # if we are supposed to be displaying errors
1219 if (self::$DisplayErrors)
1222 print(
"<b>SQL Error:</b> <i>".$this->ErrMsg
1223 .
"</i> (".$this->ErrNo.
")<br/>\n");
1224 print(
"<b>SQL Statement:</b> <i>"
1225 .htmlspecialchars($QueryString).
"</i><br/>\n");
1227 # retrieve execution trace that got us to this point
1228 $Trace = debug_backtrace();
1230 # remove current context from trace
1231 array_shift($Trace);
1233 # make sure file name and line number are available
1234 foreach ($Trace as $Index => $Loc)
1236 if (!array_key_exists(
"file", $Loc))
1238 $Trace[$Index][
"file"] =
"UNKNOWN";
1240 if (!array_key_exists(
"line", $Loc))
1242 $Trace[$Index][
"line"] =
"??";
1246 # determine length of leading path common to all file names in trace
1248 $OurFile = __FILE__;
1250 foreach ($Trace as $Loc)
1252 if ($Loc[
"file"] !=
"UNKNOWN")
1255 $FNameLength = strlen($Loc[
"file"]);
1256 while ($Index < $FNameLength &&
1257 $Loc[
"file"][$Index] == $OurFile[$Index])
1259 $PrefixLen = min($PrefixLen, $Index);
1263 foreach ($Trace as $Loc)
1267 foreach ($Loc[
"args"] as $Arg)
1270 switch (gettype($Arg))
1273 $ArgString .= $Arg ?
"TRUE" :
"FALSE";
1282 $ArgString .=
'"<i>'.htmlspecialchars(substr($Arg, 0, 40))
1283 .((strlen($Arg) > 40) ?
"..." :
"").
'</i>"';
1289 $ArgString .= strtoupper(gettype($Arg));
1293 $ArgString .= get_class($Arg);
1296 case "unknown type":
1297 $ArgString .=
"UNKNOWN";
1302 $Loc[
"file"] = substr($Loc[
"file"], $PrefixLen);
1303 $LocString .=
" ";
1304 if (array_key_exists(
"class", $Loc))
1305 { $LocString .= $Loc[
"class"].
"::"; }
1306 $LocString .= $Loc[
"function"].
"(".$ArgString.
")"
1307 .
" - ".$Loc[
"file"].
":".$Loc[
"line"]
1310 print(
"<b>Trace:</b><br>\n".$LocString);
1313 return $this->QueryHandle;
1317 # define return values (numerical values correspond to MySQL error codes)
1319 define(
"DB_OKAY", 0);
1320 define(
"DB_ERROR", 1);
1321 define(
"DB_ACCESSDENIED", 2);
1322 define(
"DB_UNKNOWNDB", 3);
1323 define(
"DB_UNKNOWNTABLE", 4);
1324 define(
"DB_SYNTAXERROR", 5);
1325 define(
"DB_DBALREADYEXISTS", 6);
1326 define(
"DB_DBDOESNOTEXIST", 7);
1327 define(
"DB_DISKFULL", 8);
1330 # define value to designate omitted arguments (so DB values can be set to NULL)
1331 define(
"DB_NOVALUE",
"!-_-_-DB_NOVALUE-_-_-!");
1333 # MySQL error code mapping
1344 # date() format for SQL dates
1345 define(
"DATE_SQL",
"Y-m-d H:i:s");
QueryErrMsg()
Get most recent error message text set by Query().
static Caching($NewSetting=NULL)
Get or set whether query result caching is currently enabled.
GetServerVersion($FullVersion=FALSE)
Get database server version number.
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.
SQL database abstraction object with smart query caching.
SetQueryErrorsToIgnore($ErrorsToIgnore, $NormalizeWhitespace=TRUE)
Set query errors to ignore.
DBUserName()
Get name used to connect with database server.
Database($UserName=NULL, $Password=NULL, $DatabaseName=NULL, $HostName=NULL)
Object constructor.
EscapeString($String)
Escape a string that may contain null bytes.
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")
GetClientVersion()
Get version number of the client libraries being used to connect to the database server (Currently th...
GetFieldType($TableName, $FieldName)
Get field (column) type.
NumRowsSelected()
Get number of rows returned by last SELECT or SHOW 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.
NumRowsAffected()
Get number of rows affected by last INSERT, UPDATE, REPLACE, or DELETE query.
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().
GetHostInfo()
Get database connection type and hostname.
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.