CaiWuXiTong/modules/EcommerceFinance/Services/UpstreamSqlDialect.php

56 lines
2.5 KiB
PHP

<?php
namespace Modules\EcommerceFinance\Services;
use InvalidArgumentException;
class UpstreamSqlDialect
{
public function __construct(public readonly string $driver)
{
if (! in_array($driver, ['sqlsrv', 'pgsql', 'mysql'], true)) {
throw new InvalidArgumentException('不支持的上游数据库类型。');
}
}
public function quote(string $identifier): string
{
if ($identifier === '' || str_contains($identifier, "\0")) throw new InvalidArgumentException('无效的数据库标识符。');
return match ($this->driver) {
'pgsql' => '"' . str_replace('"', '""', $identifier) . '"',
'mysql' => '`' . str_replace('`', '``', $identifier) . '`',
default => '[' . str_replace(']', ']]', $identifier) . ']',
};
}
public function select(string $columns, string $tail, int $limit): string
{
$limit = min(max($limit, 1), 5000);
return $this->driver === 'sqlsrv'
? 'SELECT TOP (' . $limit . ') ' . $columns . ' ' . $tail
: 'SELECT ' . $columns . ' ' . $tail . ' LIMIT ' . $limit;
}
public function catalogSql(): string
{
// Same normalized catalog shape for all engines; MySQL never enumerates other databases.
$schema = $this->driver === 'sqlsrv' ? 'INFORMATION_SCHEMA' : 'information_schema';
$sql = "SELECT c.table_schema AS schema_name, c.table_name AS object_name,
CASE WHEN t.table_type = 'VIEW' THEN 'view' ELSE 'table' END AS object_type,
c.column_name AS column_name, c.ordinal_position AS ordinal_position,
c.data_type AS data_type, c.character_maximum_length AS max_length,
c.numeric_precision AS numeric_precision, c.numeric_scale AS numeric_scale,
c.is_nullable AS is_nullable
FROM {$schema}." . ($this->driver === 'sqlsrv' ? 'COLUMNS' : 'columns') . " c
INNER JOIN {$schema}." . ($this->driver === 'sqlsrv' ? 'TABLES' : 'tables') . " t
ON t.table_schema = c.table_schema AND t.table_name = c.table_name
WHERE c.table_schema NOT IN ('sys', 'INFORMATION_SCHEMA', 'information_schema', 'pg_catalog', 'mysql', 'performance_schema')";
if ($this->driver === 'mysql') $sql .= ' AND c.table_schema = DATABASE()';
$sql .= ' ORDER BY c.table_schema, c.table_name, c.ordinal_position';
if ($this->driver === 'sqlsrv') {
$sql = preg_replace_callback('/\b([ct])\.([a-z_]+)\b/', fn ($m) => $m[1] . '.' . strtoupper($m[2]), $sql);
}
return $sql;
}
}