hedera-web/rest/core/query.php

190 lines
4.1 KiB
PHP
Raw Normal View History

<?php
2016-07-22 20:00:27 +00:00
use Vn\Lib;
2016-09-23 22:47:34 +00:00
use Vn\Web\Security;
2016-09-26 09:28:47 +00:00
use Vn\Lib\Type;
2016-07-22 20:00:27 +00:00
2018-05-23 10:14:20 +00:00
class Query extends Vn\Web\JsonRequest {
2016-09-06 14:25:02 +00:00
const PARAMS = ['sql'];
2016-09-23 22:47:34 +00:00
const SECURITY = Security::INVOKER;
2020-05-03 20:35:24 +00:00
function __construct($app) {
parent::__construct($app);
$this->utcTz = new DateTimeZone('UTC');
$dbConf = $app->getConf()['db'];
if (isset($dbConf['tz']))
$this->tz = new DateTimeZone($dbConf['tz']);
else
$this->tz = $this->utcTz;
}
2018-05-23 10:14:20 +00:00
function run($db) {
$results = [];
try {
2018-05-23 10:14:20 +00:00
$db->multiQuery($_REQUEST['sql']);
2015-02-08 15:38:38 +00:00
do {
2018-05-23 10:14:20 +00:00
$result = $db->storeResult();
2018-05-23 10:14:20 +00:00
if ($result !== FALSE) {
$results[] = $this->transformResult($result);
$result->free();
2018-05-23 11:09:55 +00:00
} else
$results[] = TRUE;
}
2018-05-23 10:14:20 +00:00
while ($db->moreResults() && $db->nextResult());
2016-09-06 14:25:02 +00:00
2015-08-17 18:02:14 +00:00
// Checks for warnings
2016-09-06 14:25:02 +00:00
2018-05-23 10:14:20 +00:00
if ($db->checkWarnings()
&&($result = $db->query('SHOW WARNINGS'))) {
2017-12-20 11:34:04 +00:00
$sql = 'SELECT `description`, @warn `code`
FROM `message` WHERE `code` = @warn';
2015-08-17 18:02:14 +00:00
2018-05-23 10:14:20 +00:00
while ($row = $result->fetch_object()) {
2017-12-20 11:34:04 +00:00
if ($row->Code == 1265
2018-05-23 10:14:20 +00:00
&&($warning = $db->getObject($sql)))
trigger_error("{$warning->code}: {$warning->description}", E_USER_WARNING);
2015-08-17 18:02:14 +00:00
else
2018-05-23 10:14:20 +00:00
trigger_error("{$row->Code}: {$row->Message}", E_USER_WARNING);
2015-08-17 18:02:14 +00:00
}
}
2016-09-06 14:25:02 +00:00
2015-08-17 18:02:14 +00:00
// Checks for errors
2018-05-23 10:14:20 +00:00
$db->checkError();
2018-05-23 11:09:55 +00:00
} catch (Vn\Db\Exception $e) {
2018-05-23 10:14:20 +00:00
if ($e->getCode() == 1644) {
$dbMessage = $e->getMessage();
2017-12-20 11:34:04 +00:00
$sql = 'SELECT `description` FROM `message` WHERE `code` = #';
2018-05-23 10:14:20 +00:00
$message = $db->getValue($sql, [$dbMessage]);
2015-08-17 18:02:14 +00:00
2017-05-02 12:33:48 +00:00
if ($message)
2018-05-23 10:14:20 +00:00
throw new Lib\UserException($message, $dbMessage);
2015-08-17 18:02:14 +00:00
}
2017-05-02 12:33:48 +00:00
throw $e;
}
return $results;
}
2016-09-06 14:25:02 +00:00
/**
2016-09-20 18:36:22 +00:00
* Transforms the database result into a JSON parseable object.
2016-09-06 14:25:02 +00:00
**/
2018-05-23 10:14:20 +00:00
function transformResult($result) {
2016-09-06 14:25:02 +00:00
$tableMap = [];
2018-05-23 10:14:20 +00:00
$columns = $result->fetch_fields();
2016-09-06 14:25:02 +00:00
$resultMap =
[
'data' => [],
'columns' => [],
'tables' => []
];
2015-02-17 11:48:53 +00:00
2018-05-23 10:14:20 +00:00
for ($i = 0; $i < $result->field_count; $i++) {
2016-09-06 14:25:02 +00:00
$column = $columns[$i];
2018-05-23 10:14:20 +00:00
switch ($column->type) {
2016-09-06 14:25:02 +00:00
case MYSQLI_TYPE_BIT:
2016-09-26 09:28:47 +00:00
$type = Type::BOOLEAN;
2016-09-06 14:25:02 +00:00
break;
case MYSQLI_TYPE_TINY:
case MYSQLI_TYPE_SHORT:
case MYSQLI_TYPE_LONG:
case MYSQLI_TYPE_LONGLONG:
case MYSQLI_TYPE_INT24:
case MYSQLI_TYPE_YEAR:
2016-09-26 09:28:47 +00:00
$type = Type::INTEGER;
2016-09-06 14:25:02 +00:00
break;
case MYSQLI_TYPE_FLOAT:
case MYSQLI_TYPE_DOUBLE:
case MYSQLI_TYPE_DECIMAL:
case MYSQLI_TYPE_NEWDECIMAL:
2016-09-26 09:28:47 +00:00
$type = Type::DOUBLE;
2016-09-06 14:25:02 +00:00
break;
case MYSQLI_TYPE_DATE:
2016-09-26 09:28:47 +00:00
$type = Type::DATE;
2016-09-06 14:25:02 +00:00
break;
case MYSQLI_TYPE_DATETIME:
case MYSQLI_TYPE_TIMESTAMP:
2016-09-26 09:28:47 +00:00
$type = Type::DATE_TIME;
2016-09-06 14:25:02 +00:00
break;
default;
2016-09-26 09:28:47 +00:00
$type = Type::STRING;
2016-09-06 14:25:02 +00:00
}
2018-05-23 10:14:20 +00:00
if (!isset($tableMap[$column->table])) {
2016-09-06 14:25:02 +00:00
$resultMap['tables'][] =
[
'name' => $column->table,
'orgname' => $column->orgtable,
'schema' => $column->db,
'pks' => []
];
2018-05-23 10:14:20 +00:00
$tableIndex = count($resultMap['tables']) - 1;
2016-09-06 14:25:02 +00:00
$tableMap[$column->table] = $tableIndex;
2018-05-23 11:09:55 +00:00
} else
2016-09-06 14:25:02 +00:00
$tableIndex = $tableMap[$column->table];
if ($column->flags & MYSQLI_PRI_KEY_FLAG)
$resultMap['tables'][$tableIndex]['pks'][] = $i;
2018-05-23 10:14:20 +00:00
$default = $this->castValue($column->def, $type);
2016-09-06 14:25:02 +00:00
$resultMap['columns'][] =
[
'type' => $type,
'flags' => $column->flags,
'def' => $default,
'name' => $column->name,
'orgname' => $column->orgname,
'table' => $tableIndex
];
}
$columns = $resultMap['columns'];
2018-05-23 10:14:20 +00:00
while ($row = $result->fetch_row()) {
2016-09-06 14:25:02 +00:00
for ($j = 0; $j < $result->field_count; $j++)
2018-05-23 10:14:20 +00:00
$row[$j] = $this->castValue($row[$j], $columns[$j]['type']);
2016-09-06 14:25:02 +00:00
$resultMap['data'][] = $row;
}
return $resultMap;
}
/**
* Transforms the database value into a JSON parseable value.
**/
2018-05-23 10:14:20 +00:00
function castValue($value, $type) {
2020-05-04 19:55:18 +00:00
if ($value === '' && $type != Type::STRING)
2020-05-03 20:35:24 +00:00
$value = NULL;
2020-05-04 19:55:18 +00:00
if ($value !== NULL)
2018-05-23 10:14:20 +00:00
switch ($type) {
2016-09-26 09:28:47 +00:00
case Type::BOOLEAN:
return (bool) $value;
case Type::INTEGER:
return (int) $value;
case Type::DOUBLE:
return (float) $value;
2020-05-03 20:35:24 +00:00
case Type::DATE:
case Type::DATE_TIME:
$d = new DateTime($value, $this->tz);
$d->setTimeZone($this->utcTz);
return $d->format('Y-m-d\TH:i:s.v\Z');
2015-02-17 11:48:53 +00:00
break;
}
2016-09-26 09:28:47 +00:00
return $value;
2015-02-17 11:48:53 +00:00
}
2016-09-06 14:25:02 +00:00
}