.gitignore 0000644 00000000060 14476160707 0006544 0 ustar 00 /vendor/
/tests/
composer.lock
.vscode/
/src_1/
composer.json 0000644 00000000746 14476160707 0007311 0 ustar 00 {
"name": "boru/dhdb",
"type": "library",
"autoload": {
"psr-4": {
"boru\\dhdb\\": "src/"
}
},
"authors": [
{
"name": "Daniel Hayes",
"email": "dhayes@boruapps.com"
}
],
"require": {
"boru/dhutils": "*",
"greenlion/php-sql-parser": "^4.6"
},
"repositories": [
{
"type": "composer",
"url": "https://satis.boruapps.com"
}
]
}
instructions-composer.txt 0000644 00000000311 14476160707 0011705 0 ustar 00 {
"require": {
"boru/dhout": "dev-master"
},
"repositories": [
{
"type": "composer",
"url": "https://satis.boruapps.com"
}
]
} src/Parser.php 0000644 00000011616 14476160707 0007321 0 ustar 00 wrapper = new SQLParserWrapper();
if(!empty($options)) {
$this->setOptions($options);
}
if(!is_null($query)) {
$this->setQuery($query);
$this->parse();
}
}
public function setQuery($query) {
$this->query = $query;
$this->parse();
return $this;
}
public function setOptions($options=[],$merge=true) {
if($merge) {
$this->options = array_merge($this->options,$options);
} else {
$this->options = $options;
}
return $this;
}
public function getExpressions($type=null) {
if(!is_null($type)) {
$type = strtoupper($type);
if(isset($this->expressions[$type])) {
return $this->expressions[$type];
}
}
return $this->expressions;
}
public function parse($sql=null,$options=[]) {
if(!is_null($sql)) {
$this->setQuery($sql);
}
if(!empty($options)) {
$this->setOptions($options);
}
$this->wrapper->parse($this->query, $this->options);
$parsed = $this->wrapper->get();
foreach($parsed as $key=>$value) {
$key = strtoupper($key);
$this->expressions[$key] = [];
foreach($value as $expr) {
$this->expressions[$key][] = Expression::fromArray($expr);
}
}
}
public function get($whatPart,$asSql=false) {
$whatPart = strtoupper($whatPart);
if(isset($this->expressions[$whatPart])) {
if($asSql) {
$sql = [];
foreach($this->expressions[$whatPart] as $expr) {
$sql[] = $expr->toSql();
}
return implode(" ",$sql);
} else {
return $this->expressions[$whatPart];
}
}
return false;
}
public function toArray($options=[]) {
$sqlArray = [];
$part = isset($options["part"]) ? $options["part"] : null;
if(is_null($part)) {
foreach($this->expressions as $key=>$value) {
$sqlArray[$key] = [];
foreach($value as $expr) {
$sqlArray[$key][] = $expr->toArray($options);
}
}
} else {
$part = strtoupper($part);
if(isset($this->expressions[$part])) {
foreach($this->expressions[$part] as $expr) {
$sqlArray[] = $expr->toArray($options);
}
}
}
return $sqlArray;
}
public function jsonSerialize() {
return $this->toArray();
}
public function __toString() {
return json_encode($this->toArray(),JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES);
}
public function toString($options=[]) {
$sqlArray = $this->toArray($options);
return json_encode($sqlArray,JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES);
}
public function toSql($options=[]) {
$params = new Params();
$sqlArray = [];
$part = isset($options["part"]) ? $options["part"] : null;
if(is_null($part)) {
foreach($this->expressions as $key=>$value) {
$sqlArray[$key] = [];
foreach($value as $expr) {
if($expr instanceof Expression) {
$sqlArray[$key][] = $expr->toSql($options,$params);
} else {
$sqlArray[$key][] = $expr;
}
}
}
foreach($sqlArray as $key=>$value) {
$sqlArray[$key] = $this->keyToSql($key)." ".implode(" ",$value);
}
} else {
$part = strtoupper($part);
if(isset($this->expressions[$part])) {
foreach($this->expressions[$part] as $expr) {
if($expr instanceof Expression) {
$sqlArray[] = $expr->toSql($options,$params);
} else {
$sqlArray[] = $expr;
}
}
}
}
return ["sql"=>implode(" ",$sqlArray),"params"=>$params->get()];
}
private function keyToSql($key) {
$key = strtoupper($key);
if($key == "ORDER") {
return "ORDER BY";
}
return $key;
}
} src/Query.php 0000644 00000013410 14476160707 0007164 0 ustar 00 rawQueryString = $queryString;
}
public function getQuery($interpolate=false) {
$parser = new QueryParser($this);
$parser->parse();
$sql = $parser->getQueryString();
if($interpolate) {
$sql = dhDB::interpolateQuery($sql,$this->values);
}
return $sql;
}
public function insert($i,$v=null) {
$this->type = "insert";
return $this->column($i,$v);
}
public function select($s) {
$this->type = "select";
return $this->column($s);
}
public function update($i,$v) {
$this->type = "update";
return $this->updateValue($i,$v);
}
public function create($t,$ifNotExists=false) {
$this->type = "create";
$this->ifNotExists = $ifNotExists;
return $this->table($t);
}
public function alter($t) {
$this->type = "alter";
return $this->table($t);
}
public function into(...$args) {
return $this->table(...$args);
}
public function from(...$args) {
return $this->table(...$args);
}
public function join(...$args) {
return $this->table(...$args);
}
public function where($c,$v=null) {
return $this->condition($c,$v);
}
public function order($o) {
$this->orderBy[] = $o;
return $this;
}
public function orderBy($o) {
$this->orderBy[] = $o;
return $this;
}
public function group($o) {
$this->groupBy[] = $o;
return $this;
}
public function groupBy($o) {
$this->groupBy[] = $o;
return $this;
}
public function limit($num,$start=0) {
$this->limit = [];
$this->limit[] = $start;
$this->limit[] = $num;
return $this;
}
public function add($col,$type=null,$extra=null) {
return $this->schemaColumn("add",$col,$type,$extra);
}
public function remove($col) {
return $this->schemaColumn("drop",$col);
}
public function change($col,$newcol,$type=null,$extra=null) {
return $this->schemaColumn("change",[$col,$newcol],$type,$extra);
}
public function addIndex($name,$cols=[],$type="key") {
return $this->schemaColumn("addIndex",$name,strtolower($type),$cols);
}
public function key($name,$cols=[],$type="key") {
return $this->schemaColumn("addIndex",$name,strtolower($type),$cols);
}
public function index($name,$cols=[],$type="key") {
return $this->schemaColumn("addIndex",$name,strtolower($type),$cols);
}
public function dropIndex($name) {
return $this->schemaColumn("dropIndex",$name);
}
public function meta($key,$value=null) {
if($this->type == "create" || $this->type == "alter") {
$this->tableMeta[] = ["key"=>$key,"value"=>$value];
}
return $this;
}
public function schemaColumn($action="add",$col,$type=null,$extra=null) {
$this->schemaColumns[] = ["action"=>$action,"column"=>$col,"type"=>$type, "extra"=>$extra];
return $this;
}
public function column($c,$v=null,$extraIfAlterOrAdd=null) {
if($this->type == "create" || $this->type == "alter") {
return $this->add($c,$v,$extraIfAlterOrAdd);
} else {
if(is_array($c)) {
foreach($c as $col) {
$this->columns[] = $col;
}
} else {
$this->columns[] = $c;
}
if(!is_null($v)) {
if(is_array($v)) {
foreach($v as $val) {
$this->value($v);
}
} else {
$this->value($v);
}
}
return $this;
}
}
public function updateValue($c,$v=null) {
if(!is_array($c) && !is_null($v)) {
$this->columns[] = $c."=?";
$this->values[] = $v;
} else {
return $this->column($c,$v);
}
return $this;
}
public function condition($c,$v=null) {
if(is_array($c)) {
foreach($c as $col) {
$this->conditions[] = $c;
}
} else {
$this->conditions[] = $c;
}
if(!is_null($v)) {
if(is_array($v)) {
foreach($v as $val) {
$this->value($val);
}
} else {
$this->value($v);
}
}
return $this;
}
public function table($t,$type=null,$on=null) {
$this->tables[] = ["name"=>$t,"type"=>$type,"on"=>$on];
return $this;
}
public function values($arr) {
foreach($arr as $v) {
$this->value($v);
}
return $this;
}
public function value($v,$vv=null) {
if(!is_null($vv)) {
$this->values[$v] = $vv;
} else {
if(is_array($v)) {
return $this->values($v);
} else {
$this->values[] = $v;
}
}
return $this;
}
} src/Schema.php 0000644 00000047505 14476160707 0007273 0 ustar 00 setTableName($tableName);
}
if(!is_null($file)) {
$this->setFile($file);
if(!is_null($this->file)) {
$this->load();
}
}
}
public function get($version=null) {
$array["name"] = $this->getTableName();
$array["meta"] = $this->getMeta($version);
$array["columns"] = $this->getColumns($version);
$array["keys"] = $this->getKeys($version);
return $array;
}
public function getAll() {
$array["tableName"] = $this->tableName;
$array["meta"] = $this->meta;
$array["columns"] = $this->columns;
$array["keys"] = $this->keys;
$array["history"] = $this->history;
$array["versions"] = $this->versions;
$array["changes"] = $this->changes;
return $array;
}
public function save($makeVersion=true) {
if(!empty($this->changes) && $makeVersion) {
$this->version++;
$versionString = $this->getVersionString();
$this->meta("comment","dhDB::".$versionString);
$this->history[$versionString] = $this->changes;
$this->versions[$versionString]["columns"] = $this->columns;
$this->versions[$versionString]["keys"] = $this->keys;
$this->versions[$versionString]["meta"] = $this->meta;
$this->changes = [];
}
if(!is_null($this->file)) {
$this->file->write(json_encode($this->getAll(),JSON_PRETTY_PRINT));
}
return $this;
}
public function load($clean=true) {
if(!is_null($this->file)) {
$data = $this->file->content(["json"=>true]);
if(is_array($data)) {
if(!$clean) {
$this->meta = dhGlobal::getVal($data,"meta",null);
$this->columns = dhGlobal::getVal($data,"columns",null);
$this->keys = dhGlobal::getVal($data,"keys",null);
}
$this->history = dhGlobal::getVal($data,"history",null);
$this->versions = dhGlobal::getVal($data,"versions",null);
$this->version = 0;
if(is_array($this->versions)) {
foreach($this->versions as $version=>$d) {
$version = intval(dhGlobal::trimString("v_",$version,dhGlobal::TRIM_START));
if($version>$this->version) {
$this->version = $version;
}
}
}
}
}
return $this;
}
public function getColumnHistory($column) {
$columnHistory = [];
if(!empty($this->history)) {
foreach($this->history as $version=>$changes) {
foreach($changes as $change) {
if($change["column"] == $column && strpos($change["action"],"Index") === false) {
$columnHistory[$version][] = $change;
}
}
}
}
return $columnHistory;
}
public function replayHistory($version=null) {
if(!is_null($version)) {
$version = $this->getVersionString($version);
if(isset($this->history[$version])) {
$this->replayHistoryVersion($version);
return true;
}
return false;
} else {
if(!empty($this->history)) {
$versions = array_keys($this->history);
foreach($versions as $version) {
$this->replayHistoryVersion($version);
}
return true;
}
return false;
}
return false;
}
protected function replayHistoryVersion($version) {
foreach($this->history[$version] as $entry) {
$this->schemaColumnEntry($entry);
}
}
public function version($version=null) {
if(is_null($version)) {
return $this->version;
}
if($version === true) {
$this->version++;
} else {
$this->version = $version;
}
return $this;
}
public function add($col,$type=null,$extra=null) {
return $this->schemaColumn("add",$col,$type,$extra);
}
public function remove($col) {
return $this->schemaColumn("drop",$col);
}
public function change($col,$newcol,$type=null,$extra=null) {
return $this->schemaColumn("change",[$col,$newcol],$type,$extra);
}
public function addIndex($name,$cols=[],$type="key") {
return $this->schemaColumn("addIndex",$name,strtolower($type),$cols);
}
public function key($name,$cols=[],$type="key") {
return $this->schemaColumn("addIndex",$name,strtolower($type),$cols);
}
public function index($name,$cols=[],$type="key") {
return $this->schemaColumn("addIndex",$name,strtolower($type),$cols);
}
public function dropIndex($name) {
return $this->schemaColumn("dropIndex",$name);
}
public function meta($key,$value=null,$version=null) {
if($version == null) {
$this->meta[$key] = ["key"=>$key,"value"=>$value];
} else {
$version = $this->getVersionString($version);
$this->versions[$version]["meta"][$key] = ["key"=>$key,"value"=>$value];
}
return $this;
}
protected function parseColExtra($extra,$glue=" ") {
$null = dhGlobal::getVal($extra,"null",false);
$collate = dhGlobal::getVal($extra,"collate",false);
$charset = dhGlobal::getVal($extra,"charset",false);
$default = dhGlobal::getVal($extra,"default",false);
$auto_incr = dhGlobal::getVal($extra,"auto_increment",false);
if(!$charset && $collate !== false) {
list($charset,$unused) = explode("_",$charset,2);
}
$parts = [];
if($charset !== false) {
$parts[] ="CHARACTER SET ".$charset;
}
if($collate !== false) {
$parts[] ="COLLATE ".$collate;
}
if($null) {
if($default === false) {
$parts[] = "DEFAULT NULL";
} else {
$parts[] = 'DEFAULT "'.$default.'"';
}
} else {
$parts[] = "NULL NULL";
if($default !== false) {
$parts[] = 'DEFAULT "'.$default.'"';
}
}
if($auto_incr !== false) {
$parts[] = "AUTO_INCREMENT";
}
return implode($glue,$parts);
}
public function schemaColumn($action="add",$col,$type=null,$extra=null) {
$entry = ["action"=>$action,"column"=>$col,"type"=>$type, "extra"=>$extra];
return $this->schemaColumnEntry($entry);
}
protected function schemaColumnEntry(array $entry) {
if(!is_array($this->changes)) {
$this->changes = [];
}
$changed = $this->processEntry($entry);
if($changed) {
$this->changes[] = $entry;
}
return $this;
}
protected function processEntry(array $entry) {
$action = $entry["action"];
$column = $entry["column"];
$type = $entry["type"];
$extra = $entry["extra"];
if($action == "add") {
if(!isset($this->columns[$column])) {
$this->columns[$column] = ["type"=>$type,"extra"=>$extra];
return true;
}
return false;
} elseif($action == "drop") {
if(isset($this->columns[$column])) {
unset($this->columns[$column]);
return true;
}
return false;
} elseif($action == "change") {
$old = $column[0];
$new = $column[1];
if(isset($this->columns[$old])) {
unset($this->columns[$old]);
$this->columns[$new] = ["type"=>$type,"extra"=>$extra];
return true;
}
if(!isset($this->columns[$new])) {
$entry["action"] == "add";
return $this->processEntry($entry);
}
return false;
} elseif($action == "dropIndex") {
if(isset($this->keys[$column])) {
unset($this->keys[$column]);
return true;
}
return false;
} elseif($action == "addIndex") {
if(!isset($this->keys[$column])) {
$this->keys[$column] = ["type"=>$type,"columns"=>$extra];
return true;
}
return false;
}
}
public function toQuery($patch=false) {
$query = new Query();
$table = $this->getTableName();
if($patch && $this->version>=1) {
return $this->toPatchQuery();
}
$query->create($table);
$after = null;
foreach($this->getColumns($this->version) as $col=>$entry) {
//if(!is_null($after)) {
//$entry["extra"]["after"] = $after;
//}
if(isset($entry["extra"]["after"])) {
unset($entry["extra"]["after"]);
}
$query->add($col,$entry["type"],$entry["extra"]);
$after = $col;
}
foreach($this->getKeys($this->version) as $name=>$entry) {
$query->addIndex($name,$entry["columns"],$entry["type"]);
}
foreach($this->getMeta($this->version) as $key=>$entry) {
$noBlank = ["auto_increment","comment"];
if(in_array($entry["key"],$noBlank) && (is_null($entry["value"]) || empty($entry["value"]))) {
} else {
$query->meta($entry["key"],$entry["value"]);
}
}
return $query;
}
public function toPatchQuery($reorder=false) {
if($this->version<=0) {
return $this->toQuery(false);
}
$changes = 0;
$savedCols = $this->getColumns($this->version);
$curCols = $this->getColumns();
$savedOrder = array_keys($savedCols);
$curOrder = array_keys($curCols);
$columnAfter = [];
$needAfter = [];
foreach($savedOrder as $colname) {
$columnAfter[$colname] = $this->getColumnAfter($colname,$this->version);
}
unset($savedOrder);
foreach($curOrder as $colname) {
if($columnAfter[$colname] != $this->getColumnAfter($colname)) {
$needAfter[$colname] = $columnAfter[$colname];
}
}
unset($curOrder);
$query = new Query();
$table = $this->getTableName();
$query->alter($table);
foreach($curCols as $col=>$entry) {
if(!isset($savedCols[$col])) {
$origCol = $col;
//currentColumn isn't part of the savedCols.. now we see if it changed
$changed = $dropped = false;
$colHist = $this->getColumnHistory($col);
foreach($colHist as $ver=>$changes) {
foreach($changes as $change) {
if($change["action"] == "change" && $change["column"][0] == $col) {
$col = $change["column"][1];
$entry = ["type"=>$change["type"],"extra"=>$change["extra"]];
$changed=true;
}
if($changed && $change["action"] == "drop" && $change["column"] == $col) {
$changed = false;
}
}
}
if($changed) {
if(isset($savedCols[$col])) {
$extra = $savedCols[$col]["extra"];
if(isset($columnAfter[$col])) {
$extra["after"] = $columnAfter[$col];
if(isset($needAfter[$col])) {
unset($needAfter[$col]);
}
}
$query->change($origCol,$col,$savedCols[$col]["type"],$extra);
$changes++;
} else {
throw new \Exception("Couldn't process change for $origCol to $col.. $col not part of current columns. History fail?");
}
} else {
$query->remove($origCol);
$changes++;
}
}
}
$addedCols = [];
foreach($savedCols as $sCol=>$entry) {
if(!isset($curCols[$sCol])) {
$entry["extra"]["after"] = $this->getColumnAfter($sCol,$this->version);
$query->add($sCol,$entry["type"],$entry["extra"]);
$addedCols[] = $sCol;
$changes++;
} else {
$changed = false;
$versionTypeDiff = false;
if(strpos($entry["type"],"(") === false) {
if(substr($curCols[$sCol]["type"],0,strlen($entry["type"])+1) == $entry["type"]."(") {
$versionTypeDiff = true;
}
}
if($entry["type"] != $curCols[$sCol]["type"] && !$versionTypeDiff) {
$changed = true;
} else {
if(!is_array($entry["extra"]) && is_array($curCols[$sCol]["extra"])) {
$changed = true;
} elseif(is_array($entry["extra"]) && !is_array($curCols[$sCol]["extra"])) {
$changed = true;
} elseif(count($entry["extra"]) !== count($curCols[$sCol]["extra"])) {
$changed = true;
} else {
foreach($entry["extra"] as $e=>$ev) {
if(!isset($curCols[$sCol]["extra"][$e]) || $curCols[$sCol]["extra"][$e] != $ev) {
$changed = true;
}
}
}
}
if($changed) {
$entry["extra"]["after"] = $this->getColumnAfter($sCol,$this->version);
if(isset($needAfter[$sCol])) {
unset($needAfter[$sCol]);
}
$query->change($sCol,$sCol,$entry["type"],$entry["extra"]);
$changes++;
}
}
}
if(!empty($needAfter)) {
foreach($needAfter as $col=>$after) {
if(in_array($after,$addedCols)) {
} else {
$extra = $savedCols[$col]["extra"];
$extra["after"] = $after;
$query->change($col,$col,$savedCols[$col]["type"],$extra);
$changes++;
}
}
}
//TODO: order check //$entry["extra"]["after"] = $this->getColumnAfter($sCol,$this->version);
if($changes>0) {
foreach($this->getMeta($this->version) as $key=>$entry) {
if($entry["key"] == "auto_increment")
$query->meta($entry["key"],$entry["value"]);
}
return $query;
}
return false;
}
protected function getColumnAfter($colName,$version=null) {
$columns = $this->getColumns($version);
$colKeys = array_keys($columns);
$after = false;
foreach($colKeys as $sCol) {
if($sCol == $colName) {
return $after;
}
$after = $sCol;
}
return $after;
}
public function jsonSerialize($array=null) {
if(is_null($array)) {
}
return $array;
}
public function __toString() {
return json_encode($this);
}
/**
* Get the value of tableName
*/
public function getTableName() {
return $this->tableName;
}
/**
* Get the value of columns
*/
public function getColumns($version=null) {
if($version == null) {
return $this->columns;
} else {
$version = $this->getVersionString($version);
return dhGlobal::getVal($this->versions[$version],"columns",null);
}
}
/**
* Get the value of keys
*/
public function getKeys($version=null) {
if($version == null) {
return $this->keys;
} else {
$version = $this->getVersionString($version);
return dhGlobal::getVal($this->versions[$version],"keys",null);
}
}
/**
* Get the value of meta
*/
public function getMeta($version=null) {
if($version == null) {
return $this->meta;
} else {
$version = $this->getVersionString($version);
return dhGlobal::getVal($this->versions[$version],"meta",null);
}
}
/**
* Get the value of versions
*/
public function getVersions() {
return $this->versions;
}
/**
* Get the value of history
*/
public function getHistory($version=null) {
if($version == null) {
return $this->history;
} else {
$version = $this->getVersionString($version);
return dhGlobal::getVal($this->history,$version,null);
}
}
/**
* Get the value of changes
*
* @return mixed
*/
public function getChanges() {
return $this->changes;
}
/**
* Set the value of columns
*
* @return self
*/
public function setColumns($columns) {
$this->columns = $columns;
return $this;
}
/**
* Set the value of tableName
*
* @return self
*/
public function setTableName($tableName) {
$this->tableName = $tableName;
return $this;
}
/**
* Set the value of keys
*
* @return self
*/
public function setKeys($keys) {
$this->keys = $keys;
return $this;
}
/**
* Set the value of meta
*
* @return self
*/
public function setMeta($meta) {
$this->meta = $meta;
return $this;
}
/**
* Get the value of file
*
* @return mixed
*/
public function getFile() {
return $this->file;
}
/**
* Set the value of file
*
* @param File|String $file
* @return self
*/
public function setFile($file) {
if(!is_object($file)) {
if(is_string($file)) {
$this->file = new File(["path"=>$file]);
} elseif(is_array($file)) {
$this->file = new File($file);
}
} else {
$this->file = $file;
}
return $this;
}
protected function getVersionString($version=null) {
if(is_null($version)) {
$version = $this->version;
}
if(!is_numeric($version)) {
return $version;
}
return "v_".$version;
}
} src/core/DebugPrinter.php 0000644 00000021136 14476160707 0011405 0 ustar 00
.dhdb-debugger-line {
width: 100%;
display: flex;
}
.dhdb-debugger-container {
width: 100%;
margin-bottom: 3px;
/*border-width: 1px 0px;
border-style: solid;
border-color: black;*/
background-color: #ececec;
font-size: 12px;
line-height: normal;
}
.dhdb-debugger-time {
width: 60px;
min-width: 60px;
max-width: 60px;
padding-left: 10px;
padding-right: 10px;
font-size: 12px;
line-height: normal;
background-color: #dbf4db;
}
.dhdb-debugger-slow {
background-color: #fbeac0;
}
.dhdb-debugger-query {
flex-grow: 1;overflow: hidden;text-overflow: ellipsis;
padding-left: 10px;
}
.dhdb-debugger-params {
flex-grow: 1;overflow: hidden;text-overflow: ellipsis;
}
.dhdb-debugger-trace {
width:100%;background-color: #ececec;
}
.dhdb-debugger-error {
width:100%;background-color: #fbeac0
}
.dhdb-debugger-trace-table {
font-size: 12px;margin-left: 15px;
}
.dhdb-debugger-trace-table td, .dhdb-debugger-td,
.table tbody tr td.dhdb-debugger-td,
.table-bordered tbody tr td.dhdb-debugger-td,
.table-bordered tbody:first-child tr:first-child td.dhdb-debugger-td,
.table tbody:first-child tr:first-child td.dhdb-debugger-td
{
padding-left: 5px;
padding-right: 5px;
padding-top: 0px;
padding-bottom: 0px;
border-top: 1px solid #ccc;
min-width: 300px;
overflow: hidden;
text-overflow: ellipsis;
text-align: left;
vertical-align: top;
}
.dhdb-debugger-linenumber {
width: 50px;
min-width: 50px;
max-width: 50px;
text-align: right;
padding-right: 5px;
display: table-cell;
}
.dhdb-debugger-filename {
display: table-cell;
}
';
public static $lines = [
"html" => [
'
',
'
',
'
{TIME}s
',
'
{SQLTXT}
',
'
{PARAMS}
',
'
',
"{ERROR_LINE}",
"{TRACE_LINE}",
'
'
],
"text" => [
"----",
"{SQLTXT}",
"{PARAMS}",
"Exec: {TIME}",
"{ERROR_LINE}",
"{TRACE_LINE}",
"----"
],
"ERROR_LINE" => [
"html" => '{ERROR_NO}: {ERROR_MSG}
',
"text" => "{ERROR_NO}: {ERROR_MSG}",
],
"TRACE_LINE" => [
"html" => '{TRACE}
',
"text" => "{TRACE}"
]
];
public static function printHtml($statement,$isSlow=false,$useInterpolate=true) {
if(!self::$hasInjectedStyle) {
echo self::$htmlStyles."\n";
self::$hasInjectedStyle = true;
}
$sqlTxt = $paramTxt = "";
if($useInterpolate) {
$sqlTxt = $statement->interpolate();
} else {
$sqlTxt = $statement->getQuery();
$paramTxt = static::paramsToString($statement->getParams());
if(!empty($paramTxt)) {
$paramTxt = "".$paramTxt."";
}
}
$arr = [];
$arr["SQLTXT"] = htmlentities($sqlTxt);
$arr["TIME"] = number_format($statement->getExecTime(),6,".","");
$arr["PARAMS"] = $paramTxt;
$arr["TRACE_LINE"] = "";
$arr["ERROR_LINE"] = "";
$arr["SLOW_TIME"] = "";
if($isSlow) {
$arr["SLOW_TIME"] = ' dhdb-debugger-slow';
}
if(!empty($statement->getTrace())) {
$tempArr = ["TRACE"=>static::traceToString($statement->getTrace())];
$arr["TRACE_LINE"] = static::parseLine(static::$lines["TRACE_LINE"]["html"],$tempArr);
}
if(is_object($statement->getError())) {
$error = $statement->getError()->toArray();
$tempArr = ["ERROR_NO"=>$error["code"],"ERROR_MSG"=>$error["message"]];
$arr["ERROR_LINE"] = static::parseLine(static::$lines["ERROR_LINE"]["html"],$tempArr);
}
$printLines = static::parseLines(static::$lines["html"],$arr);
foreach($printLines as $line) {
if(!empty($line)) {
echo $line."\n";
}
}
}
public static function printText($statement,$isSlow=false,$useInterpolate=true) {
$sqlTxt = $paramTxt = "";
if($useInterpolate) {
$sqlTxt = $statement->interpolate();
} else {
$sqlTxt = $statement->getQuery();
$paramTxt = static::paramsToString($statement->getParams());
}
$arr = [];
$arr["SQLTXT"] = $sqlTxt;
$arr["TIME"] = number_format($statement->getExecTime(),6,".","");
$arr["PARAMS"] = $paramTxt;
$arr["TRACE_LINE"] = "";
$arr["ERROR_LINE"] = "";
if(!empty($statement->getTrace())) {
$tempArr = ["TRACE"=>static::traceToString($statement->getTrace())];
$arr["TRACE_LINE"] = static::parseLine(static::$lines["TRACE_LINE"]["text"],$tempArr);
}
if(is_object($statement->getError())) {
$error = $statement->getError()->toArray();
$tempArr = ["ERROR_NO"=>$error["code"],"ERROR_MSG"=>$error["message"]];
$arr["ERROR_LINE"] = static::parseLine(static::$lines["ERROR_LINE"]["text"],$tempArr);
}
$printLines = static::parseLines(static::$lines["text"],$arr);
foreach($printLines as $line) {
if(!empty($line)) {
echo $line."\n";
}
}
}
private static function parseLines($lines,$vars) {
foreach($lines as $lnum=>$line) {
$line = static::parseLine($line,$vars);
if(empty($line)) {
unset($lines[$lnum]);
continue;
}
$lines[$lnum] = $line;
}
return $lines;
}
private static function parseLine($line,$vars) {
foreach($vars as $k=>$v) {
if(is_null($v)) $v = "";
$line = str_replace('{'.$k.'}',$v,$line);
}
return $line;
}
public static function paramsToString($params) {
$paramString = '';
if ($params && !empty($params)) {
foreach($params as $kk=>$vv) {
if (is_string($vv) && strlen($vv)>64) $vv = substr($vv,0,64).'...';
if (is_null($vv)) $paramString .= "($kk=>null) ";
else $paramString .= "($kk=>'$vv') ";
}
$paramString = "[ $paramString ]";
}
return $paramString;
}
public static function traceToString($trace) {
$fmt = "%% line %4d, file: %s func: %s";
$string = "";
foreach($trace as $arr) {
$string .= @sprintf($fmt, $arr['line'],$arr['file'],$arr['func'])."\n";
}
return $string;
}
public static function traceToTable($trace) {
$fmt = '
| %s |
%4d @
%s
|
';
$string = '';
$string .= '';
foreach($trace as $arr) {
if($arr['func'] == 'Vtiger_WebUI->process()') {
break;
}
$string .= @sprintf($fmt, $arr['func'],$arr['line'],$arr['file'])."\n";
if(strpos($arr['file'],'templates_c') !== false) {
break;
}
}
$string.= '
';
return $string;
}
} src/core/Debugger.php 0000644 00000011445 14476160707 0010541 0 ustar 00 setOptions($options);
}
}
public function setOptions($options=[]) {
foreach($options as $key=>$value) {
if(method_exists($this,$key)) {
$this->$key($value);
}
}
}
public function getOptions() {
return [
"isBrowser" => $this->isBrowser,
"useInterpolate" => $this->useInterpolate,
"saveToTable" => $this->saveToTable,
"printDebug" => $this->printDebug,
"includeTrace" => $this->includeTrace,
"slowLimit" => $this->slowLimit,
"logSlow" => $this->logSlow,
"printSlow" => $this->printSlow,
"reference" => $this->reference,
"callback" => $this->callback,
];
}
public function isBrowser($isBrowser=null) {
if(is_null($isBrowser)) return $this->isBrowser;
$this->isBrowser = $isBrowser;
}
public function useInterpolate($useInterpolate=null) {
if(is_null($useInterpolate)) return $this->useInterpolate;
$this->useInterpolate = $useInterpolate;
}
public function saveToTable($saveToTable=null) {
if(is_null($saveToTable)) return $this->saveToTable;
$this->saveToTable = $saveToTable;
}
public function printDebug($printDebug=null) {
if(is_null($printDebug)) return $this->printDebug;
$this->printDebug = $printDebug;
}
public function includeTrace($includeTrace=null) {
if(is_null($includeTrace)) return $this->includeTrace;
$this->includeTrace = $includeTrace;
}
public function slowLimit($slowLimit=null) {
if(is_null($slowLimit)) return $this->slowLimit;
$this->slowLimit = $slowLimit;
}
public function logSlow($logSlow=null) {
if(is_null($logSlow)) return $this->logSlow;
$this->logSlow = $logSlow;
}
public function printSlow($printSlow=null) {
if(is_null($printSlow)) return $this->printSlow;
$this->printSlow = $printSlow;
}
public function reference($reference=null) {
if(is_null($reference)) return $this->reference;
$this->reference = $reference;
}
public function callback($callback=null) {
if(is_null($callback)) return $this->callback;
$this->callback = $callback;
}
/**
*
* @param Statement $statement
* @return void
*/
public function log($statement) {
if(is_callable($this->callback)) {
call_user_func($this->callback,$statement);
}
if($this->saveToTable || ($this->logSlow && $this->isSlow($statement))) {
if($this->includeTrace && empty($statement->getTrace())) {
$statement->setTrace(DebugTrace::getTraceInfo(3));
}
//$this->logToTable($statement);
}
if($this->printDebug || ($this->printSlow && $this->isSlow($statement))) {
if($this->includeTrace && empty($statement->getTrace())) {
$statement->setTrace(DebugTrace::getTraceInfo(3));
}
if($this->isBrowser) {
DebugPrinter::printHtml($statement,$this->isSlow($statement),$this->useInterpolate);
} else {
DebugPrinter::printText($statement,$this->isSlow($statement),$this->useInterpolate);
}
}
}
private function isSlow($statement) {
return $statement->getExecTime() >= $this->slowLimit;
}
} src/core/Error.php 0000644 00000006061 14476160707 0010104 0 ustar 00 setMessage($exception->getMessage());
$this->setTrace($exception->getTrace());
$this->setCode($exception->getCode());
}
$this->setQuery($query);
$this->setParams($params);
$this->setInterpolated($interpolated);
}
public function toArray() {
$array["query"] = $this->query;
if(!empty($this->params)) {
$array["params"] = $this->params;
$array["interpolated"] = $this->interpolated;
}
$array["message"] = $this->message;
$array["code"] = $this->code;
$array["trace"] = $this->trace;
return $array;
}
/**
* Get the value of message
*/
public function getMessage()
{
return $this->message;
}
/**
* Set the value of message
*
* @return self
*/
public function setMessage($message)
{
$this->message = $message;
return $this;
}
/**
* Get the value of query
*/
public function getQuery()
{
return $this->query;
}
/**
* Set the value of query
*
* @return self
*/
public function setQuery($query)
{
$this->query = $query;
return $this;
}
/**
* Get the value of params
*/
public function getParams()
{
return $this->params;
}
/**
* Set the value of params
*
* @return self
*/
public function setParams($params)
{
$this->params = $params;
return $this;
}
/**
* Get the value of trace
*/
public function getTrace()
{
return $this->trace;
}
/**
* Set the value of trace
*
* @return self
*/
public function setTrace($trace)
{
$this->trace = $trace;
return $this;
}
/**
* Get the value of interpolated
*
* @return mixed
*/
public function getInterpolated() {
return $this->interpolated;
}
/**
* Set the value of interpolated
*
* @param mixed $interpolated
* @return self
*/
public function setInterpolated($interpolated) {
$this->interpolated = $interpolated;
return $this;
}
/**
* Get the value of code
*
* @return mixed
*/
public function getCode() {
return $this->code;
}
/**
* Set the value of code
*
* @param mixed $code
* @return self
*/
public function setCode($code) {
$this->code = $code;
return $this;
}
} src/core/Mysql.php 0000644 00000014675 14476160707 0010132 0 ustar 00 config = $config;
}
public function connect($config=null) {
if($this->connected) {
return true;
}
if(is_null($config)) {
$config = $this->config;
}
try {
if(!isset($this->config["dbtype"])) {
$this->config["dbtype"] = "mysql";
}
$dsn=$this->config["dbtype"].':host='.$this->config["dbhost"].";port=".$this->config["dbport"].";dbname=".$this->config["dbname"];
$user=$this->config["dbuser"];
$passwd=$this->config["dbpass"];
$options = array(
\PDO::ATTR_PERSISTENT => true,
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION
);
$this->pdo = new \PDO($dsn, $user, $passwd, $options);
$this->connected = true;
return true;
} catch (\PDOException $e) {
return false;
}
}
public function pdo() {
return $this->pdo;
}
public function prepare($sql,$params=[]) {
if(!$this->connect()) {
throw new \Exception("Could not connect to database");
}
return new Statement($this,$sql,$params);
}
public function getDumpCommand($db=null,$table=null) {
$cmd = "mysqldump";
$cmd.=" --host=".$this->config["dbhost"];
$cmd.=" --user=".$this->config["dbuser"];
$cmd.=" --password=".$this->config["dbpass"];
$cmd.=" ";
if(!is_null($db)) {
$cmd.=$db." ";
if(!is_null($table)) {
$cmd.="'".$table."' ";
}
}
return $cmd;
}
/**
* Wrapper for ResultInterface->next() so no need to check if result is proper or not before calling next()
*
* @param StatementInterface|null $handler
* @return bool|ResultInterface
*/
public function next($handler=null,$mode=\PDO::FETCH_ASSOC,$cursorOrientation = \PDO::FETCH_ORI_NEXT,$cursorOffset = 0) {
if(is_object($handler)) {
return $handler->next($mode,$cursorOrientation,$cursorOffset);
}
return false;
}
/**
* Wrapper for ResultInterface->next() so no need to check if result is proper or not before calling next()
*
* @param StatementInterface|null $handler
* @return bool|ResultInterface
*/
public function nextRow($handler=null,$assoc=true,$object=true) {
if(is_object($handler)) {
return $handler->nextRow($assoc,$object);
}
return false;
}
public function __call($method,$args) {
if(!$this->connected) {
return false;
}
return call_user_func_array( [$this->pdo,$method], $args);
}
//BC functions
public function driver($driver=null) {
return $this;
}
public function newQuery() {
return new Query();
}
public function newParser() {
return new QueryParser();
}
/**
* Returns a new Query object for ORM style operations
*
* @return Query
*/
public function makeQuery() {
return new Query();
}
/**
* Returns the SQL for a query object. If Interpolate is true, returns the interpolated query (default, true)
*
* @param Query $query the query object to parse
* @param boolean $interpolate wether or not to interpolate the returned sql
* @return string
*/
public function fromQuery(Query $query,$interpolate=true) {
$parser = new QueryParser($query);
$parser->parse();
$sql = $parser->getQueryString();
if($interpolate) {
return dhDB::interpolateQuery($sql,$query->values);
}
return $sql;
}
/**
* Generate a Schema for a table. Optionally provide an existing Schema for comparison
*
* @param string $table The tablename to parse
* @param null|Schema $schema optional schema to compare
* @return \boru\dhdb\Schema
*/
public function getTable($table,$schema=null) {
return $this->table($table,$schema);
}
public function table($tableName,$schema=null) {
$meta = [];
if(is_null($schema)) {
$schema = new Schema($tableName);
}
$sth = $this->run("SHOW TABLE STATUS LIKE ?",[$tableName]);
while($row = $sth->next()) {
$meta["engine"] = $row->get("Engine");
$meta["collate"] = $row->get("Collation");
if(!empty($row->get("Auto_increment"))) {
$meta["auto_increment"] = $row->get("Auto_increment");
}
if(!empty($row->get("Comment"))) {
$meta["comment"]= $row->get("Comment");
}
}
foreach($meta as $k=>$v) {
$schema->meta($k,$v);
}
$sth = $this->run("SHOW FULL FIELDS FROM `".$tableName."`");
while($row = $sth->next()) {
$extra = ["null"=>true];
if(strtolower($row->get("Null")) == "no") {
$extra["null"] = false;
}
if(!empty($row->get("Collation"))) {
$extra["collate"] = $row->get("Collation");
}
if(!empty($row->get("Default"))) {
$extra["default"] = $row->get("Default");
}
if(!empty($row->get("Extra")) && $row->get("Extra") == "auto_increment") {
$extra["auto_increment"] = true;
}
$schema->add($row->get("Field"),$row->get("Type"),$extra);
}
$sth = $this->run("SHOW INDEX FROM `".$tableName."`");
$indexArr = [];
while($row = $sth->next()) {
if(!isset($indexArr[$row->get("Key_name")])) {
if($row->get("Key_name") == "PRIMARY" && $row->get("Non_unique")<=0) {
$type = "primary";
} elseif($row->get("Index_type") == "FULLTEXT") {
$type="fulltext";
} elseif($row->get("Non_unique") <= 0) {
$type = "unique";
} else {
$type = "key";
}
$indexArr[$row->get("Key_name")] = [
"name"=>$row->get("Key_name"),
"type"=>$type,
"extra"=>[]
];
}
$indexArr[$row->get("Key_name")]["extra"][] = $row->get("Column_name").($row->get("Cardinality") == "D" ? " DESC" : "");
}
foreach($indexArr as $name=>$index) {
$schema->addIndex($name,$index["extra"],$index["type"]);
}
return $schema;
}
} src/core/Row.php 0000644 00000004672 14476160707 0007570 0 ustar 00 fields = $fields;
}
}
public function __set($field,$val) {
$this->set($field,$val);
}
public static function fromStatement($row) {
if(is_array($row)) {
return new self($row);
}
return false;
}
public function get($column,$default=null) {
if(isset($this->fields[$column])) {
return $this->fields[$column];
}
return $default;
}
public function set($column,$value) {
$this->fields[$column] = $value;
}
public function exists($column=null) {
if(is_null($column)) {
return !empty($this->fields);
}
return isset($this->fields[$column]);
}
public function remove($column) {
if(isset($this->fields[$column])) {
unset($this->fields[$column]);
}
}
public function toArray() {
return $this->fields;
}
public function asArray() {
return $this->fields;
}
public function asString() {
return json_encode($this->fields);
}
public function asObject() {
return (object)$this->fields;
}
/**
* Inherits trait functions from GetSetArray
* ->get($key,$default=null)
* ->set($key,$val='',$append=false)
* ->exists($key=null)
*/
public function jsonSerialize($array=null) {
if(is_null($array)) {
$array = $this->fields;
}
return $array;
}
/**
* Ignore intelephense error, php 5.6 :(
*/
public function offsetExists($offset) {
return $this->exists($offset);
}
/**
* Ignore intelephense error, php 5.6 :(
*/
public function offsetGet($offset) {
return $this->get($offset);
}
/**
* Ignore intelephense error, php 5.6 :(
*/
public function offsetSet($offset , $value) {
$this->set($offset,$value);
}
/**
* Ignore intelephense error, php 5.6 :(
*/
public function offsetUnset($offset) {
$this->remove($this->$offset);
}
public function __toString() {
return json_encode($this->fields);
}
} src/core/Statement.php 0000644 00000015514 14476160707 0010762 0 ustar 00 false,
"debugOnError" => false,
"queryCallback" => null,
"trace" => false,
];
public function __construct($mysql,$query=null,$params=[]) {
$this->mysql = $mysql;
$this->pdo = $mysql->pdo();
$this->query = $query;
if(!is_null($query)) {
$this->prepare($query);
}
if(!is_null($params)) {
$this->bind($params);
}
}
public function __destruct() {
$this->stmt = null;
}
public function run($query=null,$params=[]) {
if(!$this->hasStmt()) {
return $this;
}
if(!is_null($query) || !empty($params)) {
$query = is_null($query) ? $this->query : $query;
$params = is_null($params) ? $this->params : $params;
$this->prepare($query,$params);
}
$this->startTime = microtime(true);
$this->completed = false;
try {
$this->stmt->execute();
$this->completed = true;
$this->error = false;
} catch (\PDOException $e) {
$this->error = new Error($this->query,$this->params,$this->interpolate(),$e);
} catch (\Exception $e) {
$this->error = new Error($this->query,$this->params,$this->interpolate(),$e);
}
if($this->options["trace"]) {
$this->trace = DebugTrace::getTraceInfo();
}
$this->endTime = microtime(true);
$this->execTime = $this->endTime - $this->startTime;
$this->logQuery();
return $this;
}
private function logQuery() {
$this->mysql->getDebugger()->log($this);
}
public function doTrace() {
$this->options["trace"] = true;
return $this;
}
public function doDebug() {
$this->options["debug"] = true;
return $this;
}
public function getQuery() {
return $this->query;
}
public function getParams() {
return $this->params;
}
public function getExecTime() {
return $this->execTime;
}
public function getError() {
return $this->error;
}
public function getTrace() {
return $this->trace;
}
public function getCompleted() {
return $this->completed;
}
public function interpolate() {
if(!empty($this->query)) {
return dhDB::interpolateQuery($this->query,$this->params);
}
return "";
}
public function getPDO() {
return $this->pdo;
}
public function toArray() {
return [
"query" => $this->query,
"params" => $this->params,
"interpolated" => $this->interpolate(),
"error" => $this->error,
"trace" => $this->trace,
"execTime" => $this->execTime,
"completed" => $this->completed,
];
}
/**
* Prepare the query
* @param mixed $query
* @param array $params
* @return $this
*/
public function prepare($query,$params=[]) {
$this->query = $query;
$this->stmt = $this->mysql->pdo()->prepare($query);
if(!is_null($this->stmt) && $this->stmt !== false) {
$this->stmt->setFetchMode(\PDO::FETCH_CLASS | \PDO::FETCH_PROPS_LATE,"\\boru\\dhdb\\drivers\\mysql\\Row");
}
if(!is_null($params)) {
$this->bind($params);
}
return $this;
}
/**
* Set the parameters for the query
* @param mixed $array
* @param mixed $array2
* @return bool
*/
public function bind($array=null) {
if(is_null($array) || $array === false) {
return false;
}
if(!is_array($array)) {
$array = [$array];
}
$this->params = array_merge($this->params,$array);
foreach($array as $value) {
$this->bindParam($value);
}
return true;
}
public function bindParam($value,$type=null) {
$this->bindPos($this->bindPos,$value,$type);
$this->bindPos++;
}
public function bindPos($pos,$value,$type=null) {
if(!$this->hasStmt()) {
return false;
}
if( is_null($type) ) {
switch( true ) {
case is_int($value):
$type = \PDO::PARAM_INT;
break;
case is_bool($value):
$type = \PDO::PARAM_BOOL;
break;
case is_null($value):
$type = \PDO::PARAM_NULL;
break;
default:
$type = \PDO::PARAM_STR;
}
}
$this->stmt->bindValue($pos,$value,$type);
}
public function hasStmt() {
return !is_null($this->stmt) && $this->stmt !== false;
}
public function nextRow($assoc=true,$object=true) {
if(!$this->hasStmt()) {
return false;
}
if(!is_null($this->stmt) && $this->stmt !== false) {
if($object) {
return $this->stmt->fetch($assoc ? \PDO::FETCH_ASSOC : \PDO::FETCH_NUM);
} else {
return $this->stmt->fetch($assoc ? \PDO::FETCH_ASSOC : \PDO::FETCH_NUM);
}
}
$this->stmt = null;
unset($this->stmt);
return false;
}
public function next($mode=\PDO::FETCH_ASSOC,$cursorOrientation = \PDO::FETCH_ORI_NEXT,$cursorOffset = 0) {
if(!$this->hasStmt()) {
return false;
}
if(!is_null($this->stmt) && $row = Row::fromStatement($this->stmt->fetch($mode,$cursorOrientation,$cursorOffset))) {
return $row;
}
$this->stmt = null;
unset($this->stmt);
return false;
}
public function all($object=true) {
if(!$this->hasStmt()) {
return false;
}
if($object) {
return $this->stmt->fetchAll(\PDO::FETCH_CLASS | \PDO::FETCH_PROPS_LATE,"\\boru\\dhdb\\drivers\\mysql\\Row");
} else {
return $this->stmt->fetchAll(\PDO::FETCH_ASSOC);
}
}
public function __call($method,$args) {
if(!$this->hasStmt()) {
return false;
}
return call_user_func_array( [$this->stmt,$method], $args);
}
} src/core/query/QueryParser.php 0000644 00000041227 14476160707 0012445 0 ustar 00 setQuery($query);
}
}
public function parse($query=null) {
if(is_null($query)) {
$query = $this->getQuery();
}
//raw query string
if(!is_null($query->rawQueryString)) {
return $this->setQueryString($query->rawQueryString);
}
if(isset($query->type) && !is_null($query->type)) {
//select query
if($query->type == "select") {
return $this->parseSelect($query);
}
//update query
if($query->type == "update") {
return $this->parseUpdate($query);
}
//insert query
if($query->type == "insert") {
return $this->parseInsert($query);
}
//delete query
//union query
//create table
if($query->type == "create") {
return $this->parseCreateTable($query);
}
//alter table
if($query->type == "alter") {
return $this->parseAlterTable($query);
}
}
}
protected function parseSelect($query) {
$sql = "";
$sql.= $this->parseColumnString($query," ");
$sql.= $this->parseTableString($query," FROM ");
$sql.= $this->parseConditionString($query," WHERE ");
$sql.= $this->parseGroupByString($query);
$sql.= $this->parseOrderByString($query);
$sql.= $this->parseLimitString($query);
if(!empty($sql)) {
return $this->setQueryString("SELECT".$sql);
}
return false;
}
protected function parseUpdate($query) {
$sql = "";
$sql.= $this->parseTableString($query,"UPDATE ");
$sql.= $this->parseColumnString($query," SET ",false);
$sql.= $this->parseConditionString($query," WHERE ");
$sql.= $this->parseGroupByString($query);
$sql.= $this->parseOrderByString($query);
$sql.= $this->parseLimitString($query);
if(!empty($sql)) {
return $this->setQueryString($sql);
}
return false;
}
protected function parseInsert($query) {
$sql = "";
$sql.= $this->parseTableString($query,"INSERT INTO ");
$sql.= " (";
$sql.= $this->parseColumnString($query);
$sql.= " ) ";
$sql.= $this->parseInsertValues($query,"VALUES ");
if(!empty($sql)) {
return $this->setQueryString($sql);
}
return false;
}
protected function parseCreateTable($query) {
$sql = "";
if($query->ifNotExists) {
$sql.= $this->parseTableString($query,"CREATE TABLE IF NOT EXISTS ");
} else {
$sql.= $this->parseTableString($query,"CREATE TABLE ");
}
$sql.= " (";
$sql.= $this->parseSchemaColumnsCreate($query);
$sql.= ") ";
$sql.= $this->parseTableMeta($query," ");
if(!empty($sql)) {
return $this->setQueryString($sql);
}
return false;
}
protected function parseAlterTable($query) {
$tableAlter = $this->parseTableString($query,"ALTER TABLE ");
$columnAlter = $this->parseSchemaColumnsAlter($query);
$metaAlter = $this->parseTableMeta($query,",");
$sql = $tableAlter." ";
$sqlInner = [];
if(!empty($columnAlter)) {
$sqlInner[]=$columnAlter;
}
if(!empty($metaAlter)) {
$sqlInner[]=$metaAlter;
}
if(!empty($sqlInner)) {
return $this->setQueryString($sql.implode(", ",$sqlInner));
}
return false;
}
protected function parseGroupByString($query) {
if(!is_null($query->groupBy)) {
if(is_array($query->groupBy)) {
return " GROUP BY ".implode(",",$query->groupBy);
} else {
return " GROUP BY ".$query->groupBy;
}
}
return "";
}
protected function parseOrderByString($query) {
if(!is_null($query->orderBy)) {
if(is_array($query->orderBy)) {
return " ORDER BY ".implode(",",$query->orderBy);
} else {
return " ORDER BY ".$query->orderBy;
}
}
return "";
}
protected function parseLimitString($query) {
if(!is_null($query->limit)) {
if(is_array($query->limit)) {
return " LIMIT ".implode(",",$query->limit);
} else {
return " LIMIT ".$query->limit;
}
}
return "";
}
protected function parseColumnString($query,$prefix="",$sanitize=true) {
if(empty($query->columns)) {
return "";
}
if($sanitize) {
$columns = array_map([$this,'sanitizeColumnName'],$query->columns);
} else {
$columns = $query->columns;
}
return $prefix.implode(",",$columns);
}
protected function parseConditionString($query,$prefix="") {
if(empty($query->conditions)) {
return "";
}
$conds = [];
foreach($query->conditions as $cond) {
$conds[] = "($cond)";
}
return $prefix.implode(" AND ",$conds);
}
protected function parseTableString($query,$prefix="") {
if(empty($query->tables)) {
return "";
}
$tables = $query->tables;
$string = $this->sanitizeColumnName($tables[0]["name"]);
array_shift($tables);
if(!empty($tables)) {
$tableStrings = [];
foreach($tables as $table) {
$tstring = "";
if(!is_null($table["type"])) {
$tstring.=" ".$table["type"]." ";
} else {
$tstring.=",";
}
$tstring .= $this->sanitizeColumnName($table["name"]);
if(!is_null($table["on"])) {
$tstring.=" ON ".$table["on"];
}
$tableStrings[] = $tstring;
}
$string.=implode(" ",$tableStrings);
}
return $prefix.$string;
}
public function parseInsertValues($query,$prefix = "") {
$valueGroups = [];
if(!empty($query->values)) {
if(is_array($query->values[0])) {
//TODO
} else {
$valueGroups[] = "(".$this->generateQs($query->values).")";
}
}
return $prefix.implode(",",$valueGroups);
}
public function parseSchemaColumnsCreate($query,$prefix = "") {
if(empty($query->schemaColumns)) {
return "";
}
$coldefs = [];
foreach($query->schemaColumns as $def) {
$action = $def["action"];
$col = $def["column"];
$type = $def["type"];
$extra = $def["extra"];
if($action == "add") {
$coldefs[] = $this->sanitizeColumnName($col)." $type".(!empty($extra) ? " ".$this->parseColExtra($extra,$type) : "");
} elseif($action == "addIndex") {
$indexCols = [];
if(is_array($extra)) {
foreach($extra as $v) {
$indexCols[] = $this->sanitizeColumnName($v);
}
} else {
$indexCols[] = $this->sanitizeColumnName($extra);
}
if(empty($type) || $type == "key") {
$coldefs[] = "KEY ".$this->sanitizeColumnName($col)." (".implode(",",$indexCols).")";
} elseif($type == "primary") {
$coldefs[] = "PRIMARY KEY (".implode(",",$indexCols).")";
} elseif($type == "fulltext") {
$coldefs[] = "FULLTEXT KEY ".$this->sanitizeColumnName($col)." (".implode(",",$indexCols).")";
} elseif($type == "unique") {
$coldefs[] = "UNIQUE KEY ".$this->sanitizeColumnName($col)." (".implode(",",$indexCols).")";
}
}
}
return implode(",",$coldefs);
}
public function parseSchemaColumnsAlter($query,$prefix = "") {
if(empty($query->schemaColumns)) {
return "";
}
$out = [];
foreach($query->schemaColumns as $def) {
//$this->schemaColumns[] = ["action"=>$action,"column"=>$col,"type"=>$type, "extra"=>$extra];
$action = $def["action"];
$col = $def["column"];
$type = $def["type"];
$extra = $def["extra"];
if($action == "add") {
$out[] = "ADD COLUMN ".$this->sanitizeColumnName($col)." $type".(!empty($extra) ? " ".$this->parseColExtra($extra,$type) : "");
} elseif($action == "drop") {
$out[] = "DROP COLUMN ".$this->sanitizeColumnName($col);
} elseif($action == "change") {
$out[] = "CHANGE COLUMN ".$this->sanitizeColumnName($col[0])." ".$this->sanitizeColumnName($col[1])." $type".(!empty($extra) ? " ".$this->parseColExtra($extra,$type) : "");
} elseif($action == "dropIndex") {
$out[] = "DROP INDEX ".$this->sanitizeColumnName($col);
} elseif($action == "addIndex") {
$indexCols = [];
if(is_array($extra)) {
foreach($extra as $v) {
$indexCols[] = $this->sanitizeColumnName($v);
}
} else {
$indexCols[] = $this->sanitizeColumnName($extra);
}
if(empty($type) || $type == "key") {
$out[] = "ADD KEY ".$this->sanitizeColumnName($col)." (".implode(",",$indexCols).")";
} elseif($type == "primary") {
$out[] = "ADD PRIMARY KEY (".implode(",",$indexCols).")";
} elseif($type == "fulltext") {
$out[] = "ADD FULLTEXT INDEX ".$this->sanitizeColumnName($col)." (".implode(",",$indexCols).")";
} elseif($type == "unique") {
$out[] = "ADD UNIQUE INDEX ".$this->sanitizeColumnName($col)." (".implode(",",$indexCols).")";
}
}
}
return $prefix.implode(",",$out);
}
public function parseTableMeta($query,$implode=",") {
//tableMeta
if(empty($query->tableMeta)) {
return "";
}
$out = [];
foreach($query->tableMeta as $def) {
$key = $def["key"];
$value = $def["value"];
if($key != "auto_increment") {
if(is_null($value) || empty($value)) {
$out[] = $key;
} else {
$noEmpty = ["comment","auto_increment"];
if($key == "comment" && !empty($value)) {
$out[] = $key.'="'.$value.'"';
} else {
$out[] = $key."=".$value;
}
}
}
}
return implode($implode,$out);
}
protected function parseColExtra($extra,$type,$glue=" ") {
if(!is_array($extra)) {
if(empty($extra)) {
return "";
} else {
return $extra;
}
}
$null = dhGlobal::getVal($extra,"null",false);
$collate = dhGlobal::getVal($extra,"collate",false);
$charset = dhGlobal::getVal($extra,"charset",false);
$default = dhGlobal::getVal($extra,"default",false);
$auto_incr = dhGlobal::getVal($extra,"auto_increment",false);
$after = dhGlobal::getVal($extra,"after",false);
if(!$charset && $collate !== false) {
list($charset,$unused) = explode("_",$collate,2);
}
$parts = [];
if($charset !== false) {
$parts[] ="CHARACTER SET ".$charset;
}
if($collate !== false) {
$parts[] ="COLLATE ".$collate;
}
if($null) {
if($default === false) {
$parts[] = "DEFAULT NULL";
} else {
if($type == "timestamp" && $default == "CURRENT_TIMESTAMP") {
$parts[] = 'DEFAULT CURRENT_TIMESTAMP';
} else {
$parts[] = 'DEFAULT "'.$default.'"';
}
}
} else {
$parts[] = "NOT NULL";
if($default !== false) {
if($type == "timestamp" && $default == "CURRENT_TIMESTAMP") {
$parts[] = 'DEFAULT CURRENT_TIMESTAMP';
} else {
$parts[] = 'DEFAULT "'.$default.'"';
}
}
}
if($auto_incr !== false) {
$parts[] = "AUTO_INCREMENT";
}
if($after !== false) {
$parts[] = "AFTER ".$this->sanitizeColumnName($after);
}
return implode($glue,$parts);
}
public function sanitizeColumnName($colString) {
if(!is_array($colString) && $colString == "*") {
return $colString;
}
if(!is_array($colString)) {
//$columns = explode(",",$colString);
$columns = [$colString];
} else {
$columns = $colString;
}
return $this->sanitize_arrayOfColumns($columns);
}
public function sanitize_arrayOfColumns($columns) {
foreach($columns as $k=>$colString) {
if(strpos($colString,"(") !== false && strpos($colString,")") !== false) {
//do nothing.. it's a function or subquery, and i'm not about to go down that rabbit hole.
echo "skipping $colString\n";
} elseif(strpos($colString," ") !== false) {
$columns[$k] = $this->sanitize_colWithAlias($colString);
} elseif(strpos($colString,".") !== false) {
$columns[$k] = $this->sanitize_colWithSub($colString);
} else {
$columns[$k] = $this->sanitize_colName($colString);
}
}
return implode(",",$columns);
}
public function sanitize_colWithAlias($colString) {
$parts = preg_split('/\sas\s|\s/', strtolower($colString));
foreach($parts as $k=>$part) {
if(strpos($parts[$k],".") !== false) {
$parts[$k] = $this->sanitize_colWithSub($part);
} else {
$parts[$k] = $this->sanitize_colName($part);
}
}
return implode(" ",$parts);
}
public function sanitize_colWithSub($colString) {
$parts = explode(".",strtolower($colString));
foreach($parts as $k=>$part) {
$parts[$k] = $this->sanitize_colName($part);
}
return implode(".",$parts);
}
public function sanitize_colName($col) {
if($col == "*") {
return $col;
}
return "`".preg_replace("/[^A-Za-z0-9\-_\.\(\)\*]/", '', $col)."`";
}
public function sanitize_quoteCol($field) {
if($field == "*") {
return $field;
}
return preg_replace("/[^\`A-Za-z0-9\-_\.\(\)\*\ ]/", '', $field);
}
/**
* Get the value of query
*/
public function getQuery()
{
return $this->query;
}
/**
* Set the value of query
*
* @return self
*/
public function setQuery($query)
{
$this->query = $query;
return $this;
}
/**
* Get the value of queryString
*/
public function getQueryString()
{
return $this->queryString;
}
/**
* Set the value of queryString
*
* @return self
*/
public function setQueryString($queryString)
{
$this->queryString = $queryString;
return $this;
}
/**
* Generate an array of [?,?,?,...]
*
* @param array $array the array to count/replace with '?'
* @param string $glue optional glue to use on the returned string (default ',');
* @return string
*/
public function generateQs($array,$glue=",") {
$qarr = array_fill(0,count($array),"?");
return implode($glue,$qarr);
}
} src/dhDB.php 0000644 00000011347 14476160707 0006667 0 ustar 00 setConfig($options["config"]);
} else {
$this->setConfig($options);
}
$debuggerOpts = [];
if(isset($_SERVER["HTTP_USER_AGENT"])) {
$debuggerOpts["isBrowser"] = true;
}
$this->debugger = new Debugger($debuggerOpts);
if($static) {
static::$instance = $this;
}
}
public function query($sql,$params=[],$options=[]) {
if(!$this->connect()) {
throw new \Exception("Could not connect to database");
}
if($sql instanceof Query) {
$sql = $this->fromQuery($sql);
}
$statement = $this->prepare($sql,$params);
return $statement->run();
}
public function run($sql,$params=[],$options=[]) {
return $this->query($sql,$params,$options);
}
public function printDebug($value=null) {
return $this->debugger->printDebug($value);
}
public function slowLimit($value=null) {
return $this->debugger->slowLimit($value);
}
public function setDebug($options) {
$this->debugger->setOptions($options);
return $this;
}
public function getDebugger() {
return $this->debugger;
}
//Convinience PDO Wrapper functions simply for IDE autocomplete
/**
* (PHP 5 >= 5.1.0, PHP 7, PECL pdo >= 0.1.0)
*
* Returns the ID of the last inserted row or sequence value
* @return string|false
*/
public function lastInsertId($name=null) {
return $this->pdo()->lastInsertId($name=null);
}
//Static functions
public static function instance($config=[]) {
if(is_null(static::$instance) || !empty($config)) {
static::$instance = new static($config);
}
return static::$instance;
}
public static function interpolateQuery($query="", $params=[]) {
if(empty($params)) {
return $query;
}
$keys = array();
$values = $params;
# build a regular expression for each parameter
foreach ($params as $key => $value) {
if (is_string($key)) {
$keys[] = '/:'.$key.'/';
} else {
$keys[] = '/[?]/';
}
if (is_array($value))
$values[$key] = implode(',', $value);
if (is_null($value))
$values[$key] = 'NULL';
}
// Walk the array to see if we can add single-quotes to strings
array_walk($values, function (&$v) {
if (!is_numeric($v) && $v!="NULL") {
$v = "\"".$v."\"";
}
});
$query = preg_replace($keys, $values, $query, 1, $count);
return $query;
}
/**
* Generate an array of [?,?,?,...]
*
* @param array $array the array to count/replace with '?'
* @param string $glue optional glue to use on the returned string (default ',');
* @return string
*/
public static function generateQs($array,$glue=",") {
$qarr = array_fill(0,count($array),"?");
return implode($glue,$qarr);
}
public static function fromVtigerConfig($configIncPhpFile,$static=true,$options=[]) {
$configFile = new File(["path"=>$configIncPhpFile]);
$lineFilter = function($line) {
if(preg_match('/^\$dbconfig/', $line)) {
return $line;
}
};
$dbconfig = [];
$data = $configFile->content(["lineFilter"=>$lineFilter]);
try {
eval($data);
} catch (\Exception $e) {
return false;
}
$config = [
'dbtype'=>'mysql',
"dbhost"=>$dbconfig['db_server'],
"dbport"=>dhGlobal::trimString(":",$dbconfig['db_port'],dhGlobal::TRIM_START),
"dbuser"=>$dbconfig['db_username'],
"dbpass"=>$dbconfig['db_password'],
"dbname"=>$dbconfig['db_name'],
];
if($static) {
static::$instance = new self($config);
return static::$instance;
}
return new self($config);
}
public static function parse($queryString,$opts=[]) {
$parser = new Parser($queryString);
$options = [];
if(isset($opts["params"])) {
$options["constantAsQuestionMark"]=true;
}
if(isset($opts["part"])) {
$options["part"] = $opts["part"];
}
if(isset($opts["array"])) {
return $parser->toArray($options);
}
return $parser->toSql($options);
}
} src/parser/SQLParserWrapper.php 0000644 00000011657 14476160707 0012543 0 ustar 00 parser = new \PHPSQLParser\PHPSQLParser();
$this->creator = new \PHPSQLParser\PHPSQLCreator();
if(!empty($options)) {
$this->setOptions($options);
}
if(!is_null($query)) {
$this->setQuery($query);
$this->parse();
}
}
public function setQuery($query) {
$this->query = $query;
$this->parse();
return $this;
}
public function setOptions($options=[],$merge=true) {
if($merge) {
$this->options = array_merge($this->options,$options);
} else {
$this->options = $options;
}
return $this;
}
public function parse($sql=null,$options=[]) {
if(!is_null($sql)) {
$this->setQuery($sql);
}
if(!empty($options)) {
$this->setOptions($options);
}
$this->parser->parse($this->query, true);
$this->parsed = $this->parser->parsed;
return $this;
}
public function jsonSerialize() {
return $this->parsed;
}
public function __toString() {
return json_encode($this->parsed,JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES);
}
public function get($key=null,$default=null) {
if(is_null($key)) {
return $this->parsed;
}
if(isset($this->parsed[$key])) {
return $this->parsed[$key];
}
return dhGlobal::getDot($this->parsed,$key,$default);
}
public function set($key,$value) {
dhGlobal::dotAssign($this->parsed,$key,$value);
return $this;
}
public function getQuery() {
return $this->query;
}
public function getSelect($asSql=false) {
$part = $this->get('SELECT',false);
if($asSql) {
return $this->toQuery(["SELECT"=>$part]);
}
return $part;
}
public function getFrom($asSql=false) {
$part = $this->get('FROM',false);
if($asSql) {
return $this->toQuery(["FROM"=>$part]);
}
return $part;
}
public function getWhere($asSql=false) {
$part = $this->get('WHERE',false);
if($asSql) {
return $this->toQuery(["WHERE"=>$part]);
}
return $part;
}
public function getGroupBy($asSql=false) {
$part = $this->get('GROUP',false);
if($asSql) {
return $this->toQuery(["GROUP"=>$part]);
}
return $part;
}
public function getOrderBy($asSql=false) {
$part = $this->get('ORDER',false);
if($asSql) {
return $this->toQuery(["ORDER"=>$part]);
}
return $part;
}
public function toQuery($partArray=null) {
if(is_null($partArray)) {
$partArray = $this->parsed;
}
$sql = "";
try {
$sql = $this->creator->create($partArray);
} catch (UnsupportedFeatureException $e) {
$partType = key($partArray);
try {
$sql = $this->partQuery($partType,$partArray);
} catch (\Exception $e) {
throw new \Exception("Unsupported: ".$e->getMessage());
}
}
return $sql;
}
public function partQuery($partType,$partArray) {
$partValue = $partArray[$partType];
$partType = strtolower($partType);
if($partType == "select") {
$builder = new \PHPSQLParser\builders\SelectStatementBuilder();
} elseif($partType == "from") {
$builder = new \PHPSQLParser\builders\FromBuilder();
} elseif($partType == "where") {
$builder = new \PHPSQLParser\builders\WhereBuilder();
} elseif($partType == "group") {
$builder = new \PHPSQLParser\builders\GroupByBuilder();
} elseif($partType == "order") {
$builder = new \PHPSQLParser\builders\OrderByBuilder();
} elseif($partType == "limit") {
$builder = new \PHPSQLParser\builders\LimitBuilder();
} elseif($partType == "having") {
$builder = new \PHPSQLParser\builders\HavingBuilder();
} elseif($partType == "union") {
$builder = new \PHPSQLParser\builders\UnionStatementBuilder();
} elseif($partType == "union all") {
$builder = new \PHPSQLParser\builders\UnionAllStatementBuilder();
} else {
throw new \Exception("Unknown part type: ".$partType);
}
return $builder->build($partValue);
}
} src/parser/expr/BracketExpression.php 0000644 00000001045 14476160707 0013765 0 ustar 00 $this->expressionName(),
"subTree"=>$this->subTree($options),
];
}
public function toSql($options=[],&$params=null) {
$subTreeSql = $this->subTreeSql($options,$params);
return "(" . implode(" ",$subTreeSql) . ")";
}
} src/parser/expr/ColumnExpression.php 0000644 00000003615 14476160707 0013654 0 ustar 00 get("no_quotes")) !== false && count($noQuotes["parts"]) > 1) {
return $noQuotes["parts"][0];
}
return false;
}
public function column() {
if(($noQuotes = $this->get("no_quotes")) !== false) {
if(count($noQuotes["parts"]) > 1) {
return $noQuotes["parts"][1];
} else {
return $noQuotes["parts"][0];
}
}
return $this->get("base_expr");
return false;
}
public function alias() {
$alias = $this->get("alias");
if(is_array($alias) && isset($alias["no_quotes"])) {
return $alias["no_quotes"]["parts"][0];
}
return $this->get("alias");
}
public function getArray($options=[]) {
$return["type"] = $this->expressionName();
if($this->table() !== false) {
$return["table"] = $this->table();
}
$return["column"] = $this->column();
if($this->alias() !== false) {
$return["alias"] = $this->alias();
}
if($this->subTree($options) !== false) {
$return["subTree"] = $this->subTree($options);
}
return $return;
}
public function toSql($options=[],&$params=null) {
$return = "";
if($this->table() !== false) {
$return .= "`".$this->table() . "`.";
}
if($this->column() == "*") {
$return .= "*";
return $return;
}
$return .= "`".$this->column()."`";
if($this->alias() !== false) {
$return .= " AS " . $this->alias();
}
return $return;
}
} src/parser/expr/ConstantExpression.php 0000644 00000001762 14476160707 0014211 0 ustar 00 get("base_expr");
}
public function getArray($options=[]) {
$return["type"] = $this->expressionName();
if(isset($options["constantAsQuestionMark"]) && $options["constantAsQuestionMark"] === true) {
$return["constant"] = "?";
} else {
$return["constant"] = $this->constant();
}
if($this->subTree($options) !== false) {
$return["subTree"] = $this->subTree($options);
}
return $return;
}
public function toSql($options=[],&$params=null) {
$params->addParam($this->constant());
if(isset($options["constantAsQuestionMark"]) && $options["constantAsQuestionMark"] === true) {
return "?";
}
return $this->constant();
}
} src/parser/expr/Expression.php 0000644 00000010260 14476160707 0012470 0 ustar 00 $val) {
if(is_array($val) && isset($val["expr_type"])) {
$data[$key] = Expression::fromArray($val);
} elseif(is_array($val) && dhGlobal::isList($val)) {
$data[$key] = [];
foreach($val as $v) {
if(is_array($v) && isset($v["expr_type"])) {
$data[$key][] = Expression::fromArray($v);
} else {
$data[$key][] = $v;
}
}
}
}
$this->data = new ExpressionData($data);
}
public function get($key=null,$defaultValue=false) {
return $this->data->get($key,$defaultValue);
}
public function set($key,$value=null) {
$this->data->set($key,$value);
return $this;
}
public function expressionName() {
return "Expression";
}
public function exprType() {
return $this->get("expr_type");
}
public function type() {
return $this->get("expr_type");
}
public function baseExpr() {
return $this->get("base_expr");
}
public function base() {
return $this->get("base_expr");
}
public function subTree($options=[]) {
return $this->get("sub_tree");
}
public function position() {
return $this->get("position");
}
public function parts() {
return $this->get("no_quotes");
}
public function subTreeSql($options=[],&$params=null) {
$subTree = $this->subTree($options);
$subTreeSql = [];
if(is_array($subTree) && dhGlobal::isList($subTree)) {
foreach($subTree as $expr) {
$subTreeSql[] = $expr->toSql($options,$params);
}
} else {
$subTreeSql[] = $subTree->toSql($options,$params);
}
return $subTreeSql;
}
public static function fromArray($array) {
if(isset($array["expr_type"])) {
$exprType = $array["expr_type"];
if($exprType == "table") {
return new TableExpression($array);
}
if($exprType == "colref") {
return new ColumnExpression($array);
}
if($exprType == "const") {
return new ConstantExpression($array);
}
if($exprType == "operator") {
return new OperatorExpression($array);
}
if($exprType == "bracket_expression") {
return new BracketExpression($array);
}
if($exprType == "in-list") {
return new InListExpression($array);
}
if($exprType == "function") {
return new FunctionExpression($array);
}
if($exprType == "aggregate_function") {
return new FunctionExpression($array);
}
if($exprType == "reserved") {
return new ReservedExpression($array);
}
return new Expression($array);
} else {
return $array;
}
}
public function getArray($options=[]) {
return $this->data->toArray();
}
public function __toString() {
return json_encode($this->toArray(),JSON_PRETTY_PRINT);
}
public function jsonSerialize() {
return $this->toArray();
}
public function toArray($options=[]) {
$arr = $this->getArray($options);
foreach($arr as $k=>$v) {
if($v instanceof Expression) {
$arr[$k] = $v->toArray($options);
}
}
return $arr;
}
public function toSql($options=[],&$params=null) {
$arr = $this->getArray();
foreach($arr as $k=>$v) {
if($v instanceof Expression) {
$arr[$k] = $v->toSql($options,$params);
}
}
return $arr;
}
} src/parser/expr/ExpressionData.php 0000644 00000003043 14476160707 0013263 0 ustar 00 setFromArray($data);
}
}
public function has($dotKey) {
$val = $this->get($dotKey,"_|xzx|_NOT_SET_|xzx|_");
return $val !== "_|xzx|_NOT_SET_|xzx|_";
}
public function get($key=null,$defaultValue=null) {
if(is_null($key)) {
return $this->toArray(false);
}
if(isset($this->data[$key])) {
return $this->data[$key];
}
return $defaultValue;
}
public function set($key,$value=null) {
if(is_array($key)) {
$this->data=$key;
//dhGlobal::parseDots($this->data);
return $this;
}
dhGlobal::dotAssign($this->data,$key,$value);
return $this;
}
public function toArray() {
return $this->data;
}
public function __toString() {
return json_encode($this->toArray(),JSON_PRETTY_PRINT);
}
public function jsonSerialize() {
return $this->toArray();
}
public function setFromArray($array) {
if(is_object($array) && method_exists($array,"toArray")) {
$array = $array->toArray();
}
if(empty($array)) { return false; }
$this->data = $array;
//dhGlobal::parseDots($this->data);
return $this;
}
} src/parser/expr/FunctionExpression.php 0000644 00000001446 14476160707 0014204 0 ustar 00 get("base_expr");
}
public function getArray($options=[]) {
$return = [
"type"=>$this->expressionName(),
"func"=>$this->func(),
];
if($this->subTree($options) !== false) {
$return["subTree"] = $this->subTree($options);
}
return $return;
}
public function toSql($options=[],&$params=null) {
$subTreeSql = $this->subTreeSql($options,$params);
$return = $this->func() . "(". implode(",",$subTreeSql) .")";
return $return;
}
} src/parser/expr/InListExpression.php 0000644 00000001005 14476160707 0013610 0 ustar 00 $this->expressionName(),
"subTree"=>$this->subTree($options),
];
}
public function toSql($options=[],&$params=null) {
$subTreeSql = $this->subTreeSql($options,$params);
return "(" . implode(",",$subTreeSql) . ")";
}
} src/parser/expr/OperatorExpression.php 0000644 00000001213 14476160707 0014202 0 ustar 00 get("base_expr");
}
public function getArray($options=[]) {
$return = [
"type"=>$this->expressionName(),
"operator"=>$this->operator(),
];
if($this->subTree() !== false) {
$return["subTree"] = $this->subTree();
}
return $return;
}
public function toSql($options=[],&$params=null) {
return $this->operator();
}
} src/parser/expr/Params.php 0000644 00000000470 14476160707 0011556 0 ustar 00 data = [];
}
public function addParam($param) {
$this->data[] = $param;
}
public function get($options=[]) {
return $this->data;
}
} src/parser/expr/ReservedExpression.php 0000644 00000001015 14476160707 0014166 0 ustar 00 get("base_expr");
}
public function getArray($options=[]) {
$return["type"] = $this->expressionName();
$return["constant"] = $this->reserved();
return $return;
}
public function toSql($options=[],&$params=null) {
return $this->reserved();
}
} src/parser/expr/TableExpression.php 0000644 00000007163 14476160707 0013450 0 ustar 00 get("no_quotes")) !== false) {
return $noQuotes["parts"][0];
}
return $this->get("table");
}
public function alias() {
$alias = $this->get("alias");
if(is_array($alias) && isset($alias["no_quotes"])) {
return $alias["no_quotes"]["parts"][0];
}
return $this->get("alias");
}
public function hints() {
return $this->get("hints");
}
public function joinType() {
return $this->get("join_type");
}
public function refType() {
return $this->get("ref_type");
}
/**
* @return Expression|Expression[]|false
*/
public function refClause() {
return $this->get("ref_clause");
}
public function refClauseSql($options=[],&$params=null) {
$refClause = $this->refClause();
$refClauseSql = [];
if(is_array($refClause) && dhGlobal::isList($refClause)) {
foreach($refClause as $expr) {
$refClauseSql[] = $expr->toSql($options,$params);
}
} else {
$refClauseSql[] = $refClause->toSql($options,$params);
}
return $refClauseSql;
}
private function joinTypeSql() {
if($this->refType() === false) {
return;
}
switch($this->joinType()) {
case "LEFT":
return "LEFT JOIN";
case "RIGHT":
return "RIGHT JOIN";
case "INNER":
case "JOIN":
return "INNER JOIN";
case "CROSS":
return "CROSS JOIN";
case "STRAIGHT":
return "STRAIGHT_JOIN";
case "NATURAL":
return "NATURAL JOIN";
default:
return "JOIN";
}
}
public function getArray($options=[]) {
$return = [
"type"=>$this->expressionName(),
"table"=>$this->table(),
];
if($this->alias() !== false) {
$return["alias"] = $this->alias();
}
if($this->hints() !== false) {
$return["hints"] = $this->hints();
}
if($this->joinType() !== false) {
$return["joinType"] = $this->joinType();
}
if($this->refType() !== false) {
$return["refType"] = $this->refType();
}
if($this->refClause() !== false) {
$return["refClause"] = $this->refClause();
}
if($this->subTree() !== false) {
$return["subTree"] = $this->subTree();
}
return $return;
}
public function toSql($options=[],&$params=null) {
$parts = [];
if($this->joinType() !== false && $this->refType() !== false) {
$parts[] = $this->joinTypeSql();
}
$parts[] = "`".$this->table()."`";
if($this->alias() !== false) {
$parts[] = "AS " . $this->alias();
}
if($this->hints() !== false) {
$parts[] = $this->hints();
}
if($this->refType() !== false) {
$parts[] = $this->refType();
}
if($this->refClause() !== false) {
$refClauseSql = $this->refClauseSql($options,$params);
$parts[] = implode(" ",$refClauseSql);
}
return implode(" ",$parts);
}
}