22 Commits
v1.4 ... v1.7

Author SHA1 Message Date
Sergey Tsalkov
a1f01a4f87 few more fixes and tests for WhereClause 2011-09-23 22:03:15 -07:00
Sergey Tsalkov
80cc78edcd insertUpdate() can now handle a second array for the update component, or nothing, so it'll
re-use the insert array for the update component
2011-09-23 21:29:40 -07:00
Sergey Tsalkov
5050205e58 add insertUpdate() function for "insert ... on duplicate key update" behavior 2011-09-23 19:15:41 -07:00
Sergey Tsalkov
9f3aa571dc add some simple tests for the WhereClause system, which will now be official and documented 2011-09-23 18:44:34 -07:00
Sergey Tsalkov
a2800ef04b add insertIgnore() function -- pretty self explanatory 2011-09-23 16:11:10 -07:00
Sergey Tsalkov
164c7157a6 queryRaw() will now be officially supported, returns mysqli_result instead of array of assoc
arrays
2011-09-23 15:57:36 -07:00
Sergey Tsalkov
f09308a3f7 re-organize test files, make it easy to test for both php 5.2 and 5.3 2011-09-23 15:51:35 -07:00
Sergey Tsalkov
69bfe15ebb add test case regarding BLOBs 2011-08-25 23:54:52 -07:00
Sergey Tsalkov
7621b50a02 handle non-sql errors (such as failure to connect to MySQL server) in a user-defined way
adds DB::$nonsql_error_handler and DB::$throw_exception_on_nonsql_error
2011-08-25 23:34:37 -07:00
Sergey Tsalkov
4122fe52c1 collapse some redundant code into a function 2011-06-02 18:57:46 -04:00
Sergey Tsalkov
8072f6ab07 use static class variable, not static function variable, to hold mysql connection 2011-06-01 17:30:28 -04:00
Sergey Tsalkov
860da8d18a insert(), replace(), and update() now handle the value NULL correctly 2011-05-31 21:50:24 -04:00
Sergey Tsalkov
0ed2837f3d on second thought, we won't have insertMany() and replaceMany(), but insert() and replace()
will figure out which one you mean

this means that a minor undocumented feature, being able to insert an array and have it
automatically serialized, can't exist anymore
2011-04-29 01:48:27 -04:00
Sergey Tsalkov
65cae974c5 remove unused variable 2011-04-28 18:51:53 -04:00
Sergey Tsalkov
96892fa6c2 DB::$param_char can now be used to change the char that needs to appear in front of params (% is the default) 2011-04-28 18:41:13 -04:00
Sergey Tsalkov
ad4889da09 revert last commit -- this is a bad way to do it, and I'll have to come up with something else
to let people use strings like %i in their SQL and bypass the parser
2011-04-28 18:14:59 -04:00
Sergey Tsalkov
12604d7854 bugfix: let people have literal %'s in their queries without confusing the parser
by using %% instead
2011-04-23 20:31:18 -04:00
Sergey Tsalkov
8c5299c2e2 * add insertMany() and replaceMany() to let you do multiple inserts in one SQL command
* error and success handlers can now be set to static and object methods
2011-04-23 00:46:51 -04:00
Sergey Tsalkov
964a36e4c2 sqleval() can now be used with %s, %i, and all that good stuff
there is probably no good reason to do this, as things like md5() can be done
from PHP, but people keep asking for it, so here it is :)
2011-04-22 23:29:09 -04:00
Sergey Tsalkov
68774532e1 add delete() function -- mostly for completeness with insert(), update(), etc 2011-04-22 23:15:14 -04:00
Sergey Tsalkov
2985815750 * add tests for tableList() and columnList() -- those are now supported functions
* remove some unused code, minor cleanup
2011-04-22 23:03:37 -04:00
Sergey Tsalkov
4faebb957c add DB::sqleval() -- can be used with insert() and update() to inject raw sql stuff like NOW() 2011-04-08 13:56:28 -04:00
8 changed files with 588 additions and 172 deletions

1
.gitignore vendored
View File

@@ -0,0 +1 @@
simpletest/test_setup.php

View File

@@ -19,40 +19,63 @@
class DB
{
public static $internal_mysql = null;
public static $insert_id = 0;
public static $num_rows = 0;
public static $affected_rows = 0;
public static $stmt = null;
public static $queryResult = null;
public static $queryResultType = null;
public static $old_db = null;
public static $current_db = null;
public static $current_db_limit = 0;
public static $dbName = null;
public static $dbName = '';
public static $user = '';
public static $password = '';
public static $host = 'localhost';
public static $port = null;
public static $encoding = 'latin1';
public static $queryMode = 'queryAllRows';
public static $success_handler = false;
public static $error_handler = 'meekrodb_error_handler';
public static $throw_exception_on_error = false;
public static $param_char = '%';
public static function get($dbName = '') {
static $mysql = null;
public static $success_handler = false;
public static $error_handler = true;
public static $throw_exception_on_error = false;
public static $nonsql_error_handler = null;
public static $throw_exception_on_nonsql_error = false;
public static function get() {
$mysql = DB::$internal_mysql;
if ($mysql == null) {
if (! DB::$port) DB::$port = ini_get('mysqli.default_port');
if (DB::$dbName != '') $dbName = DB::$dbName;
DB::$current_db = $dbName;
$mysql = new mysqli(DB::$host, DB::$user, DB::$password, $dbName, DB::$port);
DB::$current_db = DB::$dbName;
$mysql = new mysqli(DB::$host, DB::$user, DB::$password, DB::$dbName, DB::$port);
if ($mysql->connect_error) {
DB::nonSQLError('Unable to connect to MySQL server! Error: ' . $mysql->connect_error);
}
$mysql->set_charset(DB::$encoding);
}
DB::$internal_mysql = $mysql;
}
return $mysql;
}
public static function nonSQLError($message) {
if (DB::$throw_exception_on_nonsql_error) {
$e = new MeekroDBException($message);
throw $e;
}
$error_handler = is_callable(DB::$nonsql_error_handler) ? DB::$nonsql_error_handler : 'meekrodb_error_handler';
call_user_func($error_handler, array(
'type' => 'nonsql',
'error' => $message
));
}
public static function debugMode($handler = true) {
DB::$success_handler = $handler;
}
@@ -63,12 +86,11 @@ class DB
public static function numRows() { return DB::$num_rows; }
public static function useDB() { $args = func_get_args(); return call_user_func_array('DB::setDB', $args); }
public static function setDB($dbName, $limit=0) {
public static function setDB($dbName) {
$db = DB::get();
DB::$old_db = DB::$current_db;
if (! $db->select_db($dbName)) die("unable to set db to $dbName");
if (! $db->select_db($dbName)) DB::nonSQLError("Unable to set database to $dbName");
DB::$current_db = $dbName;
DB::$current_db_limit = $limit;
}
@@ -85,10 +107,24 @@ class DB
}
public static function escape($str) {
$db = DB::get(DB::$dbName);
$db = DB::get();
return $db->real_escape_string($str);
}
public static function sanitize($value) {
if (is_object($value) && ($value instanceof MeekroDBEval)) {
$value = $value->text;
} else {
if (is_array($value) || is_object($value)) $value = serialize($value);
if (is_string($value)) $value = "'" . DB::escape($value) . "'";
else if (is_null($value)) $value = 'NULL';
else if (is_bool($value)) $value = ($value ? 1 : 0);
}
return $value;
}
private static function formatTableName($table) {
$table = str_replace('`', '', $table);
if (strpos($table, '.')) {
@@ -133,7 +169,8 @@ class DB
$buildquery = "UPDATE " . self::formatTableName($table) . " SET ";
$keyval = array();
foreach ($params as $key => $value) {
$keyval[] = "`" . $key . "`=" . (is_int($value) ? $value : "'" . DB::escape($value) . "'");
$value = DB::sanitize($value);
$keyval[] = "`" . $key . "`=" . $value;
}
$buildquery = "UPDATE " . self::formatTableName($table) . " SET " . implode(', ', $keyval) . " WHERE " . $where;
@@ -141,27 +178,96 @@ class DB
call_user_func_array('DB::queryNull', $args);
}
public static function insertOrReplace($which, $table, $data) {
$data = unserialize(serialize($data)); // break references within array
$keys_str = implode(', ', DB::wrapStr(array_keys($data), '`'));
public static function insertOrReplace($which, $table, $datas, $options=array()) {
$datas = unserialize(serialize($datas)); // break references within array
$keys = null;
foreach ($data as &$datum) {
if (is_array($datum)) $datum = serialize($datum);
$datum = "'" . DB::escape($datum) . "'";
if (isset($datas[0]) && is_array($datas[0])) {
$many = true;
} else {
$datas = array($datas);
$many = false;
}
foreach ($datas as $data) {
if (! $keys) {
$keys = array_keys($data);
if ($many) sort($keys);
}
$insert_values = array();
foreach ($keys as $key) {
if ($many && !isset($data[$key])) DB::nonSQLError('insert/replace many: each assoc array must have the same keys!');
$datum = $data[$key];
$datum = DB::sanitize($datum);
$insert_values[] = $datum;
}
$values[] = '(' . implode(', ', $insert_values) . ')';
}
$values_str = implode(', ', array_values($data));
$table = self::formatTableName($table);
$keys_str = implode(', ', DB::wrapStr($keys, '`'));
$values_str = implode(',', $values);
DB::queryNull("$which INTO $table ($keys_str) VALUES ($values_str)");
if (isset($options['ignore']) && $options['ignore'] && strtolower($which) == 'insert') {
DB::queryNull("INSERT IGNORE INTO $table ($keys_str) VALUES $values_str");
} else if (isset($options['update']) && $options['update'] && strtolower($which) == 'insert') {
DB::queryNull("INSERT INTO $table ($keys_str) VALUES $values_str ON DUPLICATE KEY UPDATE {$options['update']}");
} else {
DB::queryNull("$which INTO $table ($keys_str) VALUES $values_str");
}
}
public static function insert($table, $data) {
return DB::insertOrReplace('INSERT', $table, $data);
public static function insert($table, $data) { return DB::insertOrReplace('INSERT', $table, $data); }
public static function insertIgnore($table, $data) { return DB::insertOrReplace('INSERT', $table, $data, array('ignore' => true)); }
public static function replace($table, $data) { return DB::insertOrReplace('REPLACE', $table, $data); }
public static function insertUpdate() {
$args = func_get_args();
$table = array_shift($args);
$data = array_shift($args);
if (! isset($args[0])) { // update will have all the data of the insert
if (isset($data[0]) && is_array($data[0])) { //multiple insert rows specified -- failing!
DB::nonSQLError("Badly formatted insertUpdate() query -- you didn't specify the update component!");
}
$args[0] = $data;
}
if (is_array($args[0])) {
$keyval = array();
foreach ($args[0] as $key => $value) {
$value = DB::sanitize($value);
$keyval[] = "`" . $key . "`=" . $value;
}
$updatestr = implode(', ', $keyval);
} else {
$updatestr = call_user_func_array('DB::parseQueryParams', $args);
}
return DB::insertOrReplace('INSERT', $table, $data, array('update' => $updatestr));
}
public static function replace($table, $data) {
return DB::insertOrReplace('REPLACE', $table, $data);
public static function delete() {
$args = func_get_args();
$table = self::formatTableName(array_shift($args));
$where = array_shift($args);
$buildquery = "DELETE FROM $table WHERE $where";
array_unshift($args, $buildquery);
call_user_func_array('DB::queryNull', $args);
}
public static function sqleval() {
$args = func_get_args();
$text = call_user_func_array('DB::parseQueryParams', $args);
return new MeekroDBEval($text);
}
public static function columnList($table) {
@@ -170,15 +276,9 @@ class DB
public static function tableList($db = null) {
if ($db) DB::useDB($db);
$db = DB::$current_db;
return DB::queryOneColumn('Tables_in_' . $db, "SHOW TABLES");
}
private static function checkUseDB() {
if (DB::$current_db_limit > 0) {
DB::$current_db_limit -= 1;
if (DB::$current_db_limit == 0) DB::useDB(DB::$old_db);
}
$result = DB::queryFirstColumn('SHOW TABLES');
if ($db && DB::$old_db) DB::useDB(DB::$old_db);
return $result;
}
public static function parseQueryParamsOld() {
@@ -190,37 +290,36 @@ class DB
foreach ($args as $arg) {
$type = array_shift($types);
$pos = strpos($sql, '?');
if ($pos === false) die("Badly formatted SQL query: $sql");
if ($pos === false) DB::nonSQLError("Badly formatted SQL query: $sql");
if ($type == 's') $replacement = "'" . DB::escape($arg) . "'";
else if ($type == 'i') $replacement = intval($arg);
else die("Badly formatted SQL query: $sql");
else DB::nonSQLError("Badly formatted SQL query: $sql");
$sql = substr_replace($sql, $replacement, $pos, 1);
}
return $sql;
}
/*
%s = string
%i = integer
%d = decimal / double
%b = backtick
%l = literal
%ls = list of strings
%li = list of integers
%ld = list of doubles
%ll = list of literals
%lb = list of backticks
*/
public static function parseQueryParamsNew() {
$args = func_get_args();
$sql = array_shift($args);
$posList = array();
$pos_adj = 0;
$types = array('%ll', '%ls', '%l', '%li', '%ld', '%lb', '%s', '%i', '%d', '%b', '%ss');
$param_char_length = strlen(DB::$param_char);
$types = array(
DB::$param_char . 'll', // list of literals
DB::$param_char . 'ls', // list of strings
DB::$param_char . 'l', // literal
DB::$param_char . 'li', // list of integers
DB::$param_char . 'ld', // list of decimals
DB::$param_char . 'lb', // list of backticks
DB::$param_char . 's', // string
DB::$param_char . 'i', // integer
DB::$param_char . 'd', // double / decimal
DB::$param_char . 'b', // backtick
DB::$param_char . 'ss' // search string (like string, surrounded with %'s)
);
foreach ($types as $type) {
$lastPos = 0;
@@ -235,27 +334,26 @@ class DB
foreach ($posList as $pos => $type) {
$arg = array_shift($args);
$type = substr($type, $param_char_length);
$length_type = strlen($type) + $param_char_length;
if (in_array($type, array('%s', '%i', '%d', '%b', '%l'))) {
if (in_array($type, array('s', 'i', 'd', 'b', 'l'))) {
$array_type = false;
$arg = array($arg);
$length_type = strlen($type);
$type = '%l' . substr($type, 1);
} else if ($type == '%ss') {
$type = 'l' . $type;
} else if ($type == 'ss') {
$result = "'%" . DB::escape(str_replace(array('%', '_'), array('\%', '\_'), $arg)) . "%'";
$length_type = strlen($type);
} else {
$array_type = true;
$length_type = strlen($type);
if (! is_array($arg)) die("Badly formatted SQL query: $sql -- expecting array, but didn't get one!");
if (! is_array($arg)) DB::nonSQLError("Badly formatted SQL query: $sql -- expecting array, but didn't get one!");
}
if ($type == '%ls') $result = DB::wrapStr($arg, "'", true);
else if ($type == '%li') $result = array_map('intval', $arg);
else if ($type == '%ld') $result = array_map('floatval', $arg);
else if ($type == '%lb') $result = array_map('DB::formatTableName', $arg);
else if ($type == '%ll') $result = $arg;
else if (! $result) die("Badly formatted SQL query: $sql");
if ($type == 'ls') $result = DB::wrapStr($arg, "'", true);
else if ($type == 'li') $result = array_map('intval', $arg);
else if ($type == 'ld') $result = array_map('floatval', $arg);
else if ($type == 'lb') $result = array_map('DB::formatTableName', $arg);
else if ($type == 'll') $result = $arg;
else if (! $result) DB::nonSQLError("Badly formatted SQL query: $sql");
if (is_array($result)) {
if (! $array_type) $result = $result[0];
@@ -290,13 +388,16 @@ class DB
}
public static function queryNull() { $args = func_get_args(); return DB::prependCall('DB::queryHelper', $args, 'null'); }
public static function queryRaw() { $args = func_get_args(); return DB::prependCall('DB::queryHelper', $args, 'buffered'); }
public static function queryBuf() { $args = func_get_args(); return DB::prependCall('DB::queryHelper', $args, 'buffered'); }
public static function queryUnbuf() { $args = func_get_args(); return DB::prependCall('DB::queryHelper', $args, 'unbuffered'); }
public static function queryHelper() {
$args = func_get_args();
$type = array_shift($args);
if ($type != 'buffered' && $type != 'unbuffered' && $type != 'null') die("Error -- first argument to queryHelper must be buffered or unbuffered!");
if ($type != 'buffered' && $type != 'unbuffered' && $type != 'null') {
DB::nonSQLError('Error -- first argument to queryHelper must be buffered or unbuffered!');
}
$is_buffered = ($type == 'buffered');
$is_null = ($type == 'null');
@@ -309,8 +410,11 @@ class DB
if (DB::$success_handler) $runtime = microtime(true) - $starttime;
if (!$sql || $error = DB::checkError()) {
if (function_exists(DB::$error_handler)) {
call_user_func(DB::$error_handler, array(
if (DB::$error_handler) {
$error_handler = is_callable(DB::$error_handler) ? DB::$error_handler : 'meekrodb_error_handler';
call_user_func($error_handler, array(
'type' => 'sql',
'query' => $sql,
'error' => $error
));
@@ -322,7 +426,7 @@ class DB
}
} else if (DB::$success_handler) {
$runtime = sprintf('%f', $runtime * 1000);
$success_handler = function_exists(DB::$success_handler) ? DB::$success_handler : 'meekrodb_debugmode_handler';
$success_handler = is_callable(DB::$success_handler) ? DB::$success_handler : 'meekrodb_debugmode_handler';
call_user_func($success_handler, array(
'query' => $sql,
@@ -338,9 +442,6 @@ class DB
if ($is_buffered) DB::$num_rows = $result->num_rows;
else DB::$num_rows = null;
//TODO: fix DB switch back
//DB::checkUseDB();
if ($is_null) {
DB::freeResult($result);
DB::$queryResult = DB::$queryResultType = null;
@@ -494,7 +595,9 @@ class WhereClause {
public $clauses = array();
function __construct($type) {
$this->type = strtolower($type);
$type = strtolower($type);
if ($type != 'or' && $type != 'and') DB::nonSQLError('you must use either WhereClause(and) or WhereClause(or)');
$this->type = $type;
}
function add() {
@@ -511,7 +614,13 @@ class WhereClause {
function negateLast() {
$i = count($this->clauses) - 1;
$this->clauses[$i] = 'NOT (' . $this->clauses[$i] . ')';
if (!isset($this->clauses[$i])) return;
if ($this->clauses[$i] instanceof WhereClause) {
$this->clauses[$i]->negate();
} else {
$this->clauses[$i] = 'NOT (' . $this->clauses[$i] . ')';
}
}
function negate() {
@@ -528,11 +637,8 @@ class WhereClause {
return count($this->clauses);
}
function text($minimal = false) {
if (count($this->clauses) == 0) {
if ($minimal) return '(1)';
else return '';
}
function text() {
if (count($this->clauses) == 0) return '(1)';
$A = array();
foreach ($this->clauses as $clause) {
@@ -578,8 +684,8 @@ class MeekroDBException extends Exception {
}
function meekrodb_error_handler($params) {
$out[] = "QUERY: " . $params['query'];
$out[] = "ERROR: " . $params['error'];
if (isset($params['query'])) $out[] = "QUERY: " . $params['query'];
if (isset($params['error'])) $out[] = "ERROR: " . $params['error'];
$out[] = "";
if (php_sapi_name() == 'cli' && empty($_SERVER['REMOTE_ADDR'])) {
@@ -602,4 +708,12 @@ function meekrodb_debugmode_handler($params) {
}
}
class MeekroDBEval {
public $text = '';
function __construct($text) {
$this->text = $text;
}
}
?>

View File

@@ -1,26 +1,9 @@
<?php
function new_error_callback($params) {
global $error_callback_worked;
if (substr_count($params['error'], 'You have an error in your SQL syntax')) $error_callback_worked = 1;
}
function my_debug_handler($params) {
global $debug_callback_worked;
if (substr_count($params['query'], 'SELECT')) $debug_callback_worked = 1;
}
class BasicTest extends SimpleTest {
function __construct() {
error_reporting(E_ALL);
require_once '../db.class.php';
DB::$user = 'libdb_user';
DB::$password = 'sdf235sklj';
DB::$dbName = 'libdb_test';
DB::query("DROP DATABASE libdb_test");
DB::query("CREATE DATABASE libdb_test");
DB::useDB('libdb_test');
foreach (DB::tableList() as $table) {
DB::query("DROP TABLE $table");
}
}
@@ -30,7 +13,8 @@ class BasicTest extends SimpleTest {
`username` VARCHAR( 255 ) NOT NULL ,
`password` VARCHAR( 255 ) NOT NULL ,
`age` INT NOT NULL DEFAULT '10',
`height` DOUBLE NOT NULL DEFAULT '10.0'
`height` DOUBLE NOT NULL DEFAULT '10.0',
`favorite_word` VARCHAR( 255 ) NULL DEFAULT 'hi'
) ENGINE = InnoDB");
}
@@ -73,12 +57,13 @@ class BasicTest extends SimpleTest {
'age' => 15,
'height' => 10.371
));
DB::insert('`libdb_test`.`accounts`', array(
$dbname = DB::$dbName;
DB::insert("`$dbname`.`accounts`", array(
'username' => 'Charlie\'s Friend',
'password' => 'goodbye',
'age' => 30,
'height' => 155.23
'height' => 155.23,
'favorite_word' => null,
));
$this->assert(DB::insertId() === 3);
@@ -86,9 +71,14 @@ class BasicTest extends SimpleTest {
$counter = DB::queryFirstField("SELECT COUNT(*) FROM accounts");
$this->assert($counter === strval(3));
$bart = DB::queryFirstRow("SELECT * FROM accounts WHERE age IN %li AND height IN %ld AND username IN %ls",
$password = DB::queryFirstField("SELECT password FROM accounts WHERE favorite_word IS NULL");
$this->assert($password === 'goodbye');
DB::$param_char = '###';
$bart = DB::queryFirstRow("SELECT * FROM accounts WHERE age IN ###li AND height IN ###ld AND username IN ###ls",
array(15, 25), array(10.371, 150.123), array('Bart', 'Barts'));
$this->assert($bart['username'] === 'Bart');
DB::$param_char = '%';
$charlie_password = DB::queryFirstField("SELECT password FROM accounts WHERE username IN %ls AND username = %s",
array('Charlie', 'Charlie\'s Friend'), 'Charlie\'s Friend');
@@ -107,6 +97,12 @@ class BasicTest extends SimpleTest {
$this->assert($username === 'Bart');
$this->assert($password === 'hello');
$this->assert($age == 15);
$mysqli_result = DB::queryRaw("SELECT * FROM accounts WHERE favorite_word IS NULL");
$this->assert($mysqli_result instanceof MySQLi_Result);
$row = $mysqli_result->fetch_assoc();
$this->assert($row['password'] === 'goodbye');
$this->assert($mysqli_result->fetch_assoc() === null);
}
function test_4_query() {
@@ -116,52 +112,194 @@ class BasicTest extends SimpleTest {
$results = DB::query("SELECT * FROM accounts WHERE username!=%s", "Charlie's Friend");
$this->assert(count($results) === 2);
$columnlist = DB::columnList('accounts');
$this->assert(count($columnlist) === 6);
$this->assert($columnlist[0] === 'id');
$this->assert($columnlist[4] === 'height');
$tablelist = DB::tableList();
$this->assert(count($tablelist) === 1);
$this->assert($tablelist[0] === 'accounts');
$tablelist = null;
$tablelist = DB::tableList(DB::$dbName);
$this->assert(count($tablelist) === 1);
$this->assert($tablelist[0] === 'accounts');
}
function test_5_error_handler() {
global $error_callback_worked;
function test_4_1_query() {
DB::insert('accounts', array(
'username' => 'newguy',
'password' => DB::sqleval("REPEAT('blah', %i)", '3'),
'age' => DB::sqleval('171+1'),
'height' => 111.15
));
DB::$error_handler = 'new_error_callback';
DB::query("SELET * FROM accounts");
$this->assert($error_callback_worked === 1);
$row = DB::queryOneRow("SELECT * FROM accounts WHERE password=%s", 'blahblahblah');
$this->assert($row['username'] === 'newguy');
$this->assert($row['age'] === '172');
DB::update('accounts', array(
'password' => DB::sqleval("REPEAT('blah', %i)", 4),
'favorite_word' => null,
), 'username=%s', 'newguy');
$row = null;
$row = DB::queryOneRow("SELECT * FROM accounts WHERE username=%s", 'newguy');
$this->assert($row['password'] === 'blahblahblahblah');
$this->assert($row['favorite_word'] === null);
DB::query("DELETE FROM accounts WHERE password=%s", 'blahblahblahblah');
$this->assert(DB::affectedRows() === 1);
}
function test_6_exception_catch() {
DB::$error_handler = '';
DB::$throw_exception_on_error = true;
try {
DB::query("SELET * FROM accounts");
} catch(MeekroDBException $e) {
$this->assert(substr_count($e->getMessage(), 'You have an error in your SQL syntax'));
$this->assert($e->getQuery() === 'SELET * FROM accounts');
$exception_was_caught = 1;
}
$this->assert($exception_was_caught === 1);
function test_4_2_delete() {
DB::insert('accounts', array(
'username' => 'gonesoon',
'password' => 'something',
'age' => 61,
'height' => 199.194
));
try {
DB::insert('`libdb_test`.`accounts`', array(
'id' => 2,
'username' => 'Another Dude\'s \'Mom"',
'password' => 'asdfsdse',
'age' => 35,
'height' => 555.23
));
} catch(MeekroDBException $e) {
$this->assert(substr_count($e->getMessage(), 'Duplicate entry'));
$exception_was_caught = 2;
}
$this->assert($exception_was_caught === 2);
$ct = DB::queryFirstField("SELECT COUNT(*) FROM accounts WHERE username=%s AND height=%d", 'gonesoon', 199.194);
$this->assert(intval($ct) === 1);
DB::delete('accounts', 'username=%s AND age=%i AND height=%d', 'gonesoon', '61', '199.194');
$this->assert(DB::affectedRows() === 1);
$ct = DB::queryFirstField("SELECT COUNT(*) FROM accounts WHERE username=%s AND height=%d", 'gonesoon', '199.194');
$this->assert(intval($ct) === 0);
}
function test_7_debugmode_handler() {
global $debug_callback_worked;
function test_4_3_insertmany() {
$ins[] = array(
'username' => '1ofmany',
'password' => 'something',
'age' => 23,
'height' => 190.194
);
$ins[] = array(
'password' => 'somethingelse',
'username' => '2ofmany',
'age' => 25,
'height' => 190.194
);
DB::debugMode('my_debug_handler');
DB::query("SELECT * FROM accounts WHERE username!=%s", "Charlie's Friend");
DB::insert('accounts', $ins);
$this->assert(DB::affectedRows() === 2);
$this->assert($debug_callback_worked === 1);
$rows = DB::query("SELECT * FROM accounts WHERE height=%d ORDER BY age ASC", 190.194);
$this->assert(count($rows) === 2);
$this->assert($rows[0]['username'] === '1ofmany');
$this->assert($rows[0]['age'] === '23');
$this->assert($rows[1]['age'] === '25');
$this->assert($rows[1]['password'] === 'somethingelse');
$this->assert($rows[1]['username'] === '2ofmany');
DB::debugMode(false);
}
function test_5_insert_blobs() {
DB::query("CREATE TABLE `storedata` (
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`picture` BLOB
) ENGINE = InnoDB");
$smile = file_get_contents('smile1.jpg');
DB::insert('storedata', array(
'picture' => $smile,
));
DB::query("INSERT INTO storedata (picture) VALUES (%s)", $smile);
DB::query("INSERT INTO storedata (picture) VALUES (?)", 's', $smile);
$getsmile = DB::queryFirstField("SELECT picture FROM storedata WHERE id=1");
$getsmile2 = DB::queryFirstField("SELECT picture FROM storedata WHERE id=2");
$getsmile3 = DB::queryFirstField("SELECT picture FROM storedata WHERE id=3");
$this->assert($smile === $getsmile);
$this->assert($smile === $getsmile2);
$this->assert($smile === $getsmile3);
}
function test_6_insert_ignore() {
DB::insertIgnore('accounts', array(
'id' => 1, //duplicate primary key
'username' => 'gonesoon',
'password' => 'something',
'age' => 61,
'height' => 199.194
));
}
function test_7_insert_update() {
DB::insertUpdate('accounts', array(
'id' => 2, //duplicate primary key
'username' => 'gonesoon',
'password' => 'something',
'age' => 61,
'height' => 199.194
), 'age = age + %i', 1);
$this->assert(DB::affectedRows() === 2); // a quirk of MySQL, even though only 1 row was updated
$result = DB::query("SELECT * FROM accounts WHERE age = %i", 16);
$this->assert(count($result) === 1);
$this->assert($result[0]['height'] === '10.371');
DB::insertUpdate('accounts', array(
'id' => 2, //duplicate primary key
'username' => 'blahblahdude',
'age' => 233,
'height' => 199.194
));
$result = DB::query("SELECT * FROM accounts WHERE age = %i", 233);
$this->assert(count($result) === 1);
$this->assert($result[0]['height'] === '199.194');
$this->assert($result[0]['username'] === 'blahblahdude');
DB::insertUpdate('accounts', array(
'id' => 2, //duplicate primary key
'username' => 'gonesoon',
'password' => 'something',
'age' => 61,
'height' => 199.194
), array(
'age' => 74,
));
$result = DB::query("SELECT * FROM accounts WHERE age = %i", 74);
$this->assert(count($result) === 1);
$this->assert($result[0]['height'] === '199.194');
$this->assert($result[0]['username'] === 'blahblahdude');
$multiples[] = array(
'id' => 3, //duplicate primary key
'username' => 'gonesoon',
'password' => 'something',
'age' => 61,
'height' => 199.194
);
$multiples[] = array(
'id' => 1, //duplicate primary key
'username' => 'gonesoon',
'password' => 'something',
'age' => 61,
'height' => 199.194
);
DB::insertUpdate('accounts', $multiples, array('age' => 914));
$this->assert(DB::affectedRows() === 4);
$result = DB::query("SELECT * FROM accounts WHERE age=914 ORDER BY id ASC");
$this->assert(count($result) === 2);
$this->assert($result[0]['username'] === 'Abe');
$this->assert($result[1]['username'] === 'Charlie\'s Friend');
DB::query("UPDATE accounts SET age=15, username='Bart' WHERE age=%i", 74);
$this->assert(DB::affectedRows() === 1);
}
}

83
simpletest/ErrorTest.php Normal file
View File

@@ -0,0 +1,83 @@
<?
function new_error_callback($params) {
global $error_callback_worked;
if (substr_count($params['error'], 'You have an error in your SQL syntax')) $error_callback_worked = 1;
}
function my_debug_handler($params) {
global $debug_callback_worked;
if (substr_count($params['query'], 'SELECT')) $debug_callback_worked = 1;
}
class ErrorTest extends SimpleTest {
function test_1_error_handler() {
global $error_callback_worked, $static_error_callback_worked, $nonstatic_error_callback_worked;
DB::$error_handler = 'new_error_callback';
DB::query("SELET * FROM accounts");
$this->assert($error_callback_worked === 1);
DB::$error_handler = array('ErrorTest', 'static_error_callback');
DB::query("SELET * FROM accounts");
$this->assert($static_error_callback_worked === 1);
DB::$error_handler = array($this, 'nonstatic_error_callback');
DB::query("SELET * FROM accounts");
$this->assert($nonstatic_error_callback_worked === 1);
}
public static function static_error_callback($params) {
global $static_error_callback_worked;
if (substr_count($params['error'], 'You have an error in your SQL syntax')) $static_error_callback_worked = 1;
}
public function nonstatic_error_callback($params) {
global $nonstatic_error_callback_worked;
if (substr_count($params['error'], 'You have an error in your SQL syntax')) $nonstatic_error_callback_worked = 1;
}
function test_2_exception_catch() {
$dbname = DB::$dbName;
DB::$error_handler = '';
DB::$throw_exception_on_error = true;
try {
DB::query("SELET * FROM accounts");
} catch(MeekroDBException $e) {
$this->assert(substr_count($e->getMessage(), 'You have an error in your SQL syntax'));
$this->assert($e->getQuery() === 'SELET * FROM accounts');
$exception_was_caught = 1;
}
$this->assert($exception_was_caught === 1);
try {
DB::insert("`$dbname`.`accounts`", array(
'id' => 2,
'username' => 'Another Dude\'s \'Mom"',
'password' => 'asdfsdse',
'age' => 35,
'height' => 555.23
));
} catch(MeekroDBException $e) {
$this->assert(substr_count($e->getMessage(), 'Duplicate entry'));
$exception_was_caught = 2;
}
$this->assert($exception_was_caught === 2);
}
function test_3_debugmode_handler() {
global $debug_callback_worked;
DB::debugMode('my_debug_handler');
DB::query("SELECT * FROM accounts WHERE username!=%s", "Charlie's Friend");
$this->assert($debug_callback_worked === 1);
DB::debugMode(false);
}
}
?>

View File

@@ -0,0 +1,19 @@
<?
class ErrorTest_53 extends SimpleTest {
function test_1_error_handler() {
global $anonymous_error_callback_worked;
DB::$throw_exception_on_error = false;
DB::$error_handler = function($params) {
global $anonymous_error_callback_worked;
if (substr_count($params['error'], 'You have an error in your SQL syntax')) $anonymous_error_callback_worked = 1;
};
DB::query("SELET * FROM accounts");
$this->assert($anonymous_error_callback_worked === 1);
}
}
?>

View File

@@ -0,0 +1,64 @@
<?
class WhereClauseTest extends SimpleTest {
function test_1_basic_where() {
$where = new WhereClause('and');
$where->add('username=%s', 'Bart');
$where->add('password=%s', 'hello');
$result = DB::query("SELECT * FROM accounts WHERE %l", $where->text());
$this->assert(count($result) === 1);
$this->assert($result[0]['age'] === '15');
}
function test_2_simple_grouping() {
$where = new WhereClause('and');
$where->add('password=%s', 'hello');
$subclause = $where->addClause('or');
$subclause->add('age=%i', 15);
$subclause->add('age=%i', 14);
$result = DB::query("SELECT * FROM accounts WHERE %l", $where->text());
$this->assert(count($result) === 1);
$this->assert($result[0]['age'] === '15');
}
function test_3_negate_last() {
$where = new WhereClause('and');
$where->add('password=%s', 'hello');
$subclause = $where->addClause('or');
$subclause->add('username!=%s', 'Bart');
$subclause->negateLast();
$result = DB::query("SELECT * FROM accounts WHERE %l", $where->text());
$this->assert(count($result) === 1);
$this->assert($result[0]['age'] === '15');
}
function test_4_negate_last_query() {
$where = new WhereClause('and');
$where->add('password=%s', 'hello');
$subclause = $where->addClause('or');
$subclause->add('username!=%s', 'Bart');
$where->negateLast();
$result = DB::query("SELECT * FROM accounts WHERE %l", $where->text());
$this->assert(count($result) === 1);
$this->assert($result[0]['age'] === '15');
}
function test_5_negate() {
$where = new WhereClause('and');
$where->add('password=%s', 'hello');
$subclause = $where->addClause('or');
$subclause->add('username!=%s', 'Bart');
$subclause->negate();
$result = DB::query("SELECT * FROM accounts WHERE %l", $where->text());
$this->assert(count($result) === 1);
$this->assert($result[0]['age'] === '15');
}
}
?>

BIN
simpletest/smile1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

View File

@@ -11,44 +11,41 @@ class SimpleTest {
die;
}
public static function __listfiles($dir, $regex, $type='files', $rec = false) {
$A = array();
if (! $dir_handler = @opendir($dir)) return $A;
while (false !== ($filename = @readdir($dir_handler))) {
if ($filename == '.' || $filename == '..') continue;
if ($rec && is_dir("$dir/$filename")) $A = array_merge($A, File::listfiles("$dir/$filename", $regex, $type, true));
if (! preg_match($regex, $filename)) continue;
if ($type == 'files' && ! is_file("$dir/$filename")) continue;
if ($type == 'dirs' && ! is_dir("$dir/$filename")) continue;
if ($type == 'symlinks' && ! is_link("$dir/$filename")) continue;
$A[] = $dir . DIRECTORY_SEPARATOR . $filename;
}
return $A;
}
}
$files = SimpleTest::__listfiles(dirname(__FILE__), '/^.*php$/i');
if (phpversion() >= '5.3') $is_php_53 = true;
else $is_php_53 = false;
$classes_to_test = array();
foreach ($files as $fullpath) {
$filename = basename($fullpath);
if ($fullpath == __FILE__) continue;
require_once($fullpath);
$classes_to_test[] = str_replace('.php', '', $filename);
error_reporting(E_ALL);
require_once '../db.class.php';
DB::$user = 'meekrodb_test_us';
include 'test_setup.php'; //test config values go here
DB::$password = $set_password;
DB::$dbName = $set_db;
DB::$host = $set_host;
require_once 'BasicTest.php';
require_once 'WhereClauseTest.php';
require_once 'ErrorTest.php';
$classes_to_test = array(
'BasicTest',
'WhereClauseTest',
'ErrorTest',
);
if ($is_php_53) {
require_once 'ErrorTest_53.php';
$classes_to_test[] = 'ErrorTest_53';
}
foreach ($classes_to_test as $class) {
$object = new $class();
foreach (get_class_methods($object) as $method) {
if (substr($method, 0, 2) == '__') continue;
if (substr($method, 0, 4) != 'test') continue;
echo "Running $class::$method..\n";
$object->$method();
}