.gitignore000064400000000060144761607200006537 0ustar00/vendor/ /tests/ composer.lock .vscode/ /src_1/ composer.json000064400000000746144761607200007304 0ustar00{ "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.txt000064400000000311144761607200011700 0ustar00{ "require": { "boru/dhout": "dev-master" }, "repositories": [ { "type": "composer", "url": "https://satis.boruapps.com" } ] }src/Parser.php000064400000021242144761607200007310 0ustar00wrapper = 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->dataArray = []; $this->wrapper->parse($this->query, $this->options); $parsed = $this->wrapper->get(); $isUnion = false; foreach($parsed as $key=>$value) { $key = strtoupper($key); $this->expressions[$key] = []; if($key == "UNION") { foreach($value as $union) { $thing = new self($this->wrapper->toQuery($union),$this->options); $this->expressions[$key][] = $thing; } } else { if(is_numeric($key)) { unset($this->expressions[$key]); foreach($value as $k=>$v) { foreach($v as $expr) { $this->expressions[$k][] = Expression::fromArray($expr); } } } else { 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)) { if(!empty($this->dataArray)) { return $this->dataArray; } foreach($this->expressions as $key=>$value) { $sqlArray[$key] = []; if($key == "UNION") { foreach($value as $unionNum=>$unionParser) { $sqlArray[$key][] = $unionParser->toArray($options); } } else { foreach($value as $expr) { if($expr instanceof Expression) { $sqlArray[$key][] = $expr->toArray($options); } else { $sqlArray[$key][] = $expr; } } } } $this->dataArray = $sqlArray; } 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=null) { if(is_null($params)) { $params = new Params(); } $sqlArray = []; $part = isset($options["part"]) ? $options["part"] : null; if(is_null($part)) { foreach($this->expressions as $key=>$value) { $sqlArray[$key] = []; if($key === "UNION") { foreach($value as $unionNum=>$unionParser) { $unionSql = $unionParser->toSql($options,$params); $sqlArray[$key][] = $unionSql["sql"]; } } else { foreach($value as $expr) { if($expr instanceof Expression) { $sqlArray[$key][] = $expr->toSql($options,$params); } else { $sqlArray[$key][] = $expr; } } } } foreach($sqlArray as $key=>$value) { if($key == "UNION") { $sqlArray[$key] = implode(" UNION ",$value); } else { $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; } } } } if(isset($options["stats"])) { } return ["sql"=>implode(" ",$sqlArray),"params"=>$params->get()]; } public function details($options=[]) { $array = $this->toArray($options); $details = ["tables"=>[],"columns"=>[],"where"=>[]]; if(isset($array["UNION"])) { //$details = array_merge($details,$array["UNION"][0]->details($options)); } else { if(isset($array["FROM"])) { foreach($array["FROM"] as $expr) { if($expr["type"] == "Table") { $details["tables"][] = $expr["table"]; } } } if(isset($array["WHERE"])) { foreach($array["WHERE"] as $expr) { if($expr["type"] == "Column") { if(isset($expr["table"])) { $details["where"][] = $expr["table"].".".$expr["column"]; } else { $details["where"][] = $expr["column"]; } } } } if(isset($array["SELECT"])) { foreach($array["SELECT"] as $expr) { if($expr["type"] == "Column") { if(isset($expr["table"])) { $details["columns"][] = $expr["table"].".".$expr["column"]; } else { $details["columns"][] = $expr["column"]; } } } } } return $details; } public function getTables() { $tables = []; foreach($this->expressions as $key=>$value) { if($key == "FROM") { foreach($value as $expr) { $tables[] = $expr->getTables(); } } } return $tables; } private function keyToSql($key) { $key = strtoupper($key); if($key == "ORDER") { return "ORDER BY"; } return $key; } }src/Query.php000064400000013410144761607200007157 0ustar00rawQueryString = $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.php000064400000047505144761607200007266 0ustar00setTableName($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.php000064400000021151144761607200011375 0ustar00 .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.php000064400000014457144761607200010542 0ustar00setOptions($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, "logDebug" => $this->logDebug, "printDebug" => $this->printDebug, "includeTrace" => $this->includeTrace, "slowLimit" => $this->slowLimit, "logSlow" => $this->logSlow, "printSlow" => $this->printSlow, "printError" => $this->printError, "logError" => $this->logError, "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 logDebug($logDebug=null) { if(is_null($logDebug)) return $this->logDebug; $this->logDebug = $logDebug; } public function printDebug($printDebug=null) { if(is_null($printDebug)) return $this->printDebug; $this->printDebug = $printDebug; } public function printError($printError=null) { if(is_null($printError)) return $this->printError; $this->printError = $printError; } public function logError($logError=null) { if(is_null($logError)) return $this->logError; $this->logError = $logError; } 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); } $isSlow = $statement->isSlow($this->slowLimit); $isError = $statement->isError(); $shouldLog = $this->shouldLog($isSlow,$isError); $shouldPrint = $this->shouldPrint($isSlow,$isError); $includeTrace = $this->includeTrace || $isError; //should we include the trace? if(empty($statement->getTrace()) && $includeTrace && ($shouldLog || $shouldPrint)) { $statement->setTrace(DebugTrace::getTraceInfo(4,true)); } if($shouldLog) { $this->doLog($statement); } if($shouldPrint) { $this->doPrint($statement); } } private function doLog($statement) { //TODO: log to database //$this->logToTable($statement); } private function doPrint($statement) { 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; } private function shouldLog($isSlow=false,$isError=false) { if($this->logDebug) { return true; } if($this->logSlow && $isSlow) { return true; } if($this->logError && $isError) { return true; } return false; } private function shouldPrint($isSlow=false,$isError=false) { if($this->printDebug) { return true; } if($this->printSlow && $isSlow) { return true; } if($this->printError && $isError) { return true; } return false; } }src/core/Error.php000064400000006061144761607200010077 0ustar00setMessage($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.php000064400000015013144761607200010110 0ustar00config = $config; } public function connected() { return $this->connect(); } 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.php000064400000004672144761607200007563 0ustar00fields = $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.php000064400000015435144761607200010757 0ustar00 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); } $this->endTime = microtime(true); $this->execTime = $this->endTime - $this->startTime; $this->logQuery(); return $this; } private function logQuery() { $this->mysql->getDebugger()->log($this); } public function isSlow($slowTime=1) { return $this->execTime > $slowTime; } public function isError() { return $this->error !== false; } 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 setTrace($trace) { $this->trace = $trace; return $this; } 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\\core\\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.php000064400000041227144761607200012440 0ustar00setQuery($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.php000064400000014617144761607200006665 0ustar00setConfig($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; } } /** * @return Statement */ 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 logDebug($value=null) { return $this->debugger->logDebug($value); } public function printError($value=null) { return $this->debugger->printError($value); } public function logError($value=null) { return $this->debugger->logError($value); } public function printSlow($value=null) { return $this->debugger->printSlow($value); } public function logSlow($value=null) { return $this->debugger->logSlow($value); } public function slowLimit($value=null) { return $this->debugger->slowLimit($value); } public function includeTrace($value=null) { return $this->debugger->includeTrace($value); } public function setDebug($options) { $this->debugger->setOptions($options); return $this; } /** * @return Debugger */ 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]); $fileContent = static::cleanCommentsFromString($configFile->content()); $lines = explode("\n",$fileContent); foreach($lines as $ln=>$line) { if(preg_match('/^\$dbconfig/', $line)) { } else { unset($lines[$ln]); } } $data = implode("\n",$lines); $dbconfig = []; 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); } $data = $parser->toSql($options); if(isset($opts["details"])) { $data["details"] = $parser->details($options); } return $data; } private static function cleanCommentsFromString($string) { if (! defined('T_ML_COMMENT')) { define('T_ML_COMMENT', T_COMMENT); } else { define('T_DOC_COMMENT', T_ML_COMMENT); } $newStr = ''; $commentTokens = [T_COMMENT, T_ML_COMMENT, T_DOC_COMMENT]; $tokens = token_get_all($string); foreach ($tokens as $token) { if (is_array($token)) { if (in_array($token[0], $commentTokens)) { continue; } $token = $token[1]; } $newStr .= $token; } return $newStr; } }src/parser/SQLParserWrapper.php000064400000011660144761607200012530 0ustar00parser = 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, false); $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.php000064400000001045144761607200013760 0ustar00$this->expressionName(), "subTree"=>$this->subTree($options), ]; } public function toSql($options=[],&$params=null) { $subTreeSql = $this->subTreeSql($options,$params); return "(" . implode(" ",$subTreeSql) . ")"; } }src/parser/expr/ColumnExpression.php000064400000003615144761607200013647 0ustar00get("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.php000064400000001762144761607200014204 0ustar00get("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.php000064400000010703144761607200012465 0ustar00$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) || empty($subTree))) { foreach($subTree as $expr) { if(is_object($expr) && $expr instanceof Expression) { $subTreeSql[] = $expr->toSql($options,$params); } } } else { if(is_object($subTree) && $subTree instanceof Expression) { $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); } } if(isset($arr["base_expr"])) { return $arr["base_expr"]; } } }src/parser/expr/ExpressionData.php000064400000003043144761607200013256 0ustar00setFromArray($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.php000064400000001446144761607200014177 0ustar00get("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.php000064400000001005144761607200013603 0ustar00$this->expressionName(), "subTree"=>$this->subTree($options), ]; } public function toSql($options=[],&$params=null) { $subTreeSql = $this->subTreeSql($options,$params); return "(" . implode(",",$subTreeSql) . ")"; } }src/parser/expr/OperatorExpression.php000064400000001213144761607200014175 0ustar00get("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.php000064400000000470144761607200011551 0ustar00data = []; } public function addParam($param) { $this->data[] = $param; } public function get($options=[]) { return $this->data; } }src/parser/expr/ReservedExpression.php000064400000001015144761607200014161 0ustar00get("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.php000064400000007163144761607200013443 0ustar00get("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); } }