Compare commits

..

4 Commits

Author SHA1 Message Date
Clemens Schwaighofer
e9c791c164 Add better error reporting to DB\IO for query with params
On error with query with params the query was sent to the server and
if ther query itself is ok but there is a problem with the parameters
a wrong error message ($1 not found) will be returned

Add pg_last_error reporting to catch this too.

Update both error reporting to return not string and prefix combined
but prefix + error string in array

In error return check that both strings are not equal, so we do not
return the same error string twice.

Also default set dbh variable in the PgSQL class to false so it will
skip last error report if there is no dbh set yet.

Bug fix for db query with params debug output. if there are more than 9
entries the $1 of eg $10 is replaced with $1 entry again. Changed to
'#' instead '$' to avoid this.

Other:
ACL\Login: replace EOM with HTML
config.master: replace list() with []
Add single DB tester where we can test single db calls without adding
more to the general test run
2023-05-18 15:20:36 +09:00
Clemens Schwaighofer
c7ec1300b7 Published: v8.3.1 2023-04-26 15:43:11 +09:00
Clemens Schwaighofer
064710324e Bug fix in arraySearchKey path reset 2023-04-26 15:41:56 +09:00
Clemens Schwaighofer
e0356dcadf Release: v8.3.0 2023-04-26 14:56:11 +09:00
7 changed files with 100 additions and 49 deletions

View File

@@ -1 +1 @@
8.2.2 8.3.1

View File

@@ -1608,7 +1608,7 @@ class Login
// TODO: submit or JS to set target page as ajax call // TODO: submit or JS to set target page as ajax call
// NOTE: for the HTML block I ignore line lengths // NOTE: for the HTML block I ignore line lengths
// phpcs:disable // phpcs:disable
$this->login_template['password_change'] = <<<EOM $this->login_template['password_change'] = <<<HTML
<div id="pw_change_div" class="hidden" style="position: absolute; top: 30px; left: 50px; width: 400px; height: 220px; background-color: white; border: 1px solid black; padding: 25px;"> <div id="pw_change_div" class="hidden" style="position: absolute; top: 30px; left: 50px; width: 400px; height: 220px; background-color: white; border: 1px solid black; padding: 25px;">
<table> <table>
<tr><td class="norm" align="center" colspan="2"><h3>{TITLE_PASSWORD_CHANGE}</h3></td></tr> <tr><td class="norm" align="center" colspan="2"><h3>{TITLE_PASSWORD_CHANGE}</h3></td></tr>
@@ -1626,7 +1626,7 @@ class Login
</table> </table>
</div> </div>
{PASSWORD_CHANGE_SHOW} {PASSWORD_CHANGE_SHOW}
EOM; HTML;
// phpcs:enable // phpcs:enable
} }
if ($this->password_forgot) { if ($this->password_forgot) {
@@ -1650,7 +1650,7 @@ EOM;
// now check templates // now check templates
// TODO: submit or JS to set target page as ajax call // TODO: submit or JS to set target page as ajax call
if (!$this->login_template['template']) { if (!$this->login_template['template']) {
$this->login_template['template'] = <<<EOM $this->login_template['template'] = <<<HTML
<!DOCTYPE html> <!DOCTYPE html>
<html lang="{LANGUAGE}"> <html lang="{LANGUAGE}">
<head> <head>
@@ -1712,7 +1712,7 @@ h3 { font-size: 18px; }
</form> </form>
</body> </body>
</html> </html>
EOM; HTML;
} }
} }

View File

@@ -208,7 +208,9 @@ class ArrayHandler
$prev_depth = 0; $prev_depth = 0;
foreach ($recursive as $key => $value) { foreach ($recursive as $key => $value) {
if ($prev_depth > $recursive->getDepth()) { if ($prev_depth > $recursive->getDepth()) {
$key_path = []; // remove all trailing to ne depth
$diff = $prev_depth - $recursive->getDepth();
array_splice($key_path, -$diff, $diff);
} }
$prev_depth = $recursive->getDepth(); $prev_depth = $recursive->getDepth();
if ($flat === false) { if ($flat === false) {

View File

@@ -735,7 +735,10 @@ class IO
*/ */
private function __dbErrorPreprocessor(\PgSql\Result|false $cursor = false): array private function __dbErrorPreprocessor(\PgSql\Result|false $cursor = false): array
{ {
$pg_error_string = ''; $db_prefix = '';
$db_error_string = '';
$db_prefix_last = '';
$db_error_string_last = '';
// 1 = self/__dbErrorPreprocessor, 2 = __dbError, __dbWarning, // 1 = self/__dbErrorPreprocessor, 2 = __dbError, __dbWarning,
// 3+ == actual source // 3+ == actual source
// loop until we get a null, build where called chain // loop until we get a null, build where called chain
@@ -749,16 +752,31 @@ class IO
if ($where_called === null) { if ($where_called === null) {
$where_called = '[Unknown Method]'; $where_called = '[Unknown Method]';
} }
[$db_prefix_last, $db_error_string_last] = $this->db_functions->__dbPrintLastError();
if ($cursor !== false) { if ($cursor !== false) {
$pg_error_string = $this->db_functions->__dbPrintError($cursor); [$db_prefix, $db_error_string] = $this->db_functions->__dbPrintError($cursor);
} }
if ($cursor === false && method_exists($this->db_functions, '__dbPrintError')) { if ($cursor === false && method_exists($this->db_functions, '__dbPrintError')) {
$pg_error_string = $this->db_functions->__dbPrintError(); [$db_prefix, $db_error_string] = $this->db_functions->__dbPrintError();
} }
if ($pg_error_string) { // prefix the master if not the same
$this->__dbDebug('db', $pg_error_string, 'DB_ERROR', $where_called); if (
!empty($db_error_string_last) &&
trim($db_error_string) != trim($db_error_string_last)
) {
$db_error_string =
$db_prefix_last . ' ' . $db_error_string_last . ';'
. $db_prefix . ' ' . $db_error_string;
} elseif (!empty($db_error_string)) {
$db_error_string = $db_prefix . ' ' . $db_error_string;
} }
return [$where_called, $pg_error_string]; if ($db_error_string) {
$this->__dbDebug('db', $db_error_string, 'DB_ERROR', $where_called);
}
return [
$where_called,
$db_error_string
];
} }
/** /**
@@ -902,11 +920,14 @@ class IO
// because the placeholders start with $ and at 1, // because the placeholders start with $ and at 1,
// we need to increase each key and prefix it with a $ char // we need to increase each key and prefix it with a $ char
for ($i = 0, $iMax = count($keys); $i < $iMax; $i++) { for ($i = 0, $iMax = count($keys); $i < $iMax; $i++) {
$keys[$i] = '$' . ($keys[$i] + 1); // note: if I use $ here, the str_replace will
// replace it again. eg $11 '$1'1would be replaced with $1 again
// prefix data set with parameter pos // prefix data set with parameter pos
$data[$i] = $keys[$i] . ':' . ($data[$i] === null ? $data[$i] = '#' . ($keys[$i] + 1) . ':' . ($data[$i] === null ?
'"NULL"' : (string)$data[$i] '"NULL"' : (string)$data[$i]
); );
// search part
$keys[$i] = '$' . ($keys[$i] + 1);
} }
// simply replace the $1, $2, ... with the actual data and return it // simply replace the $1, $2, ... with the actual data and return it
return str_replace( return str_replace(

View File

@@ -209,10 +209,17 @@ interface SqlFunctions
/** /**
* Undocumented function * Undocumented function
* *
* @param \PgSql\Result|false $cursor * @return array{0:string,1:string}
* @return string
*/ */
public function __dbPrintError(\PgSql\Result|false $cursor = false): string; public function __dbPrintLastError(): array;
/**
* Undocumented function
*
* @param \PgSql\Result|false $cursor
* @return array{0:string,1:string}
*/
public function __dbPrintError(\PgSql\Result|false $cursor = false): array;
/** /**
* Undocumented function * Undocumented function

View File

@@ -61,7 +61,7 @@ class PgSQL implements Interface\SqlFunctions
/** @var string */ /** @var string */
private $last_error_query; private $last_error_query;
/** @var \PgSql\Connection|false */ /** @var \PgSql\Connection|false */
private $dbh; private $dbh = false;
/** /**
* queries last error query and returns true or false if error was set * queries last error query and returns true or false if error was set
@@ -532,18 +532,37 @@ class PgSQL implements Interface\SqlFunctions
return $this->dbh; return $this->dbh;
} }
/**
* Returns last error for active cursor
*
* @return array{0:string,1:string} prefix, error string
*/
public function __dbPrintLastError(): array
{
if (is_bool($this->dbh)) {
return ['', ''];
}
if (!empty($error_message = pg_last_error($this->dbh))) {
return [
'-PostgreSQL-Error-Last-',
$error_message
];
}
return ['', ''];
}
/** /**
* reads the last error for this cursor and returns * reads the last error for this cursor and returns
* html formatted string with error name * html formatted string with error name
* *
* @param \PgSql\Result|false $cursor cursor * @param \PgSql\Result|false $cursor cursor
* or null * or null
* @return string error string * @return array{0:string,1:string} prefix, error string
*/ */
public function __dbPrintError(\PgSql\Result|false $cursor = false): string public function __dbPrintError(\PgSql\Result|false $cursor = false): array
{ {
if (is_bool($this->dbh)) { if (is_bool($this->dbh)) {
return ''; return ['', ''];
} }
// run the query again for the error result here // run the query again for the error result here
if ((is_bool($cursor)) && $this->last_error_query) { if ((is_bool($cursor)) && $this->last_error_query) {
@@ -552,10 +571,12 @@ class PgSQL implements Interface\SqlFunctions
$cursor = pg_get_result($this->dbh); $cursor = pg_get_result($this->dbh);
} }
if ($cursor && $error_str = pg_result_error($cursor)) { if ($cursor && $error_str = pg_result_error($cursor)) {
return '-PostgreSQL-Error- ' return [
. $error_str; '-PostgreSQL-Error-',
$error_str
];
} else { } else {
return ''; return ['', ''];
} }
} }

View File

@@ -156,7 +156,7 @@ final class CoreLibsDBIOTest extends TestCase
$db->dbExec("DROP TABLE test_meta"); $db->dbExec("DROP TABLE test_meta");
} }
// uid is for internal reference tests // uid is for internal reference tests
$base_table = <<<EOM $base_table = <<<SQL
uid VARCHAR, uid VARCHAR,
row_int INT, row_int INT,
row_numeric NUMERIC, row_numeric NUMERIC,
@@ -172,36 +172,36 @@ final class CoreLibsDBIOTest extends TestCase
row_array_varchar VARCHAR ARRAY row_array_varchar VARCHAR ARRAY
) )
WITHOUT OIDS WITHOUT OIDS
EOM; SQL;
// create the tables // create the tables
$db->dbExec( $db->dbExec(
// primary key name is table + '_id' // primary key name is table + '_id'
<<<EOM <<<SQL
CREATE TABLE table_with_primary_key ( CREATE TABLE table_with_primary_key (
table_with_primary_key_id SERIAL PRIMARY KEY, table_with_primary_key_id SERIAL PRIMARY KEY,
$base_table $base_table
EOM SQL
/* "CREATE TABLE table_with_primary_key (" /* "CREATE TABLE table_with_primary_key ("
// primary key name is table + '_id' // primary key name is table + '_id'
. "table_with_primary_key_id SERIAL PRIMARY KEY, " . "table_with_primary_key_id SERIAL PRIMARY KEY, "
. $base_table */ . $base_table */
); );
$db->dbExec( $db->dbExec(
<<<EOM <<<SQL
CREATE TABLE table_without_primary_key ( CREATE TABLE table_without_primary_key (
$base_table $base_table
EOM SQL
/* "CREATE TABLE table_without_primary_key (" /* "CREATE TABLE table_without_primary_key ("
. $base_table */ . $base_table */
); );
// create simple table for meta test // create simple table for meta test
$db->dbExec( $db->dbExec(
<<<EOM <<<SQL
CREATE TABLE test_meta ( CREATE TABLE test_meta (
row_1 VARCHAR, row_1 VARCHAR,
row_2 INT row_2 INT
) WITHOUT OIDS ) WITHOUT OIDS
EOM SQL
/* "CREATE TABLE test_meta (" /* "CREATE TABLE test_meta ("
. "row_1 VARCHAR, " . "row_1 VARCHAR, "
. "row_2 INT" . "row_2 INT"
@@ -1342,10 +1342,10 @@ final class CoreLibsDBIOTest extends TestCase
'has default' => false, 'has default' => false,
'array dims' => 0, 'array dims' => 0,
'is enum' => false, 'is enum' => false,
'is base' => 1, 'is base' => true,
'is composite' => false, 'is composite' => false,
'is pesudo' => false,
'description' => '', 'description' => '',
'is pseudo' => false
], ],
'row_2' => [ 'row_2' => [
'num' => 2, 'num' => 2,
@@ -1355,10 +1355,10 @@ final class CoreLibsDBIOTest extends TestCase
'has default' => false, 'has default' => false,
'array dims' => 0, 'array dims' => 0,
'is enum' => false, 'is enum' => false,
'is base' => 1, 'is base' => true,
'is composite' => false, 'is composite' => false,
'is pesudo' => false,
'description' => '', 'description' => '',
'is pseudo' => false
] ]
] ]
], ],
@@ -1374,10 +1374,10 @@ final class CoreLibsDBIOTest extends TestCase
'has default' => false, 'has default' => false,
'array dims' => 0, 'array dims' => 0,
'is enum' => false, 'is enum' => false,
'is base' => 1, 'is base' => true,
'is composite' => false, 'is composite' => false,
'is pesudo' => false,
'description' => '', 'description' => '',
'is pseudo' => false
], ],
'row_2' => [ 'row_2' => [
'num' => 2, 'num' => 2,
@@ -1387,10 +1387,10 @@ final class CoreLibsDBIOTest extends TestCase
'has default' => false, 'has default' => false,
'array dims' => 0, 'array dims' => 0,
'is enum' => false, 'is enum' => false,
'is base' => 1, 'is base' => true,
'is composite' => false, 'is composite' => false,
'is pesudo' => false,
'description' => '', 'description' => '',
'is pseudo' => false
] ]
] ]
], ],
@@ -4425,16 +4425,16 @@ final class CoreLibsDBIOTest extends TestCase
] ]
] ]
], ],
// same but as EOM // same but as heredoc
'single insert (PK), EOM string' => [ 'single insert (PK), heredoc string' => [
<<<EOM <<<SQL
INSERT INTO table_with_primary_key ( INSERT INTO table_with_primary_key (
row_varchar, row_varchar_literal, row_int, row_date row_varchar, row_varchar_literal, row_int, row_date
) VALUES ( ) VALUES (
'Text', 'Other', 123, '2022-03-01' 'Text', 'Other', 123, '2022-03-01'
) )
RETURNING row_varchar, row_varchar_literal, row_int, row_date RETURNING row_varchar, row_varchar_literal, row_int, row_date
EOM, SQL,
null, null,
null, null,
null, null,
@@ -4529,16 +4529,16 @@ final class CoreLibsDBIOTest extends TestCase
] ]
] ]
], ],
// same as above but as EOM string // same as above but as heredoc string
'single insert (No PK), EOM string' => [ 'single insert (No PK), heredoc string' => [
<<<EOM <<<SQL
INSERT INTO table_without_primary_key ( INSERT INTO table_without_primary_key (
row_varchar, row_varchar_literal, row_int, row_date row_varchar, row_varchar_literal, row_int, row_date
) VALUES ( ) VALUES (
'Text', 'Other', 123, '2022-03-01' 'Text', 'Other', 123, '2022-03-01'
) )
RETURNING row_varchar, row_varchar_literal, row_int, row_date RETURNING row_varchar, row_varchar_literal, row_int, row_date
EOM, SQL,
null, null,
null, null,
null, null,