DB\IO Class updates, other Class fixes

Output\Form\Generate and ACL\Login have DB\IO method call name changes
for pos/num rows methods. Use proper methods and not use the cursor full
return check method

DB\IO:
Switched to new conenction busy check with sockt and timeout loop. So
short blocked and psql error blocked ones are not blocking other calls.

Moved the dbReturn cache read to a separte private method and cleaned up
code for more clear view

Moved all query hash creations to method to simple change hash creatio
if needed. This method can be used for external correct query hash
creation if needed.

Variable name and code block clean up in dbReturn

No data return (dbReturn or dbFetchArray) will change returned data row.
Return as is.

Moved methods around in code to group them together for next stage in
sub class creation (planned)

Renamed dbCursorPos to dbGetCursorPos
and dbCursorNumRows to dbGetCursorNumRows

Work on phpunit tests for DB\IO
This commit is contained in:
Clemens Schwaighofer
2022-03-03 06:31:55 +09:00
parent fe13c24a13
commit 42b961f35e
7 changed files with 889 additions and 239 deletions

View File

@@ -270,6 +270,7 @@ final class CoreLibsDBIOTest extends TestCase
// 0: connection array // 0: connection array
// 1: status after connection // 1: status after connection
// 2: info string // 2: info string
// 3: ???
return [ return [
'invalid connection' => [ 'invalid connection' => [
self::$db_config['invalid'], self::$db_config['invalid'],
@@ -413,18 +414,12 @@ final class CoreLibsDBIOTest extends TestCase
self::$db_config[$connection], self::$db_config[$connection],
self::$log self::$log
); );
if ($set === null) { $this->assertEquals(
// equals to do nothing $expected,
$this->assertEquals( $set === null ?
$expected, $db->dbSetDebug() :
$db->dbSetDebug()
);
} else {
$this->assertEquals(
$expected,
$db->dbSetDebug($set) $db->dbSetDebug($set)
); );
}
// must always match // must always match
$this->assertEquals( $this->assertEquals(
$expected, $expected,
@@ -452,18 +447,12 @@ final class CoreLibsDBIOTest extends TestCase
self::$db_config[$connection], self::$db_config[$connection],
self::$log self::$log
); );
if ($toggle === null) { $this->assertEquals(
// equals to do nothing $expected,
$this->assertEquals( $toggle === null ?
$expected, $db->dbToggleDebug() :
$db->dbToggleDebug()
);
} else {
$this->assertEquals(
$expected,
$db->dbToggleDebug($toggle) $db->dbToggleDebug($toggle)
); );
}
// must always match // must always match
$this->assertEquals( $this->assertEquals(
$expected, $expected,
@@ -557,7 +546,10 @@ final class CoreLibsDBIOTest extends TestCase
); );
$this->assertEquals( $this->assertEquals(
$expected_flag, $expected_flag,
$db->dbSetMaxQueryCall($max_calls) // TODO special test with null call too
$max_calls === null ?
$db->dbSetMaxQueryCall() :
$db->dbSetMaxQueryCall($max_calls)
); );
$this->assertEquals( $this->assertEquals(
$expected_max_calls, $expected_max_calls,
@@ -615,6 +607,7 @@ final class CoreLibsDBIOTest extends TestCase
// 'UTF8' // 'UTF8'
// ], // ],
// other tests includ perhaps mocking for error? // other tests includ perhaps mocking for error?
// TODO actual data check
]; ];
} }
@@ -732,28 +725,33 @@ final class CoreLibsDBIOTest extends TestCase
return [ return [
'source "t" to true' => [ 'source "t" to true' => [
't', 't',
false,
true,
],
'source "t" to true null flag' => [
't',
null,
true, true,
false
], ],
'source "true" to true' => [ 'source "true" to true' => [
'true', 'true',
false,
true, true,
false
], ],
'source "f" to false' => [ 'source "f" to false' => [
'f', 'f',
false, false,
false false,
], ],
'source "false" to false' => [ 'source "false" to false' => [
'false', 'false',
false, false,
false false,
], ],
'source anything to true' => [ 'source anything to true' => [
'something', 'something',
true,
false, false,
true,
], ],
'source empty to false' => [ 'source empty to false' => [
'', '',
@@ -762,13 +760,13 @@ final class CoreLibsDBIOTest extends TestCase
], ],
'source bool true to "t"' => [ 'source bool true to "t"' => [
true, true,
't',
true, true,
't',
], ],
'source bool false to "f"' => [ 'source bool false to "f"' => [
false, false,
'f',
true, true,
'f',
], ],
]; ];
} }
@@ -781,11 +779,11 @@ final class CoreLibsDBIOTest extends TestCase
* @testdox Have $source and convert ($reverse) to $expected [$_dataName] * @testdox Have $source and convert ($reverse) to $expected [$_dataName]
* *
* @param string|bool $source * @param string|bool $source
* @param bool|null $reverse
* @param string|bool $expected * @param string|bool $expected
* @param bool $reverse
* @return void * @return void
*/ */
public function testDbBoolean($source, $expected, bool $reverse): void public function testDbBoolean($source, ?bool $reverse, $expected): void
{ {
$db = new \CoreLibs\DB\IO( $db = new \CoreLibs\DB\IO(
self::$db_config['valid'], self::$db_config['valid'],
@@ -793,7 +791,9 @@ final class CoreLibsDBIOTest extends TestCase
); );
$this->assertEquals( $this->assertEquals(
$expected, $expected,
$db->dbBoolean($source, $reverse) $reverse === null ?
$db->dbBoolean($source) :
$db->dbBoolean($source, $reverse)
); );
$db->dbClose(); $db->dbClose();
} }
@@ -818,6 +818,11 @@ final class CoreLibsDBIOTest extends TestCase
false, false,
'41 years 9 mons 18 days' '41 years 9 mons 18 days'
], ],
'interval a null micro time' => [
'41 years 9 mons 18 days',
null,
'41 years 9 mons 18 days'
],
'interval a-1' => [ 'interval a-1' => [
'41 years 9 mons 18 days 12:31:11', '41 years 9 mons 18 days 12:31:11',
false, false,
@@ -879,11 +884,11 @@ final class CoreLibsDBIOTest extends TestCase
* @testdox Have $source and convert ($show_micro) to $expected [$_dataName] * @testdox Have $source and convert ($show_micro) to $expected [$_dataName]
* *
* @param string $source * @param string $source
* @param bool $show_micro * @param bool|null $show_micro
* @param string $expected * @param string $expected
* @return void * @return void
*/ */
public function testDbTimeFormat(string $source, bool $show_micro, string $expected): void public function testDbTimeFormat(string $source, ?bool $show_micro, string $expected): void
{ {
$db = new \CoreLibs\DB\IO( $db = new \CoreLibs\DB\IO(
self::$db_config['valid'], self::$db_config['valid'],
@@ -891,7 +896,9 @@ final class CoreLibsDBIOTest extends TestCase
); );
$this->assertEquals( $this->assertEquals(
$expected, $expected,
$db->dbTimeFormat($source, $show_micro) $show_micro === null ?
$db->dbTimeFormat($source) :
$db->dbTimeFormat($source, $show_micro)
); );
$db->dbClose(); $db->dbClose();
} }
@@ -1232,6 +1239,38 @@ final class CoreLibsDBIOTest extends TestCase
] ]
] ]
], ],
'simple table null schema' => [
'test_meta',
null,
[
'row_1' => [
'num' => 1,
'type' => 'varchar',
'len' => -1,
'not null' => false,
'has default' => false,
'array dims' => 0,
'is enum' => false,
'is base' => 1,
'is composite' => false,
'is pesudo' => false,
'description' => '',
],
'row_2' => [
'num' => 2,
'type' => 'int4',
'len' => 4,
'not null' => false,
'has default' => false,
'array dims' => 0,
'is enum' => false,
'is base' => 1,
'is composite' => false,
'is pesudo' => false,
'description' => '',
]
]
],
'table does not exist' => [ 'table does not exist' => [
'non_existing', 'non_existing',
'public', 'public',
@@ -1248,11 +1287,11 @@ final class CoreLibsDBIOTest extends TestCase
* @testdox Check table $table in schema $schema with $expected [$_dataName] * @testdox Check table $table in schema $schema with $expected [$_dataName]
* *
* @param string $table * @param string $table
* @param string $schema * @param string|null $schema
* @param array<mixed>|bool $expected * @param array<mixed>|bool $expected
* @return void * @return void
*/ */
public function testDbShowTableMetaData(string $table, string $schema, $expected): void public function testDbShowTableMetaData(string $table, ?string $schema, $expected): void
{ {
$db = new \CoreLibs\DB\IO( $db = new \CoreLibs\DB\IO(
self::$db_config['valid'], self::$db_config['valid'],
@@ -1263,14 +1302,16 @@ final class CoreLibsDBIOTest extends TestCase
$this->assertEquals( $this->assertEquals(
$expected, $expected,
$db->dbShowTableMetaData($table, $schema) $schema === null ?
$db->dbShowTableMetaData($table) :
$db->dbShowTableMetaData($table, $schema)
); );
$db->dbClose(); $db->dbClose();
} }
// - db exec test for insert/update/select/etc // - db exec test for insert/update/select/etc
// dbExec // dbExec, dbResetQueryCalled, dbGetQueryCalled
/** /**
* provide queries with return results * provide queries with return results
@@ -1280,7 +1321,7 @@ final class CoreLibsDBIOTest extends TestCase
public function queryDbExecProvider(): array public function queryDbExecProvider(): array
{ {
// 0: query // 0: query
// 1: optional primary key name // 1: optional primary key name, null for empty test
// 2: expectes result (bool, object (>=8.1)/resource (<8.1)) // 2: expectes result (bool, object (>=8.1)/resource (<8.1))
// 3: warning // 3: warning
// 4: error // 4: error
@@ -1294,6 +1335,14 @@ final class CoreLibsDBIOTest extends TestCase
'', '',
'', '',
], ],
// insert but null primary key
'table with pk insert null' => [
'INSERT INTO table_with_primary_key (row_date) VALUES (NOW())',
null,
'resource/object',
'',
'',
],
// insert to table with no pk (31?) // insert to table with no pk (31?)
'table with no pk insert' => [ 'table with no pk insert' => [
'INSERT INTO table_without_primary_key (row_date) VALUES (NOW())', 'INSERT INTO table_without_primary_key (row_date) VALUES (NOW())',
@@ -1378,6 +1427,7 @@ final class CoreLibsDBIOTest extends TestCase
// NOTE: After an error was encountered, queries after this // NOTE: After an error was encountered, queries after this
// will return a true connection busy although it was error // will return a true connection busy although it was error
// https://bugs.php.net/bug.php?id=36469 // https://bugs.php.net/bug.php?id=36469
// TODO: fix wron error 42 after error insert
'invalid returning' => [ 'invalid returning' => [
'INSERT INTO table_with_primary_key (row_date) VALUES (NOW()) RETURNING invalid', 'INSERT INTO table_with_primary_key (row_date) VALUES (NOW()) RETURNING invalid',
'', '',
@@ -1394,24 +1444,29 @@ final class CoreLibsDBIOTest extends TestCase
* tests (internal read data post exec group) * tests (internal read data post exec group)
* *
* @covers ::dbExec * @covers ::dbExec
* @covers ::dbGetQueryCalled
* @covers ::dbResetQueryCalled
* @dataProvider queryDbExecProvider * @dataProvider queryDbExecProvider
* @testdox dbExec $query and pk $pk_name with $expected_return (Warning: $warning/Error: $error) [$_dataName] * @testdox dbExec $query and pk $pk_name with $expected_return (Warning: $warning/Error: $error) [$_dataName]
* *
* @param string $query * @param string $query
* @param string $pk_name * @param string|null $pk_name
* @param [type] $expected_return * @param object|resource|bool $expected_return
* @param string $warning
* @param string $error
* @param bool $run_many_times
* @return void * @return void
*/ */
public function testDbExec( public function testDbExec(
string $query, string $query,
string $pk_name, ?string $pk_name,
$expected_return, $expected_return,
string $warning, string $warning,
string $error, string $error,
bool $run_many_times = false bool $run_many_times = false
): void { ): void {
self::$log->setLogLevelAll('debug', true); // self::$log->setLogLevelAll('debug', true);
self::$log->setLogLevelAll('print', true); // self::$log->setLogLevelAll('print', true);
$db = new \CoreLibs\DB\IO( $db = new \CoreLibs\DB\IO(
self::$db_config['valid'], self::$db_config['valid'],
self::$log self::$log
@@ -1428,58 +1483,621 @@ final class CoreLibsDBIOTest extends TestCase
$this->assertEquals( $this->assertEquals(
$expected_return, $expected_return,
// supress ANY errors here // supress ANY errors here
@$db->dbExec($query, $pk_name) $pk_name === null ?
@$db->dbExec($query) :
@$db->dbExec($query, $pk_name)
); );
$last_warning = $db->dbGetLastWarning();
$last_error = $db->dbGetLastError();
} else { } else {
// if PHP or newer, must be Object PgSql\Result // if PHP or newer, must be Object PgSql\Result
if (\CoreLibs\Check\PhpVersion::checkPHPVersion('8.1')) { if (\CoreLibs\Check\PhpVersion::checkPHPVersion('8.1')) {
$result = $pk_name === null ?
$db->dbExec($query) :
$db->dbExec($query, $pk_name);
$last_warning = $db->dbGetLastWarning();
$last_error = $db->dbGetLastError();
$this->assertIsObject( $this->assertIsObject(
$db->dbExec($query, $pk_name) $result
); );
// also check that this is correct instance type // also check that this is correct instance type
$this->assertInstanceOf( $this->assertInstanceOf(
'PgSql\Result', 'PgSql\Result',
$db->dbExec($query, $pk_name) $result
); );
} else { } else {
$this->assertIsResource( $this->assertIsResource(
$db->dbExec($query, $pk_name) $pk_name === null ?
$db->dbExec($query) :
$db->dbExec($query, $pk_name)
); );
$last_warning = $db->dbGetLastWarning();
$last_error = $db->dbGetLastError();
} }
} }
// if we have more than one run time // if we have more than one run time
// re-run same query and then catch error // re-run same query and then catch error
if ($run_many_times) { if ($run_many_times) {
for ($i = 1; $i <= $db->dbGetMaxQueryCall() + 1; $i++) { for ($i = 1; $i <= $db->dbGetMaxQueryCall() + 1; $i++) {
$db->dbExec($query, $pk_name); $pk_name === null ?
$db->dbExec($query) :
$db->dbExec($query, $pk_name);
} }
// will fail now // will fail now
$this->assertFalse( $this->assertFalse(
$db->dbExec($query, $pk_name) $pk_name === null ?
$db->dbExec($query) :
$db->dbExec($query, $pk_name)
);
$last_warning = $db->dbGetLastWarning();
$last_error = $db->dbGetLastError();
// check query called matching
$current_count = $db->dbGetQueryCalled($query);
$this->assertEquals(
$db->dbGetMaxQueryCall() + 1,
$current_count
);
// reset query called and check again
$this->assertEquals(
0,
$db->dbResetQueryCalled($query)
); );
} }
// if string for warning or error is not empty check // if string for warning or error is not empty check
$this->assertEquals( $this->assertEquals(
$warning, $warning,
$db->dbGetLastWarning() $last_warning
); );
$this->assertEquals( $this->assertEquals(
$error, $error,
$db->dbGetLastError() $last_error
); );
// reset all data // reset all data
$db->dbExec("TRUNCATE table_with_primary_key"); $db->dbExec("TRUNCATE table_with_primary_key");
$db->dbExec("TRUNCATE table_without_primary_key"); $db->dbExec("TRUNCATE table_without_primary_key");
// close connection
$db->dbClose();
}
// - return one database row
// dbReturnRow
/**
* Undocumented function
*
* @return array
*/
public function returnRowProvider(): array
{
$insert_query = "INSERT INTO table_with_primary_key (row_int, uid) VALUES (1, 'A')";
$read_query = "SELECT row_int, uid FROM table_with_primary_key WHERE uid = 'A'";
// 0: query
// 1: flag (assoc)
// 2: result
// 3: warning
// 4: error
// 5: insert query
return [
'valid select' => [
$read_query,
null,
[
'row_int' => 1,
0 => 1,
'uid' => 'A',
1 => 'A'
],
'',
'',
$insert_query,
],
'valid select, assoc only false' => [
$read_query,
false,
[
'row_int' => 1,
0 => 1,
'uid' => 'A',
1 => 'A'
],
'',
'',
$insert_query,
],
'valid select, assoc only true' => [
$read_query,
true,
[
'row_int' => 1,
'uid' => 'A',
],
'',
'',
$insert_query,
],
'empty select' => [
'',
null,
false,
'',
'11',
$insert_query,
],
'insert query' => [
$insert_query,
null,
false,
'',
'17',
$insert_query
],
// invalid QUERY
];
}
/**
* Undocumented function
*
* @covers ::dbReturnRow
* @dataProvider returnRowProvider
* @testdox dbReturnRow $query and assoc $flag_assoc with $expected (Warning: $warning/Error: $error) [$_dataName]
*
* @param string $query
* @param bool|null $flag_assoc
* @param array<mixed>|bool $expected
* @param string $warning
* @param string $error
* @param string $insert_data
* @return void
*/
public function testDbReturnRow(
string $query,
?bool $flag_assoc,
$expected,
string $warning,
string $error,
string $insert_data,
): void {
// self::$log->setLogLevelAll('debug', true);
// self::$log->setLogLevelAll('print', true);
$db = new \CoreLibs\DB\IO(
self::$db_config['valid'],
self::$log
);
// insert data before we can test, from expected array
$db->dbExec($insert_data);
// compare
$this->assertEquals(
$expected,
$flag_assoc === null ?
$db->dbReturnRow($query) :
$db->dbReturnRow($query, $flag_assoc)
);
// get last error/warnings
$last_warning = $db->dbGetLastWarning();
$last_error = $db->dbGetLastError();
// print "ER: " . $last_error . "/" . $last_warning . "\n";
// if string for warning or error is not empty check
$this->assertEquals(
$warning,
$last_warning
);
$this->assertEquals(
$error,
$last_error
);
// reset all data
$db->dbExec("TRUNCATE table_with_primary_key");
$db->dbExec("TRUNCATE table_without_primary_key");
// close connection
$db->dbClose();
}
// - return all database rows
// dbReturnArray
/**
* Undocumented function
*
* @return array
*/
public function returnArrayProvider(): array
{
$insert_query = "INSERT INTO table_with_primary_key (row_int, uid) VALUES "
. "(1, 'A'), (2, 'B')";
$read_query = "SELECT row_int, uid FROM table_with_primary_key";
// 0: query
// 1: flag (assoc)
// 2: result
// 3: warning
// 4: error
// 5: insert query
return [
'valid select' => [
$read_query,
null,
[
[
'row_int' => 1,
'uid' => 'A',
],
[
'row_int' => 2,
'uid' => 'B',
],
],
'',
'',
$insert_query,
],
'valid select, assoc ' => [
$read_query,
false,
[
[
'row_int' => 1,
0 => 1,
'uid' => 'A',
1 => 'A'
],
[
'row_int' => 2,
0 => 2,
'uid' => 'B',
1 => 'B'
],
],
'',
'',
$insert_query,
],
'empty select' => [
'',
null,
false,
'',
'11',
$insert_query,
],
'insert query' => [
$insert_query,
null,
false,
'',
'17',
$insert_query
],
// invalid QUERY
];
}
/**
* Undocumented function
*
* @covers ::dbReturnArray
* @dataProvider returnArrayProvider
* @testdox dbReturnArray $query and assoc $flag_assoc with $expected (Warning: $warning/Error: $error) [$_dataName]
*
* @param string $query
* @param boolean|null $flag_assoc
* @param array<mixed>|bool $expected
* @param string $warning
* @param string $error
* @param string $insert_data
* @return void
*/
public function testDbReturnArrray(
string $query,
?bool $flag_assoc,
$expected,
string $warning,
string $error,
string $insert_data,
): void {
// self::$log->setLogLevelAll('debug', true);
// self::$log->setLogLevelAll('print', true);
$db = new \CoreLibs\DB\IO(
self::$db_config['valid'],
self::$log
);
// insert data before we can test, from expected array
$db->dbExec($insert_data);
// compare
$this->assertEquals(
$expected,
$flag_assoc === null ?
$db->dbReturnArray($query) :
$db->dbReturnArray($query, $flag_assoc)
);
// get last error/warnings
$last_warning = $db->dbGetLastWarning();
$last_error = $db->dbGetLastError();
// if string for warning or error is not empty check
$this->assertEquals(
$warning,
$last_warning
);
$this->assertEquals(
$error,
$last_error
);
// reset all data
$db->dbExec("TRUNCATE table_with_primary_key");
$db->dbExec("TRUNCATE table_without_primary_key");
// close connection
$db->dbClose();
}
// - loop data return flow
// dbReturn, dbCacheReset, dbCursorPos, dbCursorNumRows, dbGetCursorExt
/**
* Undocumented function
*
* @return array
*/
public function dbReturnProvider(): array
{
$insert_query = "INSERT INTO table_with_primary_key (row_int, uid) VALUES "
. "(1, 'A'), (2, 'B')";
$read_query = "SELECT row_int, uid FROM table_with_primary_key";
// 0: read query
// 1: reset flag, null for default
// 2: assoc flag, null for default
// 3: expected return
// 4: read first, read all flag
// 5: read all check array
// 6: warning
// 7: error
// 8: insert data
return [
'valid select' => [
$read_query,
null,
null,
[
'row_int' => 1,
0 => 1,
'uid' => 'A',
1 => 'A'
],
true,
[],
'',
'',
$insert_query
],
'valid select, default cache, assoc only' => [
$read_query,
\CoreLibs\DB\IO::USE_CACHE,
true,
[
'row_int' => 1,
'uid' => 'A',
],
true,
[],
'',
'',
$insert_query
],
'empty select' => [
'',
null,
null,
false,
true,
[],
'',
'11',
$insert_query,
],
'insert query' => [
$insert_query,
null,
null,
false,
true,
[],
'',
'17',
$insert_query
],
// from here on a complex read all full tests
'valid select, full read' => [
$read_query,
null,
null,
[
'row_int' => 1,
0 => 1,
'uid' => 'A',
1 => 'A'
],
false,
[],
'',
'',
$insert_query
],
];
}
/**
* Undocumented function
*
* @covers ::dbReturn
* @covers ::dbCacheReset
* @covers ::dbGetCursorExt
* @covers ::dbCursorPos
* @covers ::dbCursorNumRows
* @dataProvider dbReturnProvider
* @testdox dbReturn $query and cache $flag_cache and assoc $flag_assoc with $expected (Warning: $warning/Error: $error) [$_dataName]
*
* @param string $query
* @param integer|null $flag_cache
* @param boolean|null $flag_assoc
* @param array<mixed>|bool $expected
* @param bool $read_first_only
* @param array $cursor_ext_checks
* @param string $warning
* @param string $error
* @param string $insert_data
* @return void
*/
public function testDbReturn(
string $query,
?int $flag_cache,
?bool $flag_assoc,
$expected,
bool $read_first_only,
array $cursor_ext_checks,
string $warning,
string $error,
string $insert_data,
): void {
// self::$log->setLogLevelAll('debug', true);
// self::$log->setLogLevelAll('print', true);
$db = new \CoreLibs\DB\IO(
self::$db_config['valid'],
self::$log
);
// insert data before we can test, from expected array
$db->dbExec($insert_data);
// all checks below
if ($read_first_only === true) {
// simple assert first read, then discard result
// compare
$this->assertEquals(
$expected,
$flag_cache === null && $flag_assoc === null ?
$db->dbReturn($query) :
($flag_assoc === null ?
$db->dbReturn($query, $flag_cache) :
$db->dbReturn($query, $flag_cache, $flag_assoc)
)
);
// get last error/warnings
$last_warning = $db->dbGetLastWarning();
$last_error = $db->dbGetLastError();
// if string for warning or error is not empty check
$this->assertEquals(
$warning,
$last_warning
);
$this->assertEquals(
$error,
$last_error
);
} else {
// all tests here have valid returns already, error checks not needed
// read all, and then do result compare
// cursor ext data checks (field names, rows, pos, data)
// do cache reset test
$data = [];
$pos = 0;
while (
is_array(
$res = $flag_cache === null && $flag_assoc === null ?
$db->dbReturn($query) :
($flag_assoc === null ?
$db->dbReturn($query, $flag_cache) :
$db->dbReturn($query, $flag_cache, $flag_assoc)
)
)
) {
$data[] = $res;
$pos++;
// check cursor pos
$this->assertEquals(
$pos,
$db->dbGetCursorPos($query)
);
}
// does count match for returned data and the cursor num rows
$this->assertEquals(
count($data),
$db->dbGetCursorNumRows($query)
);
// does data match
// try get cursor data for non existing, must be null
$this->assertNull(
$db->dbGetCursorExt($query, 'nonexistingfield')
);
// does reset data work, query cursor must be null
$db->dbCacheReset($query);
$this->assertNull(
$db->dbGetCursorExt($query)
);
}
// reset all data
$db->dbExec("TRUNCATE table_with_primary_key");
$db->dbExec("TRUNCATE table_without_primary_key");
// close connection
$db->dbClose();
}
// - prepared query execute
// dbPrepare, dbExecute, dbFetchArray
public function preparedProvider(): array
{
// 0: statement name
// 1: query to prepare
// 2: primary key name: null for default run
// 3: arguments for query (double array 0: for select, 0..n for insert/update)
// 4: expected prepare return
// 5: prepare warning
// 6: prepare error
// 7: expected execute return
// 8: execute warning
// 9: execute error
// 10: execute data to check (array)
// 11: insert data
return [
];
}
// bool|object|resource
public function testDbPrepared(
string $stm_name,
string $query,
?string $pk_name,
array $query_data,
$expected_prepare,
string $warning_prepare,
string $error_prepare,
$expected_execute,
string $warning_execute,
string $error_execute,
array $excute_data,
string $insert_data,
): void {
// self::$log->setLogLevelAll('debug', true);
// self::$log->setLogLevelAll('print', true);
$db = new \CoreLibs\DB\IO(
self::$db_config['valid'],
self::$log
);
// insert data before we can test, from expected array
$db->dbExec($insert_data);
// reset all data
$db->dbExec("TRUNCATE table_with_primary_key");
$db->dbExec("TRUNCATE table_without_primary_key");
// close connection
$db->dbClose(); $db->dbClose();
} }
// - db execution tests // - db execution tests
// dbReturn, dbCacheReset,
// dbFetchArray, dbReturnRow, dbReturnArray,
// dbCursorPos, dbCursorNumRows,
// dbPrepare, dbExecute
// dbExecAsync, dbCheckAsync // dbExecAsync, dbCheckAsync
// - encoding conversion on read // - encoding conversion on read
// dbSetToEncoding, dbGetToEncoding // dbSetToEncoding, dbGetToEncoding
@@ -1487,10 +2105,8 @@ final class CoreLibsDBIOTest extends TestCase
// dbDumpData // dbDumpData
// - internal read data (post exec) // - internal read data (post exec)
// dbGetReturning, dbGetInsertPKName, dbGetInsertPK, dbGetReturningExt, // dbGetReturning, dbGetInsertPKName, dbGetInsertPK, dbGetReturningExt,
// dbGetReturningArray, dbGetCursorExt, dbGetNumRows, dbGetNumFields, // dbGetReturningArray, dbGetNumRows, dbGetNumFields,
// dbGetFieldNames, dbGetQuery // dbGetFieldNames, dbGetQuery, dbGetQueryHash, dbGetDbh
// getHadError, getHadWarning,
// dbResetQueryCalled, dbGetQueryCalled
// - complex write sets // - complex write sets
// dbWriteData, dbWriteDataExt // dbWriteData, dbWriteDataExt
// - deprecated tests [no need to test perhaps] // - deprecated tests [no need to test perhaps]
@@ -1498,21 +2114,6 @@ final class CoreLibsDBIOTest extends TestCase
// getCursorExt, getNumRows // getCursorExt, getNumRows
// - error handling // - error handling
// dbGetCombinedErrorHistory, dbGetLastError, dbGetLastWarning // dbGetCombinedErrorHistory, dbGetLastError, dbGetLastWarning
/**
* grouped DB IO test
*
* @testdox DB\IO Class tests
*
* @return void
*/
public function testDBIO()
{
$this->assertTrue(true, 'DB IO Tests not implemented');
$this->markTestIncomplete(
'DB\IO Tests have not yet been implemented'
);
}
} }
// __END__ // __END__

View File

@@ -55,16 +55,26 @@ echo "DB_CONFIG_SET constant: <pre>" . print_r(DB_CONFIG, true) . "</pre><br>";
print "DB Client encoding: " . $db->dbGetEncoding() . "<br>"; print "DB Client encoding: " . $db->dbGetEncoding() . "<br>";
while (is_array($res = $db->dbReturn("SELECT * FROM max_test", DbIo::USE_CACHE, true))) { while (is_array($res = $db->dbReturn("SELECT * FROM max_test", DbIo::USE_CACHE, true))) {
print "TIME: " . $res['time'] . "<br>"; print "UUD/TIME: " . $res['uid'] . "/" . $res['time'] . "<br>";
} }
print "CACHED DATA: <pre>" . print_r($db->dbGetCursorExt(), true) . "</pre><br>"; print "CACHED DATA: <pre>" . print_r($db->dbGetCursorExt(), true) . "</pre><br>";
while (is_array($res = $db->dbReturn("SELECT * FROM max_test"))) { while (is_array($res = $db->dbReturn("SELECT * FROM max_test", DbIo::USE_CACHE))) {
print "[CACHED] TIME: " . $res['time'] . "<br>"; print "[CACHED] UID/TIME: " . $res['uid'] . "/" . $res['time'] . "<br>";
// print "****RES: <pre>" . print_r($res, true) . "</pre><br>";
} }
// print "CACHED REREAD DATA: <pre>" . print_r($db->dbGetCursorExt(), true) . "</pre><br>";
while (is_array($res = $db->dbReturn("SELECT * FROM max_test", DbIo::NO_CACHE))) {
print "[NO CACHE] UID.TIME: " . $res['uid'] . "/" . $res['time'] . "<br>";
// print "****RES: <pre>" . print_r($res, true) . "</pre><br>";
}
print "NO CACHED DATA: <pre>" . print_r($db->dbGetCursorExt(), true) . "</pre><br>";
// alternate check for valid data // alternate check for valid data
// while (($res = $db->dbReturn("SELECT * FROM max_test")) !== false) { // while (($res = $db->dbReturn("SELECT * FROM max_test")) !== false) {
// print "[CACHED] TIME: " . $res['time'] . "<br>"; // print "[CACHED] TIME: " . $res['time'] . "<br>";
// } // }
// while (is_array($res = $db->dbReturn("SELECT * FROM max_test", DbIo::USE_CACHE))) {
// print "UUD/TIME: " . $res['uid'] . "/" . $res['time'] . "<br>";
// }
print "<pre>"; print "<pre>";

View File

@@ -41,6 +41,7 @@ $log = new CoreLibs\Debug\Logging([
]); ]);
$basic = new CoreLibs\Basic($log); $basic = new CoreLibs\Basic($log);
$_uids = new CoreLibs\Create\Uids(); $_uids = new CoreLibs\Create\Uids();
use CoreLibs\Create\Uids;
$uids_class = 'CoreLibs\Create\Uids'; $uids_class = 'CoreLibs\Create\Uids';
print "<html><head><title>TEST CLASS: UIDS</title><head>"; print "<html><head><title>TEST CLASS: UIDS</title><head>";
@@ -57,6 +58,10 @@ print "S::UUIDV4: " . $uids_class::uuidv4() . "<br>";
print "S::UNIQID (d): " . $uids_class::uniqId() . "<br>"; print "S::UNIQID (d): " . $uids_class::uniqId() . "<br>";
print "S::UNIQID (md5): " . $uids_class::uniqId('md5') . "<br>"; print "S::UNIQID (md5): " . $uids_class::uniqId('md5') . "<br>";
print "S::UNIQID (sha256): " . $uids_class::uniqId('sha256') . "<br>"; print "S::UNIQID (sha256): " . $uids_class::uniqId('sha256') . "<br>";
// uniq ids
print "UNIQU ID SHORT : " . Uids::uniqIdShort() . "<br>";
print "UNIQU ID LONG : " . Uids::uniqIdLong() . "<br>";
// DEPRECATED // DEPRECATED
/* print "D/UUIDV4: ".$basic->uuidv4()."<br>"; /* print "D/UUIDV4: ".$basic->uuidv4()."<br>";
print "/DUNIQID (d): ".$basic->uniqId()."<br>"; */ print "/DUNIQID (d): ".$basic->uniqId()."<br>"; */

View File

@@ -439,7 +439,7 @@ class Login extends \CoreLibs\DB\IO
if (!is_array($res)) { if (!is_array($res)) {
$this->login_error = 1009; $this->login_error = 1009;
$this->permission_okay = false; $this->permission_okay = false;
} elseif (empty($this->dbGetCursorExt($q, 'num_rows'))) { } elseif (empty($this->dbGetCursorNumRows($q))) {
// username is wrong, but we throw for wrong username // username is wrong, but we throw for wrong username
// and wrong password the same error // and wrong password the same error
$this->login_error = 1010; $this->login_error = 1010;

View File

@@ -436,7 +436,6 @@ class IO
'22' => 'Query Execute failed', '22' => 'Query Execute failed',
'23' => 'Query Execute failed, data array does not match placeholders', '23' => 'Query Execute failed, data array does not match placeholders',
'24' => 'Missing prepared query entry for execute.', '24' => 'Missing prepared query entry for execute.',
'25' => 'Prepare query data is not in array format.',
'30' => 'Query call in a possible endless loop. ' '30' => 'Query call in a possible endless loop. '
. 'Was called more than ' . $this->MAX_QUERY_CALL . ' times', . 'Was called more than ' . $this->MAX_QUERY_CALL . ' times',
'31' => 'Could not fetch PK after query insert', '31' => 'Could not fetch PK after query insert',
@@ -885,14 +884,61 @@ class IO
private function __dbCheckConnectionOk(int $timeout_seconds = 3): bool private function __dbCheckConnectionOk(int $timeout_seconds = 3): bool
{ {
// check that no other query is running right now // check that no other query is running right now
// FIXME: do this in a loop? __dbConnectionBusySocketWait? max check timeout // below does return false after error too
if ($this->db_functions->__dbConnectionBusy()) { // if ($this->db_functions->__dbConnectionBusy()) {
if ($this->db_functions->__dbConnectionBusySocketWait($timeout_seconds)) {
$this->__dbError(41); $this->__dbError(41);
return false; return false;
} }
return true; return true;
} }
/**
* dbReturn
* Read data from previous written data cache
* @param string $query_hash The hash for the current query
* @param boolean $assoc_only Only return assoc value (key named)
* @return array Current position query data from cache
*/
private function __dbReturnCacheRead(string $query_hash, bool $assoc_only): array
{
// unset return value ...
$return = [];
// current cursor hash element
$cursor_hash = $this->cursor_ext[$query_hash];
// position in reading for current cursor hash
$cursor_pos = $cursor_hash['pos'];
// max fields in current cursor hash
$max_fields = $cursor_hash['num_fields'] ?? 0;
// read voer each field
for ($pos = 0; $pos < $max_fields; $pos++) {
// numbered pos element data (only exists in full read)
$cursor_data_pos = $cursor_hash['data'][$cursor_pos][$pos] ?? null;
// field name position from field names
$field_name_pos = $cursor_hash['field_names'][$pos] ?? null;
// field name data
$cursor_data_name = $cursor_hash['data'][$cursor_pos][$field_name_pos] ?? null;
// create mixed return array
if (
$assoc_only === false &&
$cursor_data_pos !== null
) {
$return[$pos] = $cursor_data_pos;
}
// named part (is alreays read)
if (!empty($field_name_pos)) {
// read pos first, fallback to name if not set
if ($cursor_data_pos !== null) {
$return[$field_name_pos] = $cursor_data_pos;
} else {
$return[$field_name_pos] = $cursor_data_name;
}
}
}
$this->cursor_ext[$query_hash]['pos'] ++;
return $return;
}
/** /**
* sub function for dbExec and dbExecAsync * sub function for dbExec and dbExecAsync
* - checks query is set * - checks query is set
@@ -908,7 +954,7 @@ class IO
private function __dbPrepareExec(string $query, string $pk_name) private function __dbPrepareExec(string $query, string $pk_name)
{ {
// reset current cursor before exec // reset current cursor before exec
$this->cursor = null; $this->cursor = false;
// clear matches for regex lookups // clear matches for regex lookups
$matches = []; $matches = [];
// to either use the returning method // to either use the returning method
@@ -980,7 +1026,7 @@ class IO
$this->__dbDebug('db', $this->query, '__dbPrepareExec', 'Q'); $this->__dbDebug('db', $this->query, '__dbPrepareExec', 'Q');
} }
// import protection, hash needed // import protection, hash needed
$query_hash = Hash::__hashLong($this->query); $query_hash = $this->dbGetQueryHash($this->query);
// if the array index does not exists set it 0 // if the array index does not exists set it 0
if (!array_key_exists($query_hash, $this->query_called)) { if (!array_key_exists($query_hash, $this->query_called)) {
$this->query_called[$query_hash] = 0; $this->query_called[$query_hash] = 0;
@@ -1129,13 +1175,11 @@ class IO
$this->__dbWarning( $this->__dbWarning(
33, 33,
false, false,
$stm_name . ': RETURNING returned no data', $stm_name . ': RETURNING returned no data'
'DB_WARNING'
); );
} }
} elseif (count($this->insert_id_arr) > 1) { } elseif (count($this->insert_id_arr) > 1) {
// this error handling is only for INSERT (), (), ... sets // this error handling is only for INSERT (), (), ... sets
$this->warning_id = 32;
if ($stm_name === null) { if ($stm_name === null) {
$this->__dbWarning(32, $cursor, '[dbExec]'); $this->__dbWarning(32, $cursor, '[dbExec]');
} else { } else {
@@ -1346,7 +1390,7 @@ class IO
{ {
// set start array // set start array
if ($query) { if ($query) {
$array = $this->cursor_ext[Hash::__hashLong($query)] ?? []; $array = $this->cursor_ext[$this->dbGetQueryHash($query)] ?? [];
} else { } else {
$array = $this->cursor_ext; $array = $this->cursor_ext;
} }
@@ -1585,7 +1629,8 @@ class IO
* caches data, so next time called with IDENTICAL (!!!!) * caches data, so next time called with IDENTICAL (!!!!)
* [this means 1:1 bit to bit identical query] returns cached * [this means 1:1 bit to bit identical query] returns cached
* data, or with reset flag set calls data from DB again * data, or with reset flag set calls data from DB again
* NOTE on $reset param: * NOTE on $cache param:
* - if set to 0, if same query run again, will read from cache
* - if set to 1, at the end of the query (last row returned), * - if set to 1, at the end of the query (last row returned),
* the stored array will be deleted ... * the stored array will be deleted ...
* - if set to 2, the data will be read new and cached * - if set to 2, the data will be read new and cached
@@ -1593,25 +1638,28 @@ class IO
* - if set to 3, after EACH row, the data will be reset, * - if set to 3, after EACH row, the data will be reset,
* no caching is done except for basic (count, etc) * no caching is done except for basic (count, etc)
* @param string $query Query string * @param string $query Query string
* @param int $reset reset status: * @param int $cache reset status: default: USE_CACHE
* USE_CACHE/0: normal read from cache on second run * USE_CACHE/0: normal read from cache on second run
* CLEAR_CACHE/1: read cache, clean at the end * CLEAR_CACHE/1: read cache, clean at the end
* READ_NEW/2: read new, clean at end * READ_NEW/2: read new, clean at end
* NO_CACHE/3: never cache * NO_CACHE/3: never cache [default]
* @param bool $assoc_only True to only returned the named and not * @param bool $assoc_only True to only returned the named and not
* index position ones * index position ones
* @return array<mixed>|bool return array data or false on error/end * @return array<mixed>|bool return array data or false on error/end
* @#suppress PhanTypeMismatchDimFetch * @#suppress PhanTypeMismatchDimFetch
*/ */
public function dbReturn(string $query, int $reset = self::USE_CACHE, bool $assoc_only = false) public function dbReturn(
{ string $query,
int $cache = self::USE_CACHE,
bool $assoc_only = false
) {
$this->__dbErrorReset(); $this->__dbErrorReset();
if (!$query) { if (!$query) {
$this->__dbError(11); $this->__dbError(11);
return false; return false;
} }
// create hash from query ... // create hash from query ...
$query_hash = Hash::__hashLong($query); $query_hash = $this->dbGetQueryHash($query);
// pre declare array // pre declare array
if (!isset($this->cursor_ext[$query_hash])) { if (!isset($this->cursor_ext[$query_hash])) {
$this->cursor_ext[$query_hash] = [ $this->cursor_ext[$query_hash] = [
@@ -1635,9 +1683,10 @@ class IO
} }
// init return als false // init return als false
$return = false; $return = false;
// if it is a call with reset in it we reset the cursor, so we get an uncached return // if it is a call with reset in it we reset the cursor,
// so we get an uncached return
// but only for the FIRST call (pos == 0) // but only for the FIRST call (pos == 0)
if ($reset && !$this->cursor_ext[$query_hash]['pos']) { if ($cache > self::USE_CACHE && !$this->cursor_ext[$query_hash]['pos']) {
$this->cursor_ext[$query_hash]['cursor'] = null; $this->cursor_ext[$query_hash]['cursor'] = null;
} }
// $this->debug('MENU', 'Reset: '.$reset.', Cursor: ' // $this->debug('MENU', 'Reset: '.$reset.', Cursor: '
@@ -1687,6 +1736,7 @@ class IO
$this->cursor_ext[$query_hash]['num_fields'] = $this->cursor_ext[$query_hash]['num_fields'] =
$this->db_functions->__dbNumFields($this->cursor_ext[$query_hash]['cursor']); $this->db_functions->__dbNumFields($this->cursor_ext[$query_hash]['cursor']);
// set field names // set field names
$this->cursor_ext[$query_hash]['field_names'] = [];
for ($i = 0; $i < $this->cursor_ext[$query_hash]['num_fields']; $i++) { for ($i = 0; $i < $this->cursor_ext[$query_hash]['num_fields']; $i++) {
$this->cursor_ext[$query_hash]['field_names'][] = $this->cursor_ext[$query_hash]['field_names'][] =
$this->db_functions->__dbFieldName( $this->db_functions->__dbFieldName(
@@ -1702,7 +1752,10 @@ class IO
$this->cursor_ext[$query_hash]['read_rows'] = 0; $this->cursor_ext[$query_hash]['read_rows'] = 0;
} }
// read data for further work ... but only if necessarry // read data for further work ... but only if necessarry
if ($this->cursor_ext[$query_hash]['read_rows'] == $this->cursor_ext[$query_hash]['num_rows']) { if (
$this->cursor_ext[$query_hash]['read_rows'] ==
$this->cursor_ext[$query_hash]['num_rows']
) {
$return = false; $return = false;
} else { } else {
$return = $this->__dbConvertEncoding( $return = $this->__dbConvertEncoding(
@@ -1717,7 +1770,7 @@ class IO
} }
} }
// check if cached call or reset call ... // check if cached call or reset call ...
if (!$return && !$reset) { if (!$return && $cache == self::USE_CACHE) {
// check if end of output ... // check if end of output ...
if ($this->cursor_ext[$query_hash]['pos'] >= $this->cursor_ext[$query_hash]['num_rows']) { if ($this->cursor_ext[$query_hash]['pos'] >= $this->cursor_ext[$query_hash]['num_rows']) {
$this->cursor_ext[$query_hash]['pos'] = 0; $this->cursor_ext[$query_hash]['pos'] = 0;
@@ -1727,62 +1780,25 @@ class IO
$this->cursor_ext[$query_hash]['cursor'] = 1; $this->cursor_ext[$query_hash]['cursor'] = 1;
$return = false; $return = false;
} else { } else {
// unset return value ... // cached data read
$return = []; $return = $this->__dbReturnCacheRead($query_hash, $assoc_only);
for ($i = 0; $i < $this->cursor_ext[$query_hash]['num_fields']; $i++) {
// FIXME: find out why phan throws all those array errors
// create mixed return array
if (
$assoc_only === false &&
isset($this->cursor_ext[$query_hash]['data'][$this->cursor_ext[$query_hash]['pos']][$i])
) {
$return[$i] =
/** @phan-suppress-next-line PhanTypeArraySuspiciousNullable */
$this->cursor_ext[$query_hash]['data']
[$this->cursor_ext[$query_hash]['pos']][$i];
}
// named part
if (!empty($this->cursor_ext[$query_hash]['field_names'][$i])) {
if (
isset(
$this->cursor_ext[$query_hash]['data']
[$this->cursor_ext[$query_hash]['pos']][$i]
)
) {
/** @phan-suppress-next-line PhanTypeArraySuspiciousNullable */
$return[$this->cursor_ext[$query_hash]['field_names'][$i]] =
/** @phan-suppress-next-line PhanTypeArraySuspiciousNullable */
$this->cursor_ext[$query_hash]['data']
[$this->cursor_ext[$query_hash]['pos']][$i];
} else {
// throws PhanTypeMismatchDimFetch error, but in this
// case we know we will access only named array parts
/** @phan-suppress-next-line PhanTypeArraySuspiciousNullable */
$return[$this->cursor_ext[$query_hash]['field_names'][$i]] =
/** @phan-suppress-next-line PhanTypeMismatchDimFetch,PhanTypeArraySuspiciousNullable */
$this->cursor_ext[$query_hash]['data'][$this->cursor_ext[$query_hash]
/** @phan-suppress-next-line PhanTypeArraySuspiciousNullable */
['pos']][$this->cursor_ext[$query_hash]['field_names'][$i]];
}
}
}
$this->cursor_ext[$query_hash]['pos'] ++;
} }
} else { } else {
// return row, if last && reset, then unset the hole hash array // return row, if last && reset, then unset the hole hash array
if ( if (
!$return && !$return &&
($reset == self::CLEAR_CACHE || $reset == self::NO_CACHE) && ($cache == self::CLEAR_CACHE || $cache == self::NO_CACHE) &&
$this->cursor_ext[$query_hash]['pos'] $this->cursor_ext[$query_hash]['pos']
) { ) {
// unset only the field names here of course // unset data block only
$this->cursor_ext[$query_hash]['field_names'] = null; $this->cursor_ext[$query_hash]['data'] = [];
$this->cursor_ext[$query_hash]['pos'] = 0; $this->cursor_ext[$query_hash]['pos'] = 0;
} elseif ( } elseif (
!$return && $reset == self::READ_NEW && !$return && $cache == self::READ_NEW &&
$this->cursor_ext[$query_hash]['pos'] $this->cursor_ext[$query_hash]['pos']
) { ) {
// at end of read reset pos & set cursor to 1 (so it does not get lost in session transfer) // at end of read reset pos & set cursor to 1
// (so it does not get lost in session transfer)
$this->cursor_ext[$query_hash]['pos'] = 0; $this->cursor_ext[$query_hash]['pos'] = 0;
$this->cursor_ext[$query_hash]['cursor'] = 1; $this->cursor_ext[$query_hash]['cursor'] = 1;
$return = false; $return = false;
@@ -1792,13 +1808,14 @@ class IO
// internal position counter // internal position counter
$this->cursor_ext[$query_hash]['pos'] ++; $this->cursor_ext[$query_hash]['pos'] ++;
$this->cursor_ext[$query_hash]['read_rows'] ++; $this->cursor_ext[$query_hash]['read_rows'] ++;
// if reset is <3 caching is done, else no // if reset is < NO_CACHE level caching is done, else no
if ($reset < self::NO_CACHE) { if ($cache < self::NO_CACHE) {
$temp = []; // why was this here?
foreach ($return as $field_name => $data) { // $temp = [];
$temp[$field_name] = $data; // foreach ($return as $field_name => $data) {
} // $temp[$field_name] = $data;
$this->cursor_ext[$query_hash]['data'][] = $temp; // }
$this->cursor_ext[$query_hash]['data'][] = $return;
} }
} // cached data if } // cached data if
} // cached or not if } // cached or not if
@@ -1913,7 +1930,7 @@ class IO
* @param bool $assoc_only if true, only name ref are returned * @param bool $assoc_only if true, only name ref are returned
* @return array<mixed>|bool array of hashes (row -> fields), false on error * @return array<mixed>|bool array of hashes (row -> fields), false on error
*/ */
public function dbReturnArray(string $query, bool $assoc_only = false) public function dbReturnArray(string $query, bool $assoc_only = true)
{ {
$this->__dbErrorReset(); $this->__dbErrorReset();
if (!$query) { if (!$query) {
@@ -1931,17 +1948,18 @@ class IO
} }
$rows = []; $rows = [];
while (is_array($res = $this->dbFetchArray($cursor, $assoc_only))) { while (is_array($res = $this->dbFetchArray($cursor, $assoc_only))) {
$data = []; // $data = [];
for ($i = 0; $i < $this->num_fields; $i++) { // for ($i = 0; $i < $this->num_fields; $i++) {
$data[$this->field_names[$i]] = $res[$this->field_names[$i]] ?? null; // $data[$this->field_names[$i]] = $res[$this->field_names[$i]] ?? null;
} // }
$rows[] = $data; // $rows[] = $data;
$rows[] = $res;
} }
return $rows; return $rows;
} }
// *************************** // ***************************
// CURSOR CACHE RESET // CURSOR EXT CACHE RESET
// *************************** // ***************************
/** /**
@@ -1952,9 +1970,9 @@ class IO
public function dbCacheReset(string $query): bool public function dbCacheReset(string $query): bool
{ {
$this->__dbErrorReset(); $this->__dbErrorReset();
$query_hash = Hash::__hashLong($query); $query_hash = $this->dbGetQueryHash($query);
// clears cache for this query // clears cache for this query
if (!$this->cursor_ext[$query_hash]['query']) { if (empty($this->cursor_ext[$query_hash]['query'])) {
$this->__dbError(18); $this->__dbError(18);
return false; return false;
} }
@@ -1963,22 +1981,55 @@ class IO
} }
// *************************** // ***************************
// CURSOR POSITON CHECK // CURSOR EXT DATA CHECK
// *************************** // ***************************
/**
* returns the full array for cursor ext
* or cursor for one query
* or detail data fonr one query cursor data
* @param string|null $query Query string, if not null convert to hash
* and return set cursor ext for only this
* if not found or null return null
* @return array<mixed>|string|int|resource|object|null
* Cursor Extended array full if no parameter
* Key is hash string from query run
* Or cursor data entry if query field is set
* If nothing found return null
*/
public function dbGetCursorExt($query = null, string $query_field = '')
{
if ($query !== null) {
$query_hash = $this->dbGetQueryHash($query);
if (
is_array($this->cursor_ext) &&
isset($this->cursor_ext[$query_hash])
) {
if (empty($query_field)) {
return $this->cursor_ext[$query_hash];
} else {
return $this->cursor_ext[$query_hash][$query_field] ?? null;
}
} else {
return null;
}
}
return $this->cursor_ext;
}
/** /**
* returns the current position the read out * returns the current position the read out
* @param string $query query to find in cursor_ext * @param string $query query to find in cursor_ext
* @return int|bool query position (row pos), false on error * @return int|bool query position (row pos), false on error
*/ */
public function dbCursorPos(string $query) public function dbGetCursorPos(string $query)
{ {
$this->__dbErrorReset(); $this->__dbErrorReset();
if (!$query) { if (!$query) {
$this->__dbError(11); $this->__dbError(11);
return false; return false;
} }
$query_hash = Hash::__hashLong($query); $query_hash = $this->dbGetQueryHash($query);
return (int)$this->cursor_ext[$query_hash]['pos']; return (int)$this->cursor_ext[$query_hash]['pos'];
} }
@@ -1987,14 +2038,14 @@ class IO
* @param string $query query to find in cursor_ext * @param string $query query to find in cursor_ext
* @return int|bool query position (row pos), false on error * @return int|bool query position (row pos), false on error
*/ */
public function dbCursorNumRows(string $query) public function dbGetCursorNumRows(string $query)
{ {
$this->__dbErrorReset(); $this->__dbErrorReset();
if (!$query) { if (!$query) {
$this->__dbError(11); $this->__dbError(11);
return false; return false;
} }
$query_hash = Hash::__hashLong($query); $query_hash = $this->dbGetQueryHash($query);
return (int)$this->cursor_ext[$query_hash]['num_rows']; return (int)$this->cursor_ext[$query_hash]['num_rows'];
} }
@@ -2010,7 +2061,7 @@ class IO
*/ */
public function dbResetQueryCalled(string $query): void public function dbResetQueryCalled(string $query): void
{ {
$this->query_called[Hash::__hashLong($query)] = 0; $this->query_called[$this->dbGetQueryHash($query)] = 0;
} }
/** /**
@@ -2020,7 +2071,7 @@ class IO
*/ */
public function dbGetQueryCalled(string $query): int public function dbGetQueryCalled(string $query): int
{ {
$query_hash = Hash::__hashLong($query); $query_hash = $this->dbGetQueryHash($query);
if ($this->query_called[$query_hash]) { if ($this->query_called[$query_hash]) {
return $this->query_called[$query_hash]; return $this->query_called[$query_hash];
} else { } else {
@@ -2122,7 +2173,7 @@ class IO
} }
} else { } else {
// thrown warning // thrown warning
$this->warning_id = 20; $this->__dbWarning(20, false, $stm_name);
return true; return true;
} }
} }
@@ -2146,14 +2197,7 @@ class IO
); );
return false; return false;
} }
if (!is_array($data)) { // if the count does not match
$this->__dbError(
25,
false,
$stm_name . ': Prepared query Data has to be given in array form.'
);
return false;
}
if ($this->prepare_cursor[$stm_name]['count'] != count($data)) { if ($this->prepare_cursor[$stm_name]['count'] != count($data)) {
$this->__dbError( $this->__dbError(
23, 23,
@@ -2623,6 +2667,48 @@ class IO
return $this->to_encoding; return $this->to_encoding;
} }
// ***************************
// QUERY DATA AND DB HANDLER
// ***************************
/**
* Return current database handler
* @return object|resource|bool|int|null
*/
public function dbGetDbh()
{
return $this->dbh;
}
/**
* Returns hash for query
* Hash is used in all internal storage systems for return data
* @param string $query The query to create the hash from
* @return string Hash, as set by hash lpng
*/
public function dbGetQueryHash(string $query): string
{
return Hash::__hashLong($query);
}
/**
* Get current set query
* @return string Current set query string
*/
public function dbGetQuery(): string
{
return $this->query;
}
/**
* Clear current query
* @return void
*/
public function dbResetQuery(): void
{
$this->query = '';
}
// *************************** // ***************************
// INTERNAL VARIABLES READ POST QUERY RUN // INTERNAL VARIABLES READ POST QUERY RUN
// *************************** // ***************************
@@ -2732,37 +2818,6 @@ class IO
return $this->insert_id_arr; return $this->insert_id_arr;
} }
/**
* returns the full array for cursor ext
* @param string|null $q Query string, if not null convert to hash
* and return set cursor ext for only this
* if not found or null return null
* @return array<mixed>|string|int|resource|object|null
* Cursor Extended array full if no parameter
* Key is hash string from query run
* Or cursor data entry if query field is set
* If nothing found return null
*/
public function dbGetCursorExt($q = null, string $query_field = '')
{
if ($q !== null) {
$query_hash = Hash::__hashLong($q);
if (
is_array($this->cursor_ext) &&
isset($this->cursor_ext[$query_hash])
) {
if (empty($query_field)) {
return $this->cursor_ext[$query_hash];
} else {
return $this->cursor_ext[$query_hash][$query_field];
}
} else {
return null;
}
}
return $this->cursor_ext;
}
/** /**
* returns current number of rows that where * returns current number of rows that where
* affected by UPDATE/SELECT, etc * affected by UPDATE/SELECT, etc
@@ -2792,32 +2847,9 @@ class IO
return $this->field_names; return $this->field_names;
} }
/** // ***************************
* Return current database handler // ERROR AND WARNING DATA
* @return object|resource|bool|int|null // ***************************
*/
public function dbGetDbh()
{
return $this->dbh;
}
/**
* Get current set query
* @return string Current set query string
*/
public function dbGetQuery(): string
{
return $this->query;
}
/**
* Clear current query
* @return void
*/
public function dbResetQuery(): void
{
$this->query = '';
}
/** /**
* Sets error number that was last * Sets error number that was last
@@ -2871,9 +2903,10 @@ class IO
return $this->error_history_long; return $this->error_history_long;
} }
/******************************** */ // ***************************
// DEPEREACTED CALLS // DEPEREACTED CALLS
/******************************** */ // all call below are no longer in use and throw deprecated errors
// ***************************
/** /**
* returns the db init error * returns the db init error

View File

@@ -586,9 +586,10 @@ class PgSQL
$socket = [pg_socket($this->dbh)]; $socket = [pg_socket($this->dbh)];
while ($busy) { while ($busy) {
// Will wait on that socket until that happens or the timeout is reached // Will wait on that socket until that happens or the timeout is reached
stream_select($socket, null, null, $timeout_seconds); stream_select($socket, $null, $null, $timeout_seconds);
$busy = pg_connection_busy($this->dbh); $busy = pg_connection_busy($this->dbh);
} }
return $busy;
} }
/** /**

View File

@@ -2249,14 +2249,14 @@ class Generate extends \CoreLibs\DB\Extended\ArrayIO
while (is_array($res = $this->dbReturn($data_array['query']))) { while (is_array($res = $this->dbReturn($data_array['query']))) {
/** @phan-suppress-next-line PhanTypeInvalidDimOffset */ /** @phan-suppress-next-line PhanTypeInvalidDimOffset */
$this->log->debug('edit', 'Q[' . $this->dbGetQueryHash($data_array['query']) . '] pos: ' $this->log->debug('edit', 'Q[' . $this->dbGetQueryHash($data_array['query']) . '] pos: '
. $this->dbGetCursorExt($data_array['query'], 'pos') . $this->dbGetCursorPos($data_array['query'])
. ' | want: ' . ($data_array['preset'] ?? '-') . ' | want: ' . ($data_array['preset'] ?? '-')
. ' | set: ' . ($data['preset'][$el_name] ?? '-')); . ' | set: ' . ($data['preset'][$el_name] ?? '-'));
// first is default for this element // first is default for this element
if ( if (
isset($data_array['preset']) && isset($data_array['preset']) &&
(!isset($data['preset'][$el_name]) || empty($data['preset'][$el_name])) && (!isset($data['preset'][$el_name]) || empty($data['preset'][$el_name])) &&
($this->dbGetCursorExt($data_array['query'], 'pos') == $data_array['preset']) ($this->dbGetCursorPos($data_array['query']) == $data_array['preset'])
) { ) {
$data['preset'][$el_name] = $res[0]; $data['preset'][$el_name] = $res[0];
} }