mirror of
https://github.com/OPSnet/Gazelle.git
synced 2026-01-16 18:04:34 -05:00
db sandbox: show create table, more tests
This commit is contained in:
@@ -15,7 +15,8 @@ class PgInfo {
|
||||
|
||||
public function info(): array {
|
||||
return $this->pg()->all("
|
||||
select t.table_schema || '.' || t.table_name as table_name,
|
||||
select (case when t.table_schema = 'public' then '' else t.table_schema || '.' end )
|
||||
|| t.table_name as table_name,
|
||||
pg_relation_size(t.table_schema || '.' || t.table_name) as table_size,
|
||||
pg_indexes_size(t.table_schema || '.' || t.table_name) as index_size,
|
||||
s.n_live_tup as live,
|
||||
|
||||
@@ -44,8 +44,7 @@ class PgTable extends AbstractTable {
|
||||
$this->pgro()->column("
|
||||
with pkey as (
|
||||
select cc.conrelid,
|
||||
format(E',
|
||||
constraint %I primary key(%s)', cc.conname,
|
||||
format(E',\n constraint %I primary key(%s)', cc.conname,
|
||||
string_agg(a.attname, ', '
|
||||
order by array_position(cc.conkey, a.attnum))
|
||||
) pkey
|
||||
@@ -62,7 +61,7 @@ class PgTable extends AbstractTable {
|
||||
case c.relpersistence when 't' then '' else n.nspname || '.' end,
|
||||
c.relname,
|
||||
string_agg(
|
||||
format(E'\t%I %s%s',
|
||||
format(E' %I %s%s',
|
||||
a.attname,
|
||||
pg_catalog.format_type(a.atttypid, a.atttypmod),
|
||||
case when a.attnotnull then ' not null' else '' end
|
||||
|
||||
@@ -6,43 +6,44 @@ declare(strict_types=1);
|
||||
|
||||
namespace Gazelle;
|
||||
|
||||
use Gazelle\Enum\SourceDB;
|
||||
use Gazelle\Util\Text;
|
||||
|
||||
if (!$Viewer->permitted('admin_site_debug')) {
|
||||
Error403::error();
|
||||
}
|
||||
|
||||
$src = ($_REQUEST['src'] ?? SourceDB::mysql->value) == SourceDB::mysql->value
|
||||
? SourceDB::mysql
|
||||
: SourceDB::postgres;
|
||||
$src = ($_REQUEST['src'] ?? Enum\SourceDB::mysql->value) == Enum\SourceDB::mysql->value
|
||||
? Enum\SourceDB::mysql
|
||||
: Enum\SourceDB::postgres;
|
||||
|
||||
$execute = false;
|
||||
$execute = false;
|
||||
$query = null;
|
||||
$table = null;
|
||||
$textAreaRows = 8;
|
||||
|
||||
if (isset($_GET['debug'])) {
|
||||
$data = json_decode(Text::base64UrlDecode($_GET['debug']), true);
|
||||
$data = json_decode(Text::base64UrlDecode($_GET['debug']), true);
|
||||
$query = trim($data['query']);
|
||||
if ($src === SourceDB::postgres && !empty($data['args'])) {
|
||||
if ($src === Enum\SourceDB::postgres && !empty($data['args'])) {
|
||||
$query .= "\n-- " . implode(', ', $data['args']);
|
||||
}
|
||||
$textAreaRows = max(8, substr_count($query, "\n") + 2);
|
||||
} elseif (isset($_GET['table'])) {
|
||||
$query = (new DB())->selectQuery($_GET['table']);
|
||||
$textAreaRows = max(8, substr_count($query, "\n") + 2);
|
||||
} elseif (!empty($_POST['query'])) {
|
||||
$query = trim($_POST['query']);
|
||||
$textAreaRows = max(8, substr_count($query, "\n") + 2);
|
||||
$execute = true;
|
||||
} else {
|
||||
$query = null;
|
||||
$table = $src === Enum\SourceDB::postgres
|
||||
? new DB\PgTable($_GET['table'])
|
||||
: new DB\MysqlTable($_GET['table']);
|
||||
$textAreaRows = 8;
|
||||
} elseif (!empty($_POST['query'])) {
|
||||
$query = trim($_POST['query']);
|
||||
$textAreaRows = max(8, substr_count($query, "\n") + 2);
|
||||
$execute = true;
|
||||
}
|
||||
|
||||
$error = false;
|
||||
$result = [];
|
||||
if ($execute) {
|
||||
try {
|
||||
if ($src == SourceDB::postgres) {
|
||||
if ($src == Enum\SourceDB::postgres) {
|
||||
$db = new \Gazelle\DB\Pg(PG_RO_DSN);
|
||||
$result = $db->all($query);
|
||||
} else {
|
||||
@@ -60,5 +61,6 @@ echo $Twig->render('debug/db-sandbox.twig', [
|
||||
'rows' => $textAreaRows,
|
||||
'result' => $result,
|
||||
'source' => $src->value,
|
||||
'table' => $table,
|
||||
'error' => $error,
|
||||
]);
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<div class="pad"><div class="box pad">
|
||||
<h3>Mysql table {{ table.name }} definition</h3>
|
||||
<pre>{{ table.definition }}</pre>
|
||||
<a href="tools.php?action=db_sandbox&table={{ table.name }}" class="brackets">Inspect</a>
|
||||
<a href="tools.php?action=db_sandbox&src=mysql&table={{ table.name }}" class="brackets">Inspect</a>
|
||||
</div></div>
|
||||
|
||||
<div class="pad"><div class="box pad">
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
<tr>
|
||||
<td>{{ table.stats.live|number_format }}</td>
|
||||
<td>{{ table.stats.dead|number_format }}</td>
|
||||
<td>{{ (table.stats.dead == 0
|
||||
<td>{{ (table.stats.live == 0
|
||||
? 0
|
||||
: (table.stats.dead / table.stats.live) * 100)|number_format(2)
|
||||
}}</td>
|
||||
|
||||
@@ -12,11 +12,13 @@
|
||||
unsure how many rows will be returned. This is to avoid exhausting memory, as the resultset is buffered in memory.</div>
|
||||
<div class="pad">If two columns have the same name (e.g. <code>ID</code>), only the first column will be displayed.</div>
|
||||
<form action="tools.php?action=db_sandbox" method='POST'>
|
||||
<textarea style="width: 98%;" name="query" cols="90" rows="{{ rows }}">{{ query }}</textarea><br /><br />
|
||||
<textarea style="width: 98%;" name="query" cols="90" rows="{{ rows }}">{{ query }}</textarea>
|
||||
Source
|
||||
<label><input type="radio" name="src" value="mysql"{{ checked(source == 'mysql') }} /> Mysql</label>
|
||||
<label><input type="radio" name="src" value="pg"{{ checked(source == 'pg') }} /> Postgres</label>
|
||||
<input type="submit" value="Query" />
|
||||
<br />
|
||||
<div class="box pad"><pre>{{ table.definition }}</pre></div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -134,6 +134,14 @@ class DbTest extends TestCase {
|
||||
$this->assertCount(1, $warning, 'db-warning');
|
||||
$this->assertEquals(1050, $warning[0]['code'], 'db-error-code');
|
||||
$this->assertEquals("Table '$tableName' already exists", $warning[0]['message'], 'db-error-message');
|
||||
|
||||
$db->disableQueryLog();
|
||||
$db->prepared_query('select now()');
|
||||
$n = count($queryList);
|
||||
$this->assertEquals($n, count($db->queryList()), 'db-query-log-off');
|
||||
$db->enableQueryLog();
|
||||
$db->prepared_query('select now()');
|
||||
$this->assertEquals($n + 1, count($db->queryList()), 'db-query-log-on');
|
||||
}
|
||||
|
||||
public function testGlobalStatus(): void {
|
||||
@@ -287,6 +295,15 @@ class DbTest extends TestCase {
|
||||
");
|
||||
}
|
||||
|
||||
public function testMysqlMisc(): void {
|
||||
$db = DB::DB();
|
||||
$this->assertTrue(
|
||||
$db->entityExists('users_main', 'Username'),
|
||||
'db-mysql-entity-exists'
|
||||
);
|
||||
$this->assertEquals($db->info(), 'mysql via TCP/IP', 'db-mysql-info');
|
||||
}
|
||||
|
||||
public function testMysqlTable(): void {
|
||||
$bad = new DB\MysqlTable('nosuchtable');
|
||||
$this->assertFalse($bad->exists(), 'mysql-table-does-not-exist');
|
||||
@@ -487,6 +504,17 @@ class DbTest extends TestCase {
|
||||
");
|
||||
}
|
||||
|
||||
public function testMysqlPrepare(): void {
|
||||
$db = DB::DB();
|
||||
$this->assertInstanceOf(
|
||||
\mysqli_stmt::class,
|
||||
$db->prepare('select now()'),
|
||||
'db-mysql-prepare-ok'
|
||||
);
|
||||
$this->expectException(\mysqli_sql_exception::class);
|
||||
$db->prepare('this is not sql');
|
||||
}
|
||||
|
||||
public function testPgWrapper(): void {
|
||||
$this->pg()->execute("
|
||||
create temporary table phpunit_pg_wrapper (
|
||||
@@ -515,6 +543,33 @@ class DbTest extends TestCase {
|
||||
);
|
||||
}
|
||||
|
||||
public function testPgInsertCopy(): void {
|
||||
$this->pg()->prepared_query("
|
||||
create temporary table phpunit_insert_copy
|
||||
(num int, name text, flag bool)
|
||||
");
|
||||
$output = [
|
||||
['num' => 100, 'name' => "abc\ndef", 'flag' => true],
|
||||
['num' => -100, 'name' => "ghi\tjkl", 'flag' => false],
|
||||
['num' => 17, 'name' => null, 'flag' => 0],
|
||||
['num' => null, 'name' => null, 'flag' => null],
|
||||
];
|
||||
$input = array_map(fn ($r) => array_values($r), $output);
|
||||
$this->assertTrue(
|
||||
$this->pg()->insertCopy(
|
||||
'phpunit_insert_copy',
|
||||
['num', 'name', 'flag'],
|
||||
$input
|
||||
),
|
||||
'pg-insert-copy',
|
||||
);
|
||||
$this->assertEquals(
|
||||
$output,
|
||||
$this->pg()->all("select * from phpunit_insert_copy"),
|
||||
'pg-read-insert',
|
||||
);
|
||||
}
|
||||
|
||||
public function testPgWrite(): void {
|
||||
$this->expectException(\PDOException::class);
|
||||
$this->expectExceptionMessageMatches(
|
||||
|
||||
@@ -31,7 +31,7 @@ class PgInfoTest extends TestCase {
|
||||
Enum\Direction::descending,
|
||||
);
|
||||
$list = $pgInfo->info();
|
||||
$this->assertEquals('public.user_warning', $list[0]['table_name'], 'pginfo-list');
|
||||
$this->assertEquals('user_warning', $list[0]['table_name'], 'pginfo-list');
|
||||
}
|
||||
|
||||
public function testPgInfoColumn(): void {
|
||||
|
||||
Reference in New Issue
Block a user