diff --git a/dibi/dibi.php b/dibi/dibi.php index 35f90b13..b7365ac3 100644 --- a/dibi/dibi.php +++ b/dibi/dibi.php @@ -14,7 +14,7 @@ * @license GNU GENERAL PUBLIC LICENSE * @package dibi * @category Database - * @version 0.5b $Revision$ $Date$ + * @version 0.6 $Revision$ $Date$ */ @@ -31,10 +31,12 @@ require_once dirname(__FILE__).'/libs/resultset.php'; require_once dirname(__FILE__).'/libs/parser.php'; require_once dirname(__FILE__).'/libs/exception.php'; -// support -require_once dirname(__FILE__).'/libs/date.type.demo.php'; +// required since PHP 5.1.0 +if (function_exists('date_default_timezone_set')) + date_default_timezone_set('Europe/Prague'); // or 'GMT' + /** @@ -374,7 +376,7 @@ class dibi $sql = preg_replace('#\*\*.+?\*\*#', '$0', $sql); - echo '
', $sql, ''; + echo '
', $sql, ''; } diff --git a/dibi/libs/date.type.demo.php b/dibi/libs/date.type.demo.php deleted file mode 100644 index f43bed70..00000000 --- a/dibi/libs/date.type.demo.php +++ /dev/null @@ -1,101 +0,0 @@ - - * @link http://texy.info/dibi/ - * @copyright Copyright (c) 2005-2006 David Grudl - * @license GNU GENERAL PUBLIC LICENSE - * @package dibi - * @category Database - * @version $Revision$ $Date$ - */ - - -// security - include dibi.php, not this file -if (!defined('DIBI')) die(); - - -// required since PHP 5.1.0 -// todo: -if (function_exists('date_default_timezone_set')) - date_default_timezone_set('Europe/Prague'); // or 'GMT' - - - -/** - * Pseudotype for UNIX timestamp representation - */ -class TDate implements IDibiVariable -{ - /** - * Unix timestamp - * @var int - */ - protected $time; - - - - public function __construct($time = NULL) - { - if ($time === NULL) - $this->time = time(); // current time - - elseif (is_string($time)) - $this->time = strtotime($time); // try convert to timestamp - - else - $this->time = (int) $time; - } - - - - /** - * Format for SQL - * - * @param object destination DibiDriver - * @param string optional modifier - * @return string - */ - public function toSQL($driver, $modifier = NULL) - { - return date( - $driver->formats['date'], // format according to driver's spec. - $this->time - ); - } - - - - public function getTimeStamp() - { - return $this->time; - } - - -} - - - - -/** - * Pseudotype for datetime representation - */ -class TDateTime extends TDate -{ - - public function toSQL($driver, $modifier = NULL) - { - return date( - $driver->formats['datetime'], // format according to driver's spec. - $this->time - ); - } - -} - -?> \ No newline at end of file diff --git a/dibi/libs/exception.php b/dibi/libs/exception.php index 5c6806af..d576206a 100644 --- a/dibi/libs/exception.php +++ b/dibi/libs/exception.php @@ -58,6 +58,9 @@ class DibiException extends Exception +/** + * Checks result state + */ function is_error($var) { return ($var === FALSE) || ($var instanceof Exception); diff --git a/dibi/libs/parser.php b/dibi/libs/parser.php index fc42ae5c..33cdb195 100644 --- a/dibi/libs/parser.php +++ b/dibi/libs/parser.php @@ -43,133 +43,21 @@ class DibiParser { $sql = ''; $this->driver = $driver; - $this->modifier = 0; + $this->modifier = false; $this->hasError = false; $command = null; - $lastString = null; + //$lastString = null; foreach ($args as $index => $arg) { $sql .= ' '; // always add simple space - - // array processing (with or without modifier) - if (is_array($arg)) { - // determine type: set | values | list - if ($this->modifier) { - $type = $this->modifier; - $this->modifier = false; - } else { - // autodetect - if (is_int(key($arg))) - $type = 'L'; // LIST - else { - if (!$command) - $command = strtoupper(substr(ltrim($args[0]), 0, 6)); - - $type = $command == 'UPDATE' ? 'S' : 'V'; // SET | VALUES - } - } - - // build array - $vx = $kx = array(); - switch ($type) { - case 'S': // SET - foreach ($arg as $k => $v) - $vx[] = $this->driver->quoteName($k) . '=' . $this->formatValue($v); - - $sql .= implode(', ', $vx); - break; - - case 'V': // VALUES - foreach ($arg as $k => $v) { - $kx[] = $this->driver->quoteName($k); - $vx[] = $this->formatValue($v); - } - - $sql .= '(' . implode(', ', $kx) . ') VALUES (' . implode(', ', $vx) . ')'; - break; - - case 'L': // LIST - foreach ($arg as $k => $v) - $vx[] = $this->formatValue($v); - - $sql .= implode(', ', $vx); - break; - - case 'N': // NAMES - foreach ($arg as $v) - $vx[] = $this->driver->quoteName($v); - - $sql .= implode(', ', $vx); - break; - - default: - $this->hasError = true; - $sql .= "**Unknown modifier %$type**"; - } - - continue; - } - - - - // after-modifier procession - if ($this->modifier) { - if ($arg instanceof IDibiVariable) { - $sql .= $arg->toSql($this->driver, $this->modifier); - $this->modifier = false; - continue; - } - - if (!is_scalar($arg) && !is_null($arg)) { // array is already processed - $this->hasError = true; - $this->modifier = false; - $sql .= '**Unexpected '.gettype($arg).'**'; - continue; - } - - switch ($this->modifier) { - case "s": // string - $sql .= $this->driver->escape($arg, TRUE); - break; - case 'T': // date - $sql .= date($this->driver->formats['date'], is_string($arg) ? strtotime($arg) : $arg); - break; - case 't': // datetime - $sql .= date($this->driver->formats['datetime'], is_string($arg) ? strtotime($arg) : $arg); - break; - case 'b': // boolean - $sql .= $arg ? $this->driver->formats['TRUE'] : $this->driver->formats['FALSE']; - break; - case 'i': - case 'u': // unsigned int - case 'd': // signed int - $sql .= (string) (int) $arg; - break; - case 'f': // float - $sql .= (string) (float) $arg; // something like -9E-005 is accepted by SQL - break; - case 'n': // identifier name - $sql .= $this->driver->quoteName($arg); - break; - default: - $this->hasError = true; - $sql .= "**Unknown modifier %$this->modifier**"; - } - - $this->modifier = false; - continue; - } - - // simple string means SQL - if (is_string($arg)) { + if (is_string($arg) && !$this->modifier) { // double string warning // (problematic with dibi::queryStart & dibi::queryAdd // if ($lastString === $index-1) // trigger_error("Is seems there is error in SQL near '$arg'.", E_USER_WARNING); - - $lastString = $index; +// $lastString = $index; // speed-up - is regexp required? $toSkip = strcspn($arg, '`[\'"%'); @@ -196,10 +84,17 @@ class DibiParser continue; } + // array processing without modifier - autoselect between SET or VALUES + if (is_array($arg) && !$this->modifier && is_string(key($arg))) { + if (!$command) + $command = strtoupper(substr(ltrim($args[0]), 0, 6)); + + $this->modifier = ($command == 'INSERT' || $command == 'REPLAC') ? 'V' : 'S'; + } // default processing - $sql .= $this->formatValue($arg); - + $sql .= $this->formatValue($arg, $this->modifier); + $this->modifier = false; } // for @@ -214,8 +109,77 @@ class DibiParser - private function formatValue($value) + private function formatValue($value, $modifier) { + // array processing (with or without modifier) + if (is_array($value)) { + + $vx = $kx = array(); + switch ($modifier) { + case 'S': // SET + foreach ($value as $k => $v) { + list($k, $mod) = explode('%', $k.'%', 3); // split modifier + $vx[] = $this->driver->quoteName($k) . '=' . $this->formatValue($v, $mod); + } + + return implode(', ', $vx); + + case 'V': // VALUES + foreach ($value as $k => $v) { + list($k, $mod) = explode('%', $k.'%', 3); // split modifier + $kx[] = $this->driver->quoteName($k); + $vx[] = $this->formatValue($v, $mod); + } + + return '(' . implode(', ', $kx) . ') VALUES (' . implode(', ', $vx) . ')'; + + default: // LIST + foreach ($value as $v) + $vx[] = $this->formatValue($v, $modifier); + + return implode(', ', $vx); + } + } + + + // with modifier procession + if ($modifier) { + if ($value instanceof IDibiVariable) + return $value->toSql($this->driver, $this->modifier); + + if (!is_scalar($value) && !is_null($value)) { // array is already processed + $this->hasError = true; + return '**Unexpected '.gettype($value).'**'; + } + + switch ($modifier) { + case "s": // string + return $this->driver->escape($value, TRUE); + case 'b': // boolean + return $value ? $this->driver->formats['TRUE'] : $this->driver->formats['FALSE']; + case 'i': + case 'u': // unsigned int + case 'd': // signed int + return (string) (int) $value; + case 'f': // float + return (string) (float) $value; // something like -9E-005 is accepted by SQL + case 'D': // date + return date($this->driver->formats['date'], is_string($value) ? strtotime($value) : $value); + case 'T': // datetime + return date($this->driver->formats['datetime'], is_string($value) ? strtotime($value) : $value); + case 'n': // identifier name + return $this->driver->quoteName($value); + case 'p': // preserve as SQL + return (string) $value; + default: + $this->hasError = true; + return "**Unknown modifier %$modifier**"; + } + } + + + + // without modifier procession if (is_string($value)) return $this->driver->escape($value, TRUE); @@ -232,7 +196,7 @@ class DibiParser return $value->toSql($this->driver); $this->hasError = true; - return '**Unsupported type '.gettype($value).'**'; + return '**Unexpected '.gettype($value).'**'; } diff --git a/dibi/libs/resultset.php b/dibi/libs/resultset.php index 4718b400..19825853 100644 --- a/dibi/libs/resultset.php +++ b/dibi/libs/resultset.php @@ -284,10 +284,10 @@ abstract class DibiResult implements IteratorAggregate, Countable } if ($type == self::FIELD_DATE) - return new TDate($value); // !!! experimental + return strtotime($value); // !!! not good if ($type == self::FIELD_DATETIME) - return new TDateTime($value); // !!! experimental + return strtotime($value); // !!! not good return $value; } diff --git a/examples/connect.php b/examples/connect.php index c5b9d22b..290b9a0b 100644 --- a/examples/connect.php +++ b/examples/connect.php @@ -2,38 +2,46 @@ require_once '../dibi/dibi.php'; -// use two connections: -// first connection to mysql + +// connects to mysql $state = dibi::connect(array( 'driver' => 'mysql', 'host' => 'localhost', 'username' => 'root', - 'password' => '***', + 'password' => 'xxx', // change to real password! 'database' => 'test', 'charset' => 'utf8', -), 1); +)); -if ($state instanceof Exception) { - echo $state; -} - -if (!dibi::isConnected()) { - die(); -} - - - -// second connection to odbc +/* connects to ODBC dibi::connect(array( 'driver' => 'odbc', 'username' => 'root', 'password' => '***', 'database' => 'Driver={Microsoft Access Driver (*.mdb)};Dbq=C:\\Database.mdb', -), 3); +)); +*/ -echo dibi::isConnected(); +// check status +if (!dibi::isConnected()) { + echo 'dibi::isConnected(): Not connected'; + echo "
'mysqli', 'host' => 'localhost', 'username' => 'root', - 'password' => '***', - 'database' => 'test', + 'password' => 'xxx', // change to real password! 'charset' => 'utf8', )); + $arr1 = array(1, 2, 3); $arr2 = array('one', 'two', 'three'); $arr3 = array( - 'a' => 'one', - 'b' => 'two', - 'c' => 'three', + 'col1' => 'one', + 'col2' => 'two', + 'col3' => 'three', ); $arr4 = array( - 'A' => 12, - 'B' => NULL, - 'C' => new TDateTime(31542), - 'D' => 'string', + 'a' => 12, + 'b' => NULL, + 'c%T' => time(), // modifier 'T' means datetime + 'd' => 'any string', ); +$arr5 = array('RAND()', 'ANY SQL'); -dibi::test( -" + +dibi::test(" SELECT * -FROM [test] -WHERE ([test.a] LIKE %T", '1995-03-01', " - OR [b1] IN (", $arr1, ") - OR [b2] IN (", $arr2, ") - OR [b3] IN (%N", $arr3, ") - OR [b4] IN %V", $arr4, " +FROM [db.table] +WHERE ([test.a] LIKE %D", '1995-03-01', " + OR [b1] IN (", $arr1, ") + OR [b2] IN (%s", $arr1, ") + OR [b3] IN (", $arr2, ") + OR [b4] IN (%n", $arr3, ") + OR [b4] IN (%p", $arr5, ") AND [c] = 'embedded '' string' OR [d]=%d", 10.3, " OR [true]=", true, " @@ -45,4 +50,17 @@ WHERE ([test.a] LIKE %T", '1995-03-01', " OR [null]=", NULL, " LIMIT 10"); + +// dibi detects INSERT or REPLACE command +dibi::test("INSERT INTO [test]", $arr4); + + +// dibi detects UPDATE command +$n = 123; +dibi::test("UPDATE [test] SET", $arr4, " WHERE [id]=%n", $n); + + +// array with modifier %d - means strings +dibi::test("UPDATE [test] SET%s", $arr4, " WHERE [id]=%n", $n); + ?> diff --git a/version.txt b/version.txt index 4123ea9a..af97075f 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -Dibi Version 0.5b +Dibi Version 0.6