Blame | Last modification | View Log | Download | RSS feed
<html>
<body>
<h1>DBQuery</h1>
<p>
The DBQuery class extends mysqli, so it inherits all of those functions. It can be used as a drop in replacement for mysqli with a few enhancements
</p>
<ul>
<li>
when using class function <i>doSQL</i>
<ul>
<li>
Accepts an array of queries to be executed
</li>
<li>
queries which modify data can be logged to a separate table in the database.
</li>
<li>
Error trapping done more conveniently, with lists of errors returned as part of the return value
</li>
<li>
queries which modify data are wrapped in a commit/rollback block, so any failure in any query results in the database being in the form it was before the block was executed
</li>
<li>
returns a hash containing all rows from a select, a count of the number of rows returned, any errors and meta data on the columns returned
</li>
</li>
on data modifying queries, returns number of rows affected, last_insert_id and errors
</li>
</ul>
</li>
<li>
Additional convenience functions getOneRow and getOneDBValue
</li>
<li>
Enhanced real_escape_string (function makeSafeSQLConstant)
<ul>
<li>
correctly delimits fields based on data type (default string)
</li>
<li>
interprets strings which are date, date/time, integer, float and boolean values
</li>
</ul>
</li>
</ul>
<h2>public function doSQL( $query, $parameters )</h2>
<ul>
<li>
$query<br />
string containing a single <b>select</b>, <b>show</b>, <b>describe</b> or <b>explain</b> statement, or a single string/array of strings containing insert, delete, update or DDL statements.
</li>
<li>
$parameters<br />
hash of key/value pairs which is merged into class member $this->parameters. Convenient way to modify the way a query is executed. Also used to pass 'username' for audit function
</li>
</ul>
<h3>Non Data Modifying queries</h3>
<p>
doSQL runs one query. A single string starting with one of the keywords <b>select</b>, <b>show</b>, <b>describe</b> or <b>explain</b> is run as is, with results stored in the $parameters hash which is returned by the function. Hash key/value pairs are as follows:
</p>
<ul>
<li>
'returnData'<br />
Array (one row per return row from query). Each row contains either
<ul>
<li>
associative array, where key is field name and value is the value returned by the query
</li>
<li>
indexed array, where $parameters[0][0] is the first column of the first row returned
</li>
<li>
mixed array, each column is duplicated, combining associative and indexed
</li>
</ul>
</li>
<li>
'columnMetaData'<br />
metadata for each column returned by the query. See mysqli documentation for structure
</li>
<li>
'returntype'<br />
'fetchType'<br />
type of result requested. 'returntype' is the human readable <i>associative</i>, <i>array</i> or <i>both</i>, and 'fetchType' is the actual mysqli constant associated with it. Default is 'associative' and MYSQLI_ASSOC
</li>
<li>
'rowsAffected'<br />
number of rows returned by query
</li>
<li>
'numfields'<br />
number of columns in results
</li>
<li>
'error'<br />
(possibly empty) indexed array of errors encountered.
</li>
</ul>
<p>
Following code illustrates how to use doSQL to run a simple query.
</p>
<pre>
$db = new DBQuery( '127.0.0.1', 'camp', 'camp', 'camp' );
if ($db->connect_error) {
die('Connect Error (' . $db->connect_errno . ') ' . $db->connect_error);
}
$return = $db->doSQL( "select device.device_id 'id',device.name 'name', device_type.name 'type' from device join device_type using (device_type_id) where device.removed_date is null and device_type.show_as_system = 'Y'" );
if ( $return['error'] ) {
die ( DBQuery::error2String( $result['error'] ) );
} else {
for ( $i = 0; $i < $result['rowsAffected']; $i++ ) {
foreach ( $result['returnData'][$i] as $columnName => $value ) {
print "Row $i, Column $columnName == $value\n";
}
}
}
</pre>
<h3>Data Modifying queries</h3>
<p>
If the query is an array, or if it does <b>not</b> start with one of <b>select</b>, <b>show</b>, <b>describe</b> or <b>explain</b>, it is treated as a group of statements which will modify data. At this point, the query is treated differently.
</p>
<ul>
<li>
if it is a single string, it is converted to an array with one value
</li>
<li>
mysqli::autocommit is turned off
</li>
<li>
For each query in the array
<ul>
<li>
the function logIt is called, which records the query being executed
</li>
<li>
Query is executed
</li>
<li>
If an error occurs, no more statements are executed, the error array is updated with the mysql error
</li>
</ul>
</li>
<li>
If no errors occured, a commit is executed. Otherwise, rollback is called
</li>
</ul>
<p>
When complete, the results are stored in the parameters also.
</p>
<ul>
<li>
'query'<br />
contains the array of queries which were suposed to be executed
</li>
<li>
'rowsAffected'<br />
contains the number of rows modified by the <b>last</b> query executed
</li>
<li>
'lastInsertKey'<br />
contains the last used auto-increment value
</li>
<li>
'error'<br />
contains a (possibly empty) array of errors encountered
</li>
</ul>
<p>
Following code illustrates how to use doSQL to create a table and populate it
</p>
<pre>
$db = new DBQuery( '127.0.0.1', 'camp', 'camp', 'camp' );
if ($db->connect_error) {
die('Connect Error (' . $db->connect_errno . ') ' . $db->connect_error);
}
$result = $db->doSQL(
array(
'drop table if exists temp',
'create table temp ( col1 int unsigned )',
"insert into temp values ('mike')"
)
);
if ( $result['error'] ) {
print_r ( $result );
die ( DBQuery::error2String( $result['error'] ) );
}
</pre>
<h2>private function logIt( $username, $query, $recursion = false )</h2>
<p>
this function stores all queries which modify data. The first two parameters are the user who is logged in, and the query being executed. The third parameter, $recursion, is only used internally do detect the function calling itself.
</p>
<p>
logIt populates the table defined in $this->parameters['auditTable'] which defined as <b>_activity_log</b> by default. If the table does not exist, it is created with the following SQL.
</p>
<pre>
create table _activity_log (
_activity_log_id int unsigned not null auto_increment,
timestamp timestamp,
user varchar(64),
query text,
primary key(_activity_log_id)
) comment 'tracks queries which modify data
</pre>
<p>
The name of the table, and its structure can be overridden by directly calling <i>public function buildAuditTable( $tablename = '', $createStatement = '')</i>. If $tablename or $createStatement is not passed in, the defaults are used. The audit table <b>must</b> have the fields in question, however.
</p>
<h3>Update Statements</h3>
<p>
queries which begin with the keyword <b>update</b> are treated slightly different. The query is parsed for the table name and the where clause, and a new query is created which retrieves the values in the table before the update command is executed. All rows returned are then stored in the query column of the audit table before the command is executed. <b>Note: </b> this function only works for single table updates with clearly defined where clauses, ie update <i>tablename</i> set column=value, set column = value where <i>condition</i> [order by] ... [limit] ...
</p>
<h2>public static function makeSafeSQLConstant ( $value, $type='S', $default='null', $falsetrue='10' )</h2>
<p>
This is an extension of mysqli::real_escape_string which is aware of the data type you are expecting to pass in. The default is string, in which case it simply strips slashes, does the standard real_escape_string, and encloses the result in single quotes.
</p>
<p>
In all cases, if $value is empty, returns keyword <i>null</i>. This can be overridden by setting the $default parameter (warning, you are responsible for delimiting and escaping this)
</p>
<p>
If a data type other than string is set, the following actions are taken
</p>
<ul>
<li>
$type == 'date' or 'd'<br />
attempts to convert the string to a date using strtotime, and returns it in the format YYYY-MM-DD enclosed in single quotes. Any time portion is discarded
</li>
<li>
$type == 'datetime', 'timestamp' or 'dt'<br />
Attempts to conver the string to date and time using strtotime, returning it in format YYYY-MM-DD HH:MM:SS, enclosed in single quotes.
</li>
<li>
$type == 'integer', 'i', 'float', 'f'<br />
uses intval and floatval respectively to convert the string to a number. Returns the result as an unenclosed string.
</li>
<li>
$type == 'bool', 'boolean' or 'b'<br />
Looks for the character 0, 'f' or 'n'. If one of those is the first character in the string, returns 0, else returns 1. Note this can be overridden by setting the paramters $falsetrue when calling the function.
</li>
</ul>
<p>
A note on the date and datetime. This uses strtotime, which is a very powerful function, accepting strings like 'tomorrow at 5pm' and, in most cases, correctly calculating the result. However, the functionality of this is at times erratic.
</p>
<h2>public function getOneRow( $sql = null )</h2>
<p>
executes a query, returning only the first row as an associative array
</p>
<h2>public function getOneDBValue( $sql = null )</h2>
<p>
executes query, returning only the first column of the first row found.
</p>
<h2>Convenience functions</h2>
<ul>
<li>
public static function error2String( $error )<br />
when passed an array of errors, returns a string of newline terminated, human readable text. One line per array entry
</li>
<li>
load( $parameters ) and save()<br />
public functions which simply retrieve or set $this->parameters
</li>
<li>
__set( $name, $value) and __get( $name )<br />
public functions which retrieve or set individual members of the $this->parameters array
</li>
</ul>
</body>
</html>