Files
MyGoNavi/frontend/src/utils/queryResultTable.ts
Syngnat 04bbab3d7e 🐛 fix(query-results): 修复金仓带模式表主键识别
- PG 类数据库保留 schema.table 作为查询结果表名和元数据表名
- 元数据连接继续使用当前数据库,避免把 schema 误当 database
- 补充金仓列、索引和前端可编辑定位回归测试
2026-06-29 15:18:13 +08:00

125 lines
4.6 KiB
TypeScript

export type QueryResultTableRef = {
tableName: string;
metadataDbName: string;
metadataTableName: string;
};
const stripIdentifierQuotes = (part: string): string => {
const text = String(part || '').trim();
if (!text) return '';
if ((text.startsWith('`') && text.endsWith('`')) || (text.startsWith('"') && text.endsWith('"'))) {
return text.slice(1, -1).trim();
}
if (text.startsWith('[') && text.endsWith(']')) {
return text.slice(1, -1).trim();
}
return text;
};
const isOracleLikeDialect = (dialect: string): boolean => {
const normalized = String(dialect || '').trim().toLowerCase();
return normalized === 'oracle' || normalized === 'dameng' || normalized === 'dm' || normalized === 'dm8';
};
const keepsQualifiedTableNameForMetadata = (dialect: string): boolean => {
const normalized = String(dialect || '').trim().toLowerCase();
return normalized === 'duckdb' || isPostgresLikeDialect(normalized);
};
const isPostgresLikeDialect = (dialect: string): boolean => {
const normalized = String(dialect || '').trim().toLowerCase();
return normalized === 'postgres'
|| normalized === 'postgresql'
|| normalized === 'pg'
|| normalized === 'kingbase'
|| normalized === 'kingbase8'
|| normalized === 'kingbasees'
|| normalized === 'kingbasev8'
|| normalized === 'highgo'
|| normalized === 'vastbase'
|| normalized === 'opengauss'
|| normalized === 'open_gauss'
|| normalized === 'open-gauss'
|| normalized === 'gaussdb'
|| normalized === 'gauss_db'
|| normalized === 'gauss-db';
};
const isQuotedIdentifier = (part: string): boolean => {
const text = String(part || '').trim();
if (!text) return false;
return (text.startsWith('`') && text.endsWith('`'))
|| (text.startsWith('"') && text.endsWith('"'))
|| (text.startsWith('[') && text.endsWith(']'));
};
const normalizeIdentifierPart = (part: string, dialect: string): string => {
const text = String(part || '').trim();
const value = stripIdentifierQuotes(text);
if (!value) return '';
if (isOracleLikeDialect(dialect) && !isQuotedIdentifier(text)) {
return value.toUpperCase();
}
return value;
};
const normalizeCurrentDbName = (currentDb: string, dialect: string): string => {
const value = String(currentDb || '').trim();
if (!value) return '';
return isOracleLikeDialect(dialect) ? value.toUpperCase() : value;
};
const normalizeQualifiedNameParts = (raw: string, dialect: string): string[] => (
String(raw || '')
.split('.')
.map((part) => normalizeIdentifierPart(part, dialect))
.filter(Boolean)
);
export const extractQueryResultTableRef = (
sql: string,
dialect: string,
currentDb: string,
defaultSchema = '',
): QueryResultTableRef | undefined => {
const text = String(sql || '').trim();
if (!text) return undefined;
if (/\b(JOIN|UNION|INTERSECT|EXCEPT|MINUS)\b/i.test(text)) return undefined;
if (/^\s*SELECT\s+DISTINCT\b/i.test(text)) return undefined;
if (/\bGROUP\s+BY\b|\bHAVING\b/i.test(text)) return undefined;
const tableMatch = text.match(/^\s*SELECT\s+.+?\s+FROM\s+((?:[`"\[]?\w+[`"\]]?)(?:\s*\.\s*(?:[`"\[]?\w+[`"\]]?)){0,2})\s*(?:$|[\s;])/im);
if (!tableMatch) return undefined;
const parts = normalizeQualifiedNameParts(tableMatch[1], dialect);
if (parts.length === 0) return undefined;
const metadataTableName = parts[parts.length - 1] || '';
if (!metadataTableName) return undefined;
const owner = parts.length >= 2 ? parts[parts.length - 2] : '';
const defaultOracleSchema = isOracleLikeDialect(dialect)
? normalizeCurrentDbName(defaultSchema, dialect)
: '';
const fallbackSchema = isOracleLikeDialect(dialect)
? defaultOracleSchema || normalizeCurrentDbName(currentDb, dialect)
: normalizeCurrentDbName(currentDb, dialect);
const metadataDbName = owner || fallbackSchema;
const qualifiedTableName = owner ? `${owner}.${metadataTableName}` : metadataTableName;
const pgLikeQualifiedMetadata = isPostgresLikeDialect(dialect) && owner;
const resolvedMetadataDbName = pgLikeQualifiedMetadata
? normalizeCurrentDbName(currentDb, dialect)
: metadataDbName;
const tableName = (isOracleLikeDialect(dialect) && owner) || pgLikeQualifiedMetadata
? `${owner}.${metadataTableName}`
: (keepsQualifiedTableNameForMetadata(dialect) && owner ? `${owner}.${metadataTableName}` : metadataTableName);
const resolvedMetadataTableName = keepsQualifiedTableNameForMetadata(dialect) && owner
? qualifiedTableName
: metadataTableName;
return {
tableName,
metadataDbName: resolvedMetadataDbName || metadataDbName,
metadataTableName: resolvedMetadataTableName,
};
};