fix(grid): honor include-database-name setting in SQL extractors
This commit is contained in:
1 parent
8c6acaad3d
commit
dd84e6c06a
5 files changed
+73
-5
No files matched your search
@@ -7465,6 +7465,7 @@ const {
|
||||
sql: computed(() => props.sql),
|
||||
exportSql: computed(() => props.exportSql),
|
||||
tableMeta: computed(() => (props.tableMeta ? { ...props.tableMeta } : undefined)),
|
||||
includeDatabaseName: computed(() => settingsStore.editorSettings.generateSqlIncludeDatabaseName),
|
||||
copyInsertTargetLabel: computed(() => props.tableMeta?.tableName ?? props.customSaveHandler?.targetLabel),
|
||||
mongoUpdateTarget: computed(() => props.mongoUpdateTarget),
|
||||
databaseType: computed(() => props.databaseType),
|
||||
|
||||
@@ -80,6 +80,8 @@ export interface UseDataGridExportOptions {
|
||||
sql: ComputedRef<string | undefined>;
|
||||
exportSql?: ComputedRef<string | undefined>;
|
||||
tableMeta: ComputedRef<DataGridTableMeta | undefined>;
|
||||
/** Editor setting "Include database name in generated SQL" — passed through to SQL extractors. */
|
||||
includeDatabaseName?: ComputedRef<boolean>;
|
||||
copyInsertTargetLabel?: ComputedRef<string | undefined>;
|
||||
mongoUpdateTarget?: ComputedRef<MongoCopyUpdateTarget | undefined>;
|
||||
databaseType: ComputedRef<DatabaseType | undefined>;
|
||||
@@ -722,6 +724,7 @@ export function useDataGridExport(options: UseDataGridExportOptions) {
|
||||
databaseType,
|
||||
identifierQuote,
|
||||
tableMeta,
|
||||
includeDatabaseName: options.includeDatabaseName,
|
||||
hasCellSelection,
|
||||
selectedCells,
|
||||
selectedCellMatrix,
|
||||
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
import type { DataGridTableMeta } from "@/lib/dataGrid/dataGridSql";
|
||||
import { binaryCellClipboardText } from "@/lib/dataGrid/binaryCellDownload";
|
||||
import { formatError } from "@/lib/backend/errorUtils";
|
||||
import { tableMetaWithoutOptionalDatabaseQualifier } from "@/lib/table/tableSelectSql";
|
||||
import type { DatabaseType } from "@/types/database";
|
||||
|
||||
interface ExtractorRowItem {
|
||||
@@ -50,6 +51,8 @@ interface UseDataGridExtractorOptions {
|
||||
databaseType: ComputedRef<DatabaseType | undefined>;
|
||||
identifierQuote?: ComputedRef<string | undefined>;
|
||||
tableMeta: ComputedRef<DataGridTableMeta | undefined>;
|
||||
/** Editor setting "Include database name in generated SQL". When false, SQL extractors omit optional schema/database qualifiers. */
|
||||
includeDatabaseName?: ComputedRef<boolean>;
|
||||
hasCellSelection: ComputedRef<boolean>;
|
||||
selectedCells: ComputedRef<SelectionData>;
|
||||
selectedCellMatrix: ComputedRef<CellSelectionMatrix | null>;
|
||||
@@ -216,9 +219,13 @@ export function useDataGridExtractor(options: UseDataGridExtractorOptions) {
|
||||
const rows = rawRows.map((row) => row.map((value, index) => extractorCellValue(value, columnTypes[index], normalizeValues, presentBinaryText, index)));
|
||||
const tableMeta =
|
||||
descriptor.category === "sql"
|
||||
? compactTableMeta(
|
||||
options.tableMeta.value,
|
||||
columns.map((column) => column.sourceName ?? column.displayName),
|
||||
? tableMetaWithoutOptionalDatabaseQualifier(
|
||||
compactTableMeta(
|
||||
options.tableMeta.value,
|
||||
columns.map((column) => column.sourceName ?? column.displayName),
|
||||
),
|
||||
options.databaseType.value,
|
||||
options.includeDatabaseName?.value,
|
||||
)
|
||||
: undefined;
|
||||
const request: DataGridExtractRequest = {
|
||||
|
||||
+41
-1
@@ -1,6 +1,6 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { encodeSqlServerLinkedSchema } from "@/lib/database/sqlServerLinkedServers";
|
||||
import { qualifiedTableName, qualifyTableReferencesInSql, quoteTableDataIdentifier, quoteTableIdentifier, quoteTableIdentifierIfNeeded } from "@/lib/table/tableSelectSql";
|
||||
import { qualifiedTableName, qualifyTableReferencesInSql, quoteTableDataIdentifier, quoteTableIdentifier, quoteTableIdentifierIfNeeded, tableMetaWithoutOptionalDatabaseQualifier } from "@/lib/table/tableSelectSql";
|
||||
|
||||
describe("qualifiedTableName — Doris/StarRocks multi-catalog", () => {
|
||||
it("prefixes external catalog for Doris (no schema)", () => {
|
||||
@@ -167,6 +167,46 @@ describe("qualifiedTableName — includeDatabaseName on quoted-identifier paths
|
||||
});
|
||||
});
|
||||
|
||||
describe("tableMetaWithoutOptionalDatabaseQualifier — copy extractors (#9326)", () => {
|
||||
const mysqlMeta = { schema: "analytics", database: "analytics", tableName: "events" };
|
||||
|
||||
it("strips MySQL schema/database when includeDatabaseName is false", () => {
|
||||
expect(tableMetaWithoutOptionalDatabaseQualifier(mysqlMeta, "mysql", false)).toEqual({ schema: undefined, database: undefined, tableName: "events" });
|
||||
});
|
||||
|
||||
it("keeps MySQL schema when includeDatabaseName is true or unset", () => {
|
||||
expect(tableMetaWithoutOptionalDatabaseQualifier(mysqlMeta, "mysql", true)).toBe(mysqlMeta);
|
||||
expect(tableMetaWithoutOptionalDatabaseQualifier(mysqlMeta, "mysql")).toBe(mysqlMeta);
|
||||
});
|
||||
|
||||
it("keeps schema for dialects that require fully qualified names", () => {
|
||||
expect(tableMetaWithoutOptionalDatabaseQualifier({ schema: "dbo", tableName: "users" }, "sqlserver", false)).toEqual({ schema: "dbo", tableName: "users" });
|
||||
});
|
||||
|
||||
it("matches SELECT-template dropsSchemaQualifier for Oracle/Postgres", () => {
|
||||
// Same rule as #9110: when the setting is off, optional schema prefixes are
|
||||
// dropped so the active connection schema applies.
|
||||
expect(tableMetaWithoutOptionalDatabaseQualifier({ schema: "SCOTT", tableName: "EMP" }, "oracle", false)).toEqual({ schema: undefined, tableName: "EMP" });
|
||||
expect(tableMetaWithoutOptionalDatabaseQualifier({ schema: "public", tableName: "users" }, "postgres", false)).toEqual({ schema: undefined, tableName: "users" });
|
||||
});
|
||||
|
||||
it("returns undefined tableMeta unchanged", () => {
|
||||
expect(tableMetaWithoutOptionalDatabaseQualifier(undefined, "mysql", false)).toBeUndefined();
|
||||
});
|
||||
|
||||
it("keeps qualifiers for Doris/StarRocks external catalogs", () => {
|
||||
// External-catalog tables are only addressable as catalog.database.table,
|
||||
// mirroring the SELECT-template rule in qualifiedTableName.
|
||||
const externalCatalogMeta = { catalog: "ext", database: "db", tableName: "t" };
|
||||
expect(tableMetaWithoutOptionalDatabaseQualifier(externalCatalogMeta, "doris", false)).toBe(externalCatalogMeta);
|
||||
expect(tableMetaWithoutOptionalDatabaseQualifier(externalCatalogMeta, "starrocks", false)).toBe(externalCatalogMeta);
|
||||
});
|
||||
|
||||
it("still strips the internal-catalog database qualifier", () => {
|
||||
expect(tableMetaWithoutOptionalDatabaseQualifier({ catalog: "internal", database: "db", tableName: "t" }, "doris", false)).toEqual({ catalog: "internal", schema: undefined, database: undefined, tableName: "t" });
|
||||
});
|
||||
});
|
||||
|
||||
describe("qualifiedTableName — GBase 8s", () => {
|
||||
it("omits the metadata owner for GBase 8s table data", () => {
|
||||
expect(qualifiedTableName({ databaseType: "informix", driverProfile: "gbase8s", identifierQuote: "", schema: "gbasedbt", tableName: "connection_smoke" })).toBe("connection_smoke");
|
||||
|
||||
@@ -44,10 +44,27 @@ const DATABASE_QUALIFIED_TABLE_TYPES = new Set<DatabaseType>(["mysql", "clickhou
|
||||
// name" on schema-aware engines — except for databases that can only address
|
||||
// objects through their full qualified name (`catalog.schema.table` /
|
||||
// `database.schema.table`), where dropping it would break the query.
|
||||
function dropsSchemaQualifier(databaseType: DatabaseType | undefined, includeDatabaseName?: boolean): boolean {
|
||||
export function dropsSchemaQualifier(databaseType: DatabaseType | undefined, includeDatabaseName?: boolean): boolean {
|
||||
return includeDatabaseName === false && databaseType !== undefined && !DATABASE_SCHEMA_QUALIFIED_TYPES.has(databaseType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Strip optional schema/database qualifiers from table metadata used to build
|
||||
* generated SQL. Mirrors `dropsSchemaQualifier` so copy-as-INSERT/UPDATE
|
||||
* extractors honor "Include database name in generated SQL" the same way
|
||||
* SELECT templates do (#9326).
|
||||
*/
|
||||
export function tableMetaWithoutOptionalDatabaseQualifier<T extends { schema?: string; database?: string; catalog?: string }>(tableMeta: T | undefined, databaseType: DatabaseType | undefined, includeDatabaseName?: boolean): T | undefined {
|
||||
if (!tableMeta || !dropsSchemaQualifier(databaseType, includeDatabaseName)) return tableMeta;
|
||||
// Doris/StarRocks external-catalog tables are only addressable through the
|
||||
// 3-part `catalog.database.table` form; stripping the middle segment would
|
||||
// retarget the generated SQL, so keep the qualifiers (same rule as
|
||||
// `qualifiedTableName`).
|
||||
if (tableMeta.catalog && tableMeta.catalog !== "internal" && (databaseType === "doris" || databaseType === "starrocks")) return tableMeta;
|
||||
if (tableMeta.schema === undefined && tableMeta.database === undefined) return tableMeta;
|
||||
return { ...tableMeta, schema: undefined, database: undefined };
|
||||
}
|
||||
|
||||
function sqlStatementSpans(sql: string, dialectId: string): Array<{ start: number; end: number }> {
|
||||
const spans: Array<{ start: number; end: number }> = [];
|
||||
let start = 0;
|
||||
|
||||
Reference in new issue
Block a user