mirror of
https://github.com/t8y2/dbx.git
synced 2026-10-19 16:16:45 +00:00
fix(kingbase): honor connection identifier quotes in exports
This commit is contained in:
@@ -426,6 +426,7 @@ export function useDataGridExport(options: UseDataGridExportOptions) {
|
||||
}
|
||||
return buildDataGridCopyInsertStatement({
|
||||
databaseType: databaseType.value,
|
||||
identifierQuote: options.identifierQuote?.value,
|
||||
tableMeta: tableMeta.value,
|
||||
columns: data.columns,
|
||||
columnTypes: data.columnTypes,
|
||||
@@ -1250,6 +1251,7 @@ export function useDataGridExport(options: UseDataGridExportOptions) {
|
||||
const exportData = sqlInsertExportData(result);
|
||||
const content = await formatSqlInsert({
|
||||
databaseType: databaseType.value,
|
||||
identifierQuote: options.identifierQuote?.value,
|
||||
schema: tableMeta.value?.schema,
|
||||
tableName: tableMeta.value?.tableName || "table_name",
|
||||
columns: exportData.columns,
|
||||
@@ -1271,6 +1273,7 @@ export function useDataGridExport(options: UseDataGridExportOptions) {
|
||||
const exportData = sqlInsertExportData(result);
|
||||
const content = await formatSqlInsert({
|
||||
databaseType: databaseType.value,
|
||||
identifierQuote: options.identifierQuote?.value,
|
||||
schema: tableMeta.value?.schema,
|
||||
tableName: tableMeta.value?.tableName || "table_name",
|
||||
columns: exportData.columns,
|
||||
|
||||
@@ -4310,6 +4310,7 @@ export interface QueryResultExportRequest {
|
||||
exportColumnTypes?: Array<string | null | undefined>;
|
||||
numericColumnRightAlign?: boolean;
|
||||
columnComments?: Array<string | null> | null;
|
||||
identifierQuote?: string;
|
||||
}
|
||||
|
||||
export async function startTableExport(request: TableExportRequest, onProgress: (progress: TableExportProgress) => void): Promise<TableExportProgress> {
|
||||
|
||||
@@ -36,6 +36,7 @@ export interface DataGridSaveStatementOptions {
|
||||
|
||||
export interface DataGridCopyUpdateStatementOptions {
|
||||
databaseType?: DatabaseType;
|
||||
identifierQuote?: string;
|
||||
tableMeta: DataGridTableMeta;
|
||||
columns: string[];
|
||||
sourceColumns?: Array<string | undefined>;
|
||||
@@ -46,6 +47,7 @@ export type DataGridCopyInsertMode = "merged" | "row-by-row";
|
||||
|
||||
export interface DataGridCopyInsertStatementOptions {
|
||||
databaseType?: DatabaseType;
|
||||
identifierQuote?: string;
|
||||
tableMeta?: DataGridTableMeta;
|
||||
columns: string[];
|
||||
columnTypes?: Array<string | null | undefined>;
|
||||
|
||||
@@ -29,6 +29,7 @@ export function formatTsv(columns: string[], rows: ExportCellValue[][]): string
|
||||
|
||||
export interface FormatSqlInsertOptions {
|
||||
databaseType?: DatabaseType;
|
||||
identifierQuote?: string;
|
||||
schema?: string;
|
||||
tableName?: string;
|
||||
qualifiedTableName?: string;
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
import { createPinia, setActivePinia } from "pinia";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
const mocks = vi.hoisted(() => ({
|
||||
ensureConnected: vi.fn(),
|
||||
getConfig: vi.fn(),
|
||||
connectionIdentifierQuote: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("@/lib/backend/api", () => ({
|
||||
saveOpenTabsState: vi.fn().mockResolvedValue(undefined),
|
||||
}));
|
||||
|
||||
vi.mock("@/stores/connectionStore", () => ({
|
||||
useConnectionStore: () => ({
|
||||
ensureConnected: mocks.ensureConnected,
|
||||
getConfig: mocks.getConfig,
|
||||
connectionIdentifierQuote: mocks.connectionIdentifierQuote,
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock("@/stores/settingsStore", () => ({
|
||||
useSettingsStore: () => ({
|
||||
editorSettings: {
|
||||
exportBatchSize: 1000,
|
||||
exportRowLimitEnabled: false,
|
||||
exportRowLimit: 100_000,
|
||||
globalQueryTimeoutSecs: 30,
|
||||
queryExportKeysetOptimizationEnabled: true,
|
||||
numericColumnRightAlign: true,
|
||||
},
|
||||
}),
|
||||
}));
|
||||
|
||||
function installLocalStorage() {
|
||||
const data = new Map<string, string>();
|
||||
vi.stubGlobal("localStorage", {
|
||||
getItem: vi.fn((key: string) => data.get(key) ?? null),
|
||||
setItem: vi.fn((key: string, value: string) => data.set(key, value)),
|
||||
removeItem: vi.fn((key: string) => data.delete(key)),
|
||||
});
|
||||
}
|
||||
|
||||
describe("queryStore query result export", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
installLocalStorage();
|
||||
setActivePinia(createPinia());
|
||||
mocks.ensureConnected.mockResolvedValue(undefined);
|
||||
mocks.getConfig.mockReturnValue({ id: "kingbase-1", name: "Kingbase", db_type: "kingbase", database: "app", query_timeout_secs: 30 });
|
||||
mocks.connectionIdentifierQuote.mockReturnValue("[");
|
||||
});
|
||||
|
||||
it("passes the live connection identifier quote to backend SQL export", async () => {
|
||||
const { useQueryStore } = await import("@/stores/queryStore");
|
||||
const store = useQueryStore();
|
||||
const tabId = store.createTab("kingbase-1", "app", "Query");
|
||||
const tab = store.tabs.find((item) => item.id === tabId)!;
|
||||
tab.sql = "SELECT select FROM audit_log";
|
||||
tab.lastExecutedSql = tab.sql;
|
||||
tab.result = {
|
||||
columns: ["select"],
|
||||
rows: [["value"]],
|
||||
affected_rows: 0,
|
||||
execution_time_ms: 1,
|
||||
};
|
||||
|
||||
const request = await store.buildQueryResultExportRequest(tabId, {
|
||||
exportId: "export-1",
|
||||
filePath: "audit.sql",
|
||||
format: "sql",
|
||||
exportTableName: "audit_log",
|
||||
exportColumnTypes: ["text"],
|
||||
});
|
||||
|
||||
expect(request?.identifierQuote).toBe("[");
|
||||
expect(mocks.connectionIdentifierQuote).toHaveBeenCalledWith("kingbase-1");
|
||||
});
|
||||
});
|
||||
@@ -6084,6 +6084,7 @@ export const useQueryStore = defineStore("query", () => {
|
||||
exportTableName: options.exportTableName,
|
||||
exportColumnTypes: options.exportColumnTypes,
|
||||
numericColumnRightAlign: settings.numericColumnRightAlign,
|
||||
identifierQuote: connStore.connectionIdentifierQuote(location.connectionId),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6119,6 +6120,7 @@ export const useQueryStore = defineStore("query", () => {
|
||||
executionId: uuid(),
|
||||
numericColumnRightAlign: settings.numericColumnRightAlign,
|
||||
columnComments,
|
||||
identifierQuote: connStore.connectionIdentifierQuote(tab.connectionId),
|
||||
};
|
||||
|
||||
const tracker = useExportTracker();
|
||||
|
||||
@@ -48,6 +48,7 @@ pub(super) fn write_sql_inserts(
|
||||
let data = sql_selected_data(context, false)?;
|
||||
let statement = build_data_grid_copy_insert_statement(DataGridCopyInsertStatementOptions {
|
||||
database_type: context.request.database_type,
|
||||
identifier_quote: context.request.identifier_quote.clone(),
|
||||
table_meta: context.request.table_meta.clone(),
|
||||
columns: data.columns,
|
||||
column_types: Some(data.column_types),
|
||||
@@ -98,6 +99,7 @@ pub(super) fn write_sql_updates(
|
||||
}
|
||||
let statements = build_data_grid_copy_update_statements(DataGridCopyUpdateStatementOptions {
|
||||
database_type: context.request.database_type,
|
||||
identifier_quote: context.request.identifier_quote.clone(),
|
||||
table_meta: table_meta.clone(),
|
||||
columns: data.columns,
|
||||
source_columns: Some(data.source_columns),
|
||||
@@ -301,7 +303,7 @@ pub(super) fn write_where_clause(
|
||||
value,
|
||||
context.selected_column_info[column_index],
|
||||
true,
|
||||
None,
|
||||
context.request.identifier_quote.as_deref(),
|
||||
);
|
||||
write_bytes(output, predicate.as_bytes())?;
|
||||
}
|
||||
|
||||
@@ -246,6 +246,53 @@ fn builds_updates_with_hidden_primary_keys_and_selected_columns() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sql_copy_honors_kingbase_mysql_compat_connection_identifier_quote() {
|
||||
let table_meta = DataGridTableMeta {
|
||||
catalog: None,
|
||||
database: None,
|
||||
schema: Some("audit-schema".to_string()),
|
||||
table_name: "events".to_string(),
|
||||
primary_keys: vec!["id".to_string()],
|
||||
columns: Some(vec![
|
||||
DataGridColumnInfo {
|
||||
name: "id".to_string(),
|
||||
data_type: "int".to_string(),
|
||||
is_nullable: false,
|
||||
is_primary_key: true,
|
||||
column_default: None,
|
||||
extra: None,
|
||||
},
|
||||
DataGridColumnInfo {
|
||||
name: "event_type".to_string(),
|
||||
data_type: "varchar".to_string(),
|
||||
is_nullable: false,
|
||||
is_primary_key: false,
|
||||
column_default: None,
|
||||
extra: None,
|
||||
},
|
||||
]),
|
||||
};
|
||||
|
||||
let mut insert = request(DataGridExtractorId::SqlInserts);
|
||||
insert.database_type = Some(DatabaseType::Kingbase);
|
||||
insert.identifier_quote = Some("`".to_string());
|
||||
insert.table_meta = Some(table_meta.clone());
|
||||
insert.columns = vec![column("id", 0), column("event_type", 1)];
|
||||
insert.rows = vec![vec![json!(1), json!("login")]];
|
||||
let insert_result = extract_data_grid_selection(insert).expect("Kingbase SQL INSERT extraction");
|
||||
assert_eq!(insert_result.text, "INSERT INTO `audit-schema`.`events` (`id`, `event_type`) VALUES (1, 'login');");
|
||||
|
||||
let mut updates = request(DataGridExtractorId::SqlUpdates);
|
||||
updates.database_type = Some(DatabaseType::Kingbase);
|
||||
updates.identifier_quote = Some("`".to_string());
|
||||
updates.table_meta = Some(table_meta);
|
||||
updates.columns = vec![column("id", 0), column("event_type", 1)];
|
||||
updates.rows = vec![vec![json!(1), json!("logout")]];
|
||||
let updates_result = extract_data_grid_selection(updates).expect("Kingbase SQL UPDATE extraction");
|
||||
assert_eq!(updates_result.text, "UPDATE `audit-schema`.`events` SET `event_type` = 'logout' WHERE `id` = 1;");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sql_update_computed_column_option_matches_the_frontend_capability() {
|
||||
let mut request = request(DataGridExtractorId::SqlUpdates);
|
||||
@@ -595,6 +642,7 @@ fn build_data_grid_copy_update_statements_returns_empty_for_mongodb() {
|
||||
use crate::data_grid_sql::{build_data_grid_copy_update_statements, DataGridCopyUpdateStatementOptions};
|
||||
let options = DataGridCopyUpdateStatementOptions {
|
||||
database_type: Some(DatabaseType::MongoDb),
|
||||
identifier_quote: None,
|
||||
table_meta: DataGridTableMeta {
|
||||
catalog: None,
|
||||
database: None,
|
||||
|
||||
@@ -90,6 +90,8 @@ pub struct DataGridSaveStatementOptions {
|
||||
pub struct DataGridCopyUpdateStatementOptions {
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub database_type: Option<DatabaseType>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub identifier_quote: Option<String>,
|
||||
pub table_meta: DataGridTableMeta,
|
||||
pub columns: Vec<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
@@ -104,6 +106,8 @@ pub struct DataGridCopyInsertStatementOptions {
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub database_type: Option<DatabaseType>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub identifier_quote: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub table_meta: Option<DataGridTableMeta>,
|
||||
pub columns: Vec<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
@@ -362,7 +366,7 @@ pub fn build_data_grid_copy_update_statements(options: DataGridCopyUpdateStateme
|
||||
options.table_meta.schema.as_deref(),
|
||||
options.table_meta.database.as_deref(),
|
||||
&options.table_meta.table_name,
|
||||
None,
|
||||
options.identifier_quote.as_deref(),
|
||||
);
|
||||
let mut statements = Vec::new();
|
||||
for row in &options.rows {
|
||||
@@ -374,7 +378,7 @@ pub fn build_data_grid_copy_update_statements(options: DataGridCopyUpdateStateme
|
||||
.map(|(column, index, info)| {
|
||||
format!(
|
||||
"{} = {}",
|
||||
data_grid_identifier(options.database_type, column, None),
|
||||
data_grid_identifier(options.database_type, column, options.identifier_quote.as_deref()),
|
||||
format_grid_sql_literal(row.get(*index).unwrap_or(&Value::Null), options.database_type, *info)
|
||||
)
|
||||
})
|
||||
@@ -393,7 +397,7 @@ pub fn build_data_grid_copy_update_statements(options: DataGridCopyUpdateStateme
|
||||
row.get(primary_key_indexes[index]).unwrap_or(&Value::Null),
|
||||
primary_key_info[index],
|
||||
false,
|
||||
None,
|
||||
options.identifier_quote.as_deref(),
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
@@ -447,18 +451,19 @@ pub fn build_data_grid_copy_insert_statement(options: DataGridCopyInsertStatemen
|
||||
let table = options.table_meta.as_ref().map_or_else(
|
||||
|| "table_name".to_string(),
|
||||
|meta| {
|
||||
crate::sql_dialect::qualified_table_name_with_catalog(
|
||||
data_grid_qualified_table_name(
|
||||
options.database_type,
|
||||
meta.catalog.as_deref(),
|
||||
meta.schema.as_deref(),
|
||||
meta.database.as_deref(),
|
||||
&meta.table_name,
|
||||
options.identifier_quote.as_deref(),
|
||||
)
|
||||
},
|
||||
);
|
||||
let columns = insert_columns
|
||||
.iter()
|
||||
.map(|(column, _, _)| quote_ident(options.database_type, column))
|
||||
.map(|(column, _, _)| data_grid_identifier(options.database_type, column, options.identifier_quote.as_deref()))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
let value_rows = options
|
||||
@@ -3233,6 +3238,7 @@ mod tests {
|
||||
fn builds_copy_update_statements() {
|
||||
let statements = build_data_grid_copy_update_statements(DataGridCopyUpdateStatementOptions {
|
||||
database_type: Some(DatabaseType::Postgres),
|
||||
identifier_quote: None,
|
||||
table_meta: DataGridTableMeta {
|
||||
catalog: None,
|
||||
database: None,
|
||||
@@ -3255,6 +3261,7 @@ mod tests {
|
||||
fn builds_copy_insert_statement_without_primary_keys() {
|
||||
let statement = build_data_grid_copy_insert_statement(DataGridCopyInsertStatementOptions {
|
||||
database_type: Some(DatabaseType::Mysql),
|
||||
identifier_quote: None,
|
||||
table_meta: Some(DataGridTableMeta {
|
||||
catalog: None,
|
||||
database: None,
|
||||
@@ -3281,6 +3288,7 @@ mod tests {
|
||||
fn copy_insert_keeps_json_cells_as_single_json_literals() {
|
||||
let statement = build_data_grid_copy_insert_statement(DataGridCopyInsertStatementOptions {
|
||||
database_type: Some(DatabaseType::Elasticsearch),
|
||||
identifier_quote: None,
|
||||
table_meta: None,
|
||||
columns: vec!["id".to_string(), "active".to_string(), "profile".to_string()],
|
||||
column_types: Some(vec![Some("number".to_string()), Some("boolean".to_string()), Some("json".to_string())]),
|
||||
@@ -3301,6 +3309,7 @@ mod tests {
|
||||
fn copy_insert_keeps_mysql_json_array_as_single_json_literal() {
|
||||
let statement = build_data_grid_copy_insert_statement(DataGridCopyInsertStatementOptions {
|
||||
database_type: Some(DatabaseType::Mysql),
|
||||
identifier_quote: None,
|
||||
table_meta: None,
|
||||
columns: vec!["data".to_string()],
|
||||
column_types: Some(vec![Some("json".to_string())]),
|
||||
@@ -3318,6 +3327,7 @@ mod tests {
|
||||
fn copy_insert_keeps_mysql_json_empty_array_as_single_json_literal() {
|
||||
let statement = build_data_grid_copy_insert_statement(DataGridCopyInsertStatementOptions {
|
||||
database_type: Some(DatabaseType::Mysql),
|
||||
identifier_quote: None,
|
||||
table_meta: None,
|
||||
columns: vec!["data".to_string()],
|
||||
column_types: Some(vec![Some("json".to_string())]),
|
||||
@@ -3335,6 +3345,7 @@ mod tests {
|
||||
fn copy_insert_keeps_mysql_json_object_as_single_json_literal() {
|
||||
let statement = build_data_grid_copy_insert_statement(DataGridCopyInsertStatementOptions {
|
||||
database_type: Some(DatabaseType::Mysql),
|
||||
identifier_quote: None,
|
||||
table_meta: None,
|
||||
columns: vec!["data".to_string()],
|
||||
column_types: Some(vec![Some("json".to_string())]),
|
||||
@@ -3352,6 +3363,7 @@ mod tests {
|
||||
fn builds_copy_insert_without_primary_keys_when_primary_keys_are_hidden() {
|
||||
let statement = build_data_grid_copy_insert_statement(DataGridCopyInsertStatementOptions {
|
||||
database_type: Some(DatabaseType::Mysql),
|
||||
identifier_quote: None,
|
||||
table_meta: Some(DataGridTableMeta {
|
||||
catalog: None,
|
||||
database: None,
|
||||
@@ -3379,6 +3391,7 @@ mod tests {
|
||||
fn builds_copy_insert_statement_row_by_row() {
|
||||
let statement = build_data_grid_copy_insert_statement(DataGridCopyInsertStatementOptions {
|
||||
database_type: Some(DatabaseType::Mysql),
|
||||
identifier_quote: None,
|
||||
table_meta: Some(DataGridTableMeta {
|
||||
catalog: None,
|
||||
database: None,
|
||||
@@ -3407,6 +3420,7 @@ mod tests {
|
||||
fn oracle_copy_insert_statement_uses_one_statement_per_row() {
|
||||
let statement = build_data_grid_copy_insert_statement(DataGridCopyInsertStatementOptions {
|
||||
database_type: Some(DatabaseType::Oracle),
|
||||
identifier_quote: None,
|
||||
table_meta: Some(DataGridTableMeta {
|
||||
catalog: None,
|
||||
database: None,
|
||||
@@ -3445,6 +3459,7 @@ mod tests {
|
||||
|
||||
let insert = build_data_grid_copy_insert_statement(DataGridCopyInsertStatementOptions {
|
||||
database_type: Some(DatabaseType::Mysql),
|
||||
identifier_quote: None,
|
||||
table_meta: Some(table_meta.clone()),
|
||||
columns: columns.clone(),
|
||||
column_types: None,
|
||||
@@ -3461,6 +3476,7 @@ mod tests {
|
||||
|
||||
let updates = build_data_grid_copy_update_statements(DataGridCopyUpdateStatementOptions {
|
||||
database_type: Some(DatabaseType::Mysql),
|
||||
identifier_quote: None,
|
||||
table_meta,
|
||||
columns,
|
||||
source_columns: None,
|
||||
@@ -3499,6 +3515,7 @@ mod tests {
|
||||
fn builds_copy_insert_statement_omits_postgres_tsvector_columns() {
|
||||
let statement = build_data_grid_copy_insert_statement(DataGridCopyInsertStatementOptions {
|
||||
database_type: Some(DatabaseType::Postgres),
|
||||
identifier_quote: None,
|
||||
table_meta: Some(DataGridTableMeta {
|
||||
catalog: None,
|
||||
database: None,
|
||||
@@ -3530,6 +3547,7 @@ mod tests {
|
||||
fn oracle_copy_insert_uses_result_column_types_for_date_literals() {
|
||||
let statement = build_data_grid_copy_insert_statement(DataGridCopyInsertStatementOptions {
|
||||
database_type: Some(DatabaseType::Oracle),
|
||||
identifier_quote: None,
|
||||
table_meta: None,
|
||||
columns: vec!["ID".to_string(), "CREATED_ON".to_string(), "RAW_TEXT".to_string()],
|
||||
column_types: Some(vec![
|
||||
@@ -5032,6 +5050,56 @@ mod tests {
|
||||
.all(|statement| statement.contains("`gc`.`docfileinfo`") && !statement.contains('"')));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn kingbase_mysql_compat_copy_insert_uses_backtick_identifiers() {
|
||||
let statement = build_data_grid_copy_insert_statement(DataGridCopyInsertStatementOptions {
|
||||
database_type: Some(DatabaseType::Kingbase),
|
||||
identifier_quote: Some("`".to_string()),
|
||||
table_meta: Some(DataGridTableMeta {
|
||||
catalog: None,
|
||||
database: None,
|
||||
schema: Some("audit-schema".to_string()),
|
||||
table_name: "events".to_string(),
|
||||
primary_keys: vec!["id".to_string()],
|
||||
columns: None,
|
||||
}),
|
||||
columns: vec!["id".to_string(), "event_type".to_string()],
|
||||
column_types: None,
|
||||
source_columns: None,
|
||||
rows: vec![vec![json!(1), json!("login")]],
|
||||
exclude_primary_keys: false,
|
||||
include_computed_columns: false,
|
||||
insert_mode: DataGridCopyInsertMode::Merged,
|
||||
});
|
||||
|
||||
assert_eq!(
|
||||
statement.as_deref(),
|
||||
Some("INSERT INTO `audit-schema`.`events` (`id`, `event_type`) VALUES (1, 'login');")
|
||||
);
|
||||
assert!(!statement.as_deref().unwrap_or_default().contains('"'));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn kingbase_mysql_compat_copy_update_uses_backtick_identifiers() {
|
||||
let statements = build_data_grid_copy_update_statements(DataGridCopyUpdateStatementOptions {
|
||||
database_type: Some(DatabaseType::Kingbase),
|
||||
identifier_quote: Some("`".to_string()),
|
||||
table_meta: DataGridTableMeta {
|
||||
catalog: None,
|
||||
database: None,
|
||||
schema: Some("audit-schema".to_string()),
|
||||
table_name: "events".to_string(),
|
||||
primary_keys: vec!["id".to_string()],
|
||||
columns: None,
|
||||
},
|
||||
columns: vec!["id".to_string(), "event_type".to_string()],
|
||||
source_columns: None,
|
||||
rows: vec![vec![json!(1), json!("logout")]],
|
||||
});
|
||||
|
||||
assert_eq!(statements, vec!["UPDATE `audit-schema`.`events` SET `event_type` = 'logout' WHERE `id` = 1;"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn vastbase_query_result_writes_use_resolved_search_path_schema() {
|
||||
let result = prepare_data_grid_save(DataGridSaveStatementOptions {
|
||||
@@ -6419,6 +6487,7 @@ mod tests {
|
||||
fn builds_clickhouse_copy_update_statements() {
|
||||
let statements = build_data_grid_copy_update_statements(DataGridCopyUpdateStatementOptions {
|
||||
database_type: Some(DatabaseType::ClickHouse),
|
||||
identifier_quote: None,
|
||||
table_meta: DataGridTableMeta {
|
||||
catalog: None,
|
||||
database: None,
|
||||
@@ -6448,6 +6517,7 @@ mod tests {
|
||||
|
||||
let copy_updates = build_data_grid_copy_update_statements(DataGridCopyUpdateStatementOptions {
|
||||
database_type: Some(DatabaseType::Doris),
|
||||
identifier_quote: None,
|
||||
table_meta: table_meta.clone(),
|
||||
columns: vec!["id".to_string(), "status".to_string()],
|
||||
source_columns: None,
|
||||
@@ -6460,6 +6530,7 @@ mod tests {
|
||||
|
||||
let copy_insert = build_data_grid_copy_insert_statement(DataGridCopyInsertStatementOptions {
|
||||
database_type: Some(DatabaseType::Doris),
|
||||
identifier_quote: None,
|
||||
table_meta: Some(table_meta.clone()),
|
||||
columns: vec!["id".to_string(), "status".to_string()],
|
||||
column_types: None,
|
||||
|
||||
@@ -8,7 +8,7 @@ use crate::connection::task_client_session_id;
|
||||
use crate::models::connection::DatabaseType;
|
||||
use crate::mysql_ddl_normalize::DdlNormalizeOptions;
|
||||
use crate::object_source_sql::build_export_object_source_sql;
|
||||
use crate::sql_dialect::{qualified_table_name, quote_table_identifier, uses_single_row_insert_statements};
|
||||
use crate::sql_dialect::{qualified_table_name, uses_single_row_insert_statements};
|
||||
use crate::transfer::{
|
||||
format_ch_array_sql_literal, format_pg_array_sql_literal, is_identity_column_extra,
|
||||
is_mysql_generated_column_extra, keyset_pagination_sql_with_identifier_quote, quote_identifier,
|
||||
@@ -266,6 +266,8 @@ pub struct ExportedTableSql {
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub database_type: Option<DatabaseType>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub identifier_quote: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub schema: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub table_name: Option<String>,
|
||||
@@ -291,6 +293,8 @@ pub struct BuildExportInsertStatementsOptions {
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub database_type: Option<DatabaseType>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub identifier_quote: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub schema: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub table_name: Option<String>,
|
||||
@@ -935,6 +939,7 @@ pub fn build_export_insert_statements(options: BuildExportInsertStatementsOption
|
||||
options.schema.as_deref(),
|
||||
options.table_name.as_deref(),
|
||||
options.qualified_table_name.as_deref(),
|
||||
options.identifier_quote.as_deref(),
|
||||
)?;
|
||||
let insert_columns = options
|
||||
.columns
|
||||
@@ -970,7 +975,13 @@ pub fn build_export_insert_statements(options: BuildExportInsertStatementsOption
|
||||
};
|
||||
let columns = insert_columns
|
||||
.iter()
|
||||
.map(|(_, column, _)| quote_table_identifier(options.database_type, column))
|
||||
.map(|(_, column, _)| {
|
||||
crate::sql_dialect::quote_table_data_identifier(
|
||||
options.database_type,
|
||||
column,
|
||||
options.identifier_quote.as_deref(),
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
let mut statements = Vec::new();
|
||||
@@ -1131,6 +1142,7 @@ pub fn build_database_sql_export(options: BuildDatabaseSqlExportOptions) -> Resu
|
||||
|
||||
let inserts = build_export_insert_statements(BuildExportInsertStatementsOptions {
|
||||
database_type: table.database_type,
|
||||
identifier_quote: table.identifier_quote.clone(),
|
||||
schema: table.schema,
|
||||
table_name: table.table_name,
|
||||
qualified_table_name: table.qualified_table_name,
|
||||
@@ -1156,6 +1168,7 @@ fn export_qualified_table_name(
|
||||
schema: Option<&str>,
|
||||
table_name: Option<&str>,
|
||||
qualified_name: Option<&str>,
|
||||
identifier_quote: Option<&str>,
|
||||
) -> Result<String, String> {
|
||||
if let Some(name) = qualified_name.filter(|name| !name.trim().is_empty()) {
|
||||
return Ok(name.to_string());
|
||||
@@ -1163,6 +1176,14 @@ fn export_qualified_table_name(
|
||||
let table_name = table_name
|
||||
.filter(|name| !name.trim().is_empty())
|
||||
.ok_or_else(|| "tableName is required when qualifiedTableName is not provided".to_string())?;
|
||||
if crate::sql_dialect::uses_connection_identifier_quote(database_type, identifier_quote) {
|
||||
return Ok(crate::sql_dialect::table_data_qualified_table_name(
|
||||
database_type,
|
||||
schema,
|
||||
table_name,
|
||||
identifier_quote,
|
||||
));
|
||||
}
|
||||
Ok(qualified_table_name(database_type, schema, table_name))
|
||||
}
|
||||
|
||||
@@ -1591,8 +1612,12 @@ fn write_database_export_rows<W: Write>(
|
||||
// path and the legacy typed INSERT writer. In particular, MySQL uses the
|
||||
// selected database rather than a schema-qualified table name.
|
||||
let qualified_table_name = crate::transfer::qualified_table(table, schema, db_type, None);
|
||||
// Batch database exports do not currently thread a per-connection identifier
|
||||
// quote through BuildDatabaseSqlExportOptions; Kingbase MySQL-compat users
|
||||
// should fall back to the single-table export path which carries the quote.
|
||||
let statements = build_export_insert_statements(BuildExportInsertStatementsOptions {
|
||||
database_type: Some(*db_type),
|
||||
identifier_quote: None,
|
||||
schema: (!schema.is_empty()).then(|| schema.to_string()),
|
||||
table_name: Some(table.to_string()),
|
||||
qualified_table_name: Some(qualified_table_name),
|
||||
@@ -3052,6 +3077,7 @@ mod tests {
|
||||
fn mysql_spatial_export_uses_wkb_constructor_and_preserves_srid() {
|
||||
let statements = build_export_insert_statements(BuildExportInsertStatementsOptions {
|
||||
database_type: Some(DatabaseType::Mysql),
|
||||
identifier_quote: None,
|
||||
schema: None,
|
||||
table_name: Some("places".to_string()),
|
||||
qualified_table_name: None,
|
||||
@@ -3129,6 +3155,7 @@ mod tests {
|
||||
fn database_specific_boolean_export_literals() {
|
||||
let sqlserver_statements = build_export_insert_statements(BuildExportInsertStatementsOptions {
|
||||
database_type: Some(DatabaseType::SqlServer),
|
||||
identifier_quote: None,
|
||||
schema: Some("dbo".to_string()),
|
||||
table_name: Some("flags".to_string()),
|
||||
qualified_table_name: None,
|
||||
@@ -3141,6 +3168,7 @@ mod tests {
|
||||
.unwrap();
|
||||
let postgres_statements = build_export_insert_statements(BuildExportInsertStatementsOptions {
|
||||
database_type: Some(DatabaseType::Postgres),
|
||||
identifier_quote: None,
|
||||
schema: Some("public".to_string()),
|
||||
table_name: Some("flags".to_string()),
|
||||
qualified_table_name: None,
|
||||
@@ -3168,6 +3196,7 @@ mod tests {
|
||||
fn sqlserver_export_prefixes_unicode_string_literals() {
|
||||
let statements = build_export_insert_statements(BuildExportInsertStatementsOptions {
|
||||
database_type: Some(DatabaseType::SqlServer),
|
||||
identifier_quote: None,
|
||||
schema: Some("dbo".to_string()),
|
||||
table_name: Some("people".to_string()),
|
||||
qualified_table_name: None,
|
||||
@@ -3212,6 +3241,7 @@ mod tests {
|
||||
fn mysql_export_inserts_escape_control_characters() {
|
||||
let statements = build_export_insert_statements(BuildExportInsertStatementsOptions {
|
||||
database_type: Some(DatabaseType::Mysql),
|
||||
identifier_quote: None,
|
||||
schema: None,
|
||||
table_name: Some("notes".to_string()),
|
||||
qualified_table_name: None,
|
||||
@@ -3234,6 +3264,7 @@ mod tests {
|
||||
let long_value = "x".repeat(300_000);
|
||||
let statements = build_export_insert_statements(BuildExportInsertStatementsOptions {
|
||||
database_type: Some(DatabaseType::Mysql),
|
||||
identifier_quote: None,
|
||||
schema: None,
|
||||
table_name: Some("payloads".to_string()),
|
||||
qualified_table_name: None,
|
||||
@@ -3253,6 +3284,7 @@ mod tests {
|
||||
fn sqlserver_export_caps_multi_row_insert_at_1000_rows() {
|
||||
let statements = build_export_insert_statements(BuildExportInsertStatementsOptions {
|
||||
database_type: Some(DatabaseType::SqlServer),
|
||||
identifier_quote: None,
|
||||
schema: Some("dbo".to_string()),
|
||||
table_name: Some("items".to_string()),
|
||||
qualified_table_name: None,
|
||||
@@ -3273,6 +3305,7 @@ mod tests {
|
||||
fn doris_export_inserts_escape_control_characters() {
|
||||
let statements = build_export_insert_statements(BuildExportInsertStatementsOptions {
|
||||
database_type: Some(DatabaseType::Doris),
|
||||
identifier_quote: None,
|
||||
schema: Some("warehouse".to_string()),
|
||||
table_name: Some("events".to_string()),
|
||||
qualified_table_name: None,
|
||||
@@ -3291,6 +3324,7 @@ mod tests {
|
||||
fn postgres_export_inserts_escape_control_characters() {
|
||||
let statements = build_export_insert_statements(BuildExportInsertStatementsOptions {
|
||||
database_type: Some(DatabaseType::Postgres),
|
||||
identifier_quote: None,
|
||||
schema: Some("public".to_string()),
|
||||
table_name: Some("notes".to_string()),
|
||||
qualified_table_name: None,
|
||||
@@ -3309,6 +3343,7 @@ mod tests {
|
||||
fn postgres_export_inserts_escape_quotes_and_backslashes_without_changing_plain_strings() {
|
||||
let statements = build_export_insert_statements(BuildExportInsertStatementsOptions {
|
||||
database_type: Some(DatabaseType::Postgres),
|
||||
identifier_quote: None,
|
||||
schema: Some("public".to_string()),
|
||||
table_name: Some("notes".to_string()),
|
||||
qualified_table_name: None,
|
||||
@@ -3337,6 +3372,7 @@ mod tests {
|
||||
fn postgres_jsonb_export_preserves_json_escape_sequences() {
|
||||
let statements = build_export_insert_statements(BuildExportInsertStatementsOptions {
|
||||
database_type: Some(DatabaseType::Postgres),
|
||||
identifier_quote: None,
|
||||
schema: Some("public".to_string()),
|
||||
table_name: Some("events".to_string()),
|
||||
qualified_table_name: None,
|
||||
@@ -3360,6 +3396,7 @@ mod tests {
|
||||
fn postgres_vector_export_preserves_pgvector_bracket_literals() {
|
||||
let statements = build_export_insert_statements(BuildExportInsertStatementsOptions {
|
||||
database_type: Some(DatabaseType::Postgres),
|
||||
identifier_quote: None,
|
||||
schema: Some("public".to_string()),
|
||||
table_name: Some("items".to_string()),
|
||||
qualified_table_name: None,
|
||||
@@ -3393,6 +3430,7 @@ mod tests {
|
||||
fn builds_batched_insert_statements_for_export() {
|
||||
let statements = build_export_insert_statements(BuildExportInsertStatementsOptions {
|
||||
database_type: Some(DatabaseType::Mysql),
|
||||
identifier_quote: None,
|
||||
schema: None,
|
||||
table_name: Some("users".to_string()),
|
||||
qualified_table_name: None,
|
||||
@@ -3417,6 +3455,7 @@ mod tests {
|
||||
fn oracle_export_inserts_use_one_statement_per_row() {
|
||||
let statements = build_export_insert_statements(BuildExportInsertStatementsOptions {
|
||||
database_type: Some(DatabaseType::Oracle),
|
||||
identifier_quote: None,
|
||||
schema: Some("APP".to_string()),
|
||||
table_name: Some("USERS".to_string()),
|
||||
qualified_table_name: None,
|
||||
@@ -3441,6 +3480,7 @@ mod tests {
|
||||
fn oracle_export_omits_synthetic_rowid_from_insert_columns() {
|
||||
let statements = build_export_insert_statements(BuildExportInsertStatementsOptions {
|
||||
database_type: Some(DatabaseType::Oracle),
|
||||
identifier_quote: None,
|
||||
schema: Some("APP".to_string()),
|
||||
table_name: Some("USERS".to_string()),
|
||||
qualified_table_name: None,
|
||||
@@ -3459,6 +3499,7 @@ mod tests {
|
||||
fn oceanbase_oracle_export_omits_synthetic_rowid_from_insert_columns() {
|
||||
let statements = build_export_insert_statements(BuildExportInsertStatementsOptions {
|
||||
database_type: Some(DatabaseType::OceanbaseOracle),
|
||||
identifier_quote: None,
|
||||
schema: Some("APP".to_string()),
|
||||
table_name: Some("USERS".to_string()),
|
||||
qualified_table_name: None,
|
||||
@@ -3477,6 +3518,7 @@ mod tests {
|
||||
fn non_oracle_export_preserves_dbx_rowid_named_column() {
|
||||
let statements = build_export_insert_statements(BuildExportInsertStatementsOptions {
|
||||
database_type: Some(DatabaseType::Mysql),
|
||||
identifier_quote: None,
|
||||
schema: None,
|
||||
table_name: Some("users".to_string()),
|
||||
qualified_table_name: None,
|
||||
@@ -3495,6 +3537,7 @@ mod tests {
|
||||
fn oracle_date_columns_export_as_date_literals() {
|
||||
let statements = build_export_insert_statements(BuildExportInsertStatementsOptions {
|
||||
database_type: Some(DatabaseType::Oracle),
|
||||
identifier_quote: None,
|
||||
schema: Some("APP".to_string()),
|
||||
table_name: Some("EVENTS".to_string()),
|
||||
qualified_table_name: None,
|
||||
@@ -3523,6 +3566,7 @@ mod tests {
|
||||
for database_type in [DatabaseType::Oracle, DatabaseType::OceanbaseOracle] {
|
||||
let statements = build_export_insert_statements(BuildExportInsertStatementsOptions {
|
||||
database_type: Some(database_type),
|
||||
identifier_quote: None,
|
||||
schema: Some("APP".to_string()),
|
||||
table_name: Some("EVENTS".to_string()),
|
||||
qualified_table_name: None,
|
||||
@@ -3594,6 +3638,7 @@ mod tests {
|
||||
fn non_oracle_timestamp_exports_keep_existing_literals() {
|
||||
let statements = build_export_insert_statements(BuildExportInsertStatementsOptions {
|
||||
database_type: Some(DatabaseType::Postgres),
|
||||
identifier_quote: None,
|
||||
schema: Some("public".to_string()),
|
||||
table_name: Some("events".to_string()),
|
||||
qualified_table_name: None,
|
||||
@@ -3618,6 +3663,7 @@ mod tests {
|
||||
fn mysql_bit_columns_export_without_quoted_string_values() {
|
||||
let statements = build_export_insert_statements(BuildExportInsertStatementsOptions {
|
||||
database_type: Some(DatabaseType::Mysql),
|
||||
identifier_quote: None,
|
||||
schema: None,
|
||||
table_name: Some("flags".to_string()),
|
||||
qualified_table_name: None,
|
||||
@@ -3639,6 +3685,7 @@ mod tests {
|
||||
fn dameng_bit_columns_export_as_numeric_literals() {
|
||||
let statements = build_export_insert_statements(BuildExportInsertStatementsOptions {
|
||||
database_type: Some(DatabaseType::Dameng),
|
||||
identifier_quote: None,
|
||||
schema: Some("DBX_TEST".to_string()),
|
||||
table_name: Some("FLAGS".to_string()),
|
||||
qualified_table_name: None,
|
||||
@@ -3660,6 +3707,7 @@ mod tests {
|
||||
fn dameng_strings_export_nul_as_chr_expression() {
|
||||
let statements = build_export_insert_statements(BuildExportInsertStatementsOptions {
|
||||
database_type: Some(DatabaseType::Dameng),
|
||||
identifier_quote: None,
|
||||
schema: Some("DBX_TEST".to_string()),
|
||||
table_name: Some("NUL_VALUES".to_string()),
|
||||
qualified_table_name: None,
|
||||
@@ -3701,6 +3749,7 @@ mod tests {
|
||||
fn mysql_export_uses_typed_literals_for_numeric_and_blob_columns() {
|
||||
let statements = build_export_insert_statements(BuildExportInsertStatementsOptions {
|
||||
database_type: Some(DatabaseType::Mysql),
|
||||
identifier_quote: None,
|
||||
schema: None,
|
||||
table_name: Some("t_test_01".to_string()),
|
||||
qualified_table_name: None,
|
||||
@@ -3727,6 +3776,7 @@ mod tests {
|
||||
fn temporal_columns_export_without_rfc3339_separator_or_utc_suffix() {
|
||||
let statements = build_export_insert_statements(BuildExportInsertStatementsOptions {
|
||||
database_type: Some(DatabaseType::Mysql),
|
||||
identifier_quote: None,
|
||||
schema: None,
|
||||
table_name: Some("events".to_string()),
|
||||
qualified_table_name: None,
|
||||
@@ -3760,6 +3810,7 @@ mod tests {
|
||||
fn postgres_timestamptz_export_keeps_timezone_without_rfc3339_t_separator() {
|
||||
let statements = build_export_insert_statements(BuildExportInsertStatementsOptions {
|
||||
database_type: Some(DatabaseType::Postgres),
|
||||
identifier_quote: None,
|
||||
schema: Some("public".to_string()),
|
||||
table_name: Some("events".to_string()),
|
||||
qualified_table_name: None,
|
||||
@@ -3786,6 +3837,7 @@ mod tests {
|
||||
fn sqlserver_rowversion_timestamp_type_is_not_treated_as_datetime() {
|
||||
let statements = build_export_insert_statements(BuildExportInsertStatementsOptions {
|
||||
database_type: Some(DatabaseType::SqlServer),
|
||||
identifier_quote: None,
|
||||
schema: Some("dbo".to_string()),
|
||||
table_name: Some("events".to_string()),
|
||||
qualified_table_name: None,
|
||||
@@ -3809,6 +3861,7 @@ mod tests {
|
||||
fn postgres_tsvector_columns_are_omitted_from_sql_insert_export() {
|
||||
let statements = build_export_insert_statements(BuildExportInsertStatementsOptions {
|
||||
database_type: Some(DatabaseType::Postgres),
|
||||
identifier_quote: None,
|
||||
schema: Some("public".to_string()),
|
||||
table_name: Some("articles".to_string()),
|
||||
qualified_table_name: None,
|
||||
@@ -3832,6 +3885,7 @@ mod tests {
|
||||
tables: vec![ExportedTableSql {
|
||||
display_name: "orders".to_string(),
|
||||
database_type: Some(DatabaseType::Mysql),
|
||||
identifier_quote: None,
|
||||
schema: None,
|
||||
table_name: Some("orders".to_string()),
|
||||
qualified_table_name: None,
|
||||
@@ -3918,6 +3972,7 @@ mod tests {
|
||||
fn dameng_identity_export_inserts_enable_identity_insert() {
|
||||
let statements = build_export_insert_statements(BuildExportInsertStatementsOptions {
|
||||
database_type: Some(DatabaseType::Dameng),
|
||||
identifier_quote: None,
|
||||
schema: Some("SYSDBA".to_string()),
|
||||
table_name: Some("USERS".to_string()),
|
||||
qualified_table_name: None,
|
||||
@@ -3945,6 +4000,7 @@ mod tests {
|
||||
tables: vec![ExportedTableSql {
|
||||
display_name: "users".to_string(),
|
||||
database_type: Some(DatabaseType::Mysql),
|
||||
identifier_quote: None,
|
||||
schema: None,
|
||||
table_name: Some("users".to_string()),
|
||||
qualified_table_name: None,
|
||||
@@ -4296,4 +4352,22 @@ mod tests {
|
||||
|
||||
let _ = std::fs::remove_dir_all(&scratch);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn kingbase_mysql_compat_export_insert_uses_backtick_identifiers() {
|
||||
let statements = build_export_insert_statements(BuildExportInsertStatementsOptions {
|
||||
database_type: Some(DatabaseType::Kingbase),
|
||||
identifier_quote: Some("`".to_string()),
|
||||
schema: Some("audit-schema".to_string()),
|
||||
table_name: Some("events".to_string()),
|
||||
qualified_table_name: None,
|
||||
columns: vec!["id".to_string(), "event_type".to_string()],
|
||||
column_types: vec![None, None],
|
||||
column_extras: vec![None, None],
|
||||
rows: vec![vec![json!(1), json!("login")]],
|
||||
batch_size: Some(100),
|
||||
})
|
||||
.unwrap();
|
||||
assert_eq!(statements, vec!["INSERT INTO `audit-schema`.`events` (`id`, `event_type`) VALUES (1, 'login');"]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,6 +104,8 @@ pub struct QueryResultExportRequest {
|
||||
pub numeric_column_right_align: bool,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub column_comments: Option<Vec<Option<String>>>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub identifier_quote: Option<String>,
|
||||
}
|
||||
|
||||
pub struct StagedExportTarget {
|
||||
@@ -300,6 +302,7 @@ struct SqlInsertWriter {
|
||||
database_type: DatabaseType,
|
||||
schema: Option<String>,
|
||||
table_name: String,
|
||||
identifier_quote: Option<String>,
|
||||
}
|
||||
|
||||
impl SqlInsertWriter {
|
||||
@@ -325,6 +328,7 @@ impl SqlInsertWriter {
|
||||
database_type: request.database_type,
|
||||
schema: request.schema.clone(),
|
||||
table_name,
|
||||
identifier_quote: request.identifier_quote.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -355,6 +359,7 @@ impl SqlInsertWriter {
|
||||
}
|
||||
let stmts = build_export_insert_statements(BuildExportInsertStatementsOptions {
|
||||
database_type: Some(self.database_type),
|
||||
identifier_quote: self.identifier_quote.clone(),
|
||||
schema: self.schema.clone(),
|
||||
table_name: Some(self.table_name.clone()),
|
||||
qualified_table_name: None,
|
||||
@@ -1869,6 +1874,7 @@ mod tests {
|
||||
export_column_types: None,
|
||||
numeric_column_right_align: false,
|
||||
column_comments: None,
|
||||
identifier_quote: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1179,6 +1179,7 @@ async fn try_export_native_table_stream(
|
||||
}
|
||||
let statements = build_export_insert_statements(BuildExportInsertStatementsOptions {
|
||||
database_type: Some(*db_type),
|
||||
identifier_quote: request.identifier_quote.clone(),
|
||||
schema: request.schema.clone(),
|
||||
table_name: Some(request.table_name.clone()),
|
||||
qualified_table_name: None,
|
||||
@@ -1993,6 +1994,7 @@ async fn export_table_data_core_inner(
|
||||
|
||||
let statements = build_export_insert_statements(BuildExportInsertStatementsOptions {
|
||||
database_type: Some(db_type),
|
||||
identifier_quote: request.identifier_quote.clone(),
|
||||
schema: request.schema.clone(),
|
||||
table_name: Some(request.table_name.clone()),
|
||||
qualified_table_name: None,
|
||||
@@ -2761,6 +2763,7 @@ mod tests {
|
||||
|
||||
let statements = build_export_insert_statements(BuildExportInsertStatementsOptions {
|
||||
database_type: Some(DatabaseType::Oracle),
|
||||
identifier_quote: request.identifier_quote,
|
||||
schema: request.schema,
|
||||
table_name: Some(request.table_name),
|
||||
qualified_table_name: None,
|
||||
|
||||
@@ -104,6 +104,7 @@ async fn live_clickhouse_query_result_export_xlsx_streams_random_order_query_onc
|
||||
export_table_name: None,
|
||||
export_column_types: None,
|
||||
column_comments: None,
|
||||
identifier_quote: None,
|
||||
numeric_column_right_align: false,
|
||||
};
|
||||
let done_seen = AtomicBool::new(false);
|
||||
|
||||
@@ -450,6 +450,7 @@ async fn live_mysql_query_result_export_xlsx_streams_single_query_without_duplic
|
||||
export_table_name: None,
|
||||
export_column_types: None,
|
||||
column_comments: None,
|
||||
identifier_quote: None,
|
||||
numeric_column_right_align: false,
|
||||
};
|
||||
let done_seen = AtomicBool::new(false);
|
||||
@@ -540,6 +541,7 @@ async fn live_mysql_xlsx_export_can_outlive_query_timeout_while_rows_keep_arrivi
|
||||
export_table_name: None,
|
||||
export_column_types: None,
|
||||
column_comments: None,
|
||||
identifier_quote: None,
|
||||
numeric_column_right_align: false,
|
||||
};
|
||||
let rows_exported = AtomicU64::new(0);
|
||||
|
||||
@@ -144,6 +144,7 @@ async fn live_postgres_query_result_export_uses_single_streamed_query() {
|
||||
export_table_name: None,
|
||||
export_column_types: None,
|
||||
column_comments: None,
|
||||
identifier_quote: None,
|
||||
numeric_column_right_align: false,
|
||||
};
|
||||
let done_seen = AtomicBool::new(false);
|
||||
@@ -224,6 +225,7 @@ async fn live_postgres_query_result_xlsx_preserves_temporal_cell_types() {
|
||||
export_table_name: None,
|
||||
export_column_types: None,
|
||||
column_comments: None,
|
||||
identifier_quote: None,
|
||||
numeric_column_right_align: false,
|
||||
};
|
||||
|
||||
@@ -293,6 +295,7 @@ async fn live_postgres_numeric_xlsx_ignores_fractional_trailing_zeros() {
|
||||
export_table_name: None,
|
||||
export_column_types: None,
|
||||
column_comments: None,
|
||||
identifier_quote: None,
|
||||
numeric_column_right_align: true,
|
||||
};
|
||||
|
||||
@@ -367,6 +370,7 @@ async fn live_postgres_truncated_batch_result_export_replays_safe_temp_setup() {
|
||||
export_table_name: None,
|
||||
export_column_types: None,
|
||||
column_comments: None,
|
||||
identifier_quote: None,
|
||||
numeric_column_right_align: false,
|
||||
};
|
||||
let csv_rows = AtomicU64::new(0);
|
||||
@@ -443,6 +447,7 @@ async fn live_postgres_xlsx_export_can_outlive_query_timeout_while_rows_keep_arr
|
||||
export_table_name: None,
|
||||
export_column_types: None,
|
||||
column_comments: None,
|
||||
identifier_quote: None,
|
||||
numeric_column_right_align: false,
|
||||
};
|
||||
let rows_exported = AtomicU64::new(0);
|
||||
@@ -510,6 +515,7 @@ async fn live_postgres_stream_still_times_out_without_progress_and_recovers() {
|
||||
export_table_name: None,
|
||||
export_column_types: None,
|
||||
column_comments: None,
|
||||
identifier_quote: None,
|
||||
numeric_column_right_align: false,
|
||||
};
|
||||
let started_at = Instant::now();
|
||||
|
||||
@@ -70,6 +70,7 @@ async fn postgres_tsvector_generated_columns_are_readable_and_omitted_from_inser
|
||||
};
|
||||
let copy_insert = build_data_grid_copy_insert_statement(DataGridCopyInsertStatementOptions {
|
||||
database_type: Some(DatabaseType::Postgres),
|
||||
identifier_quote: None,
|
||||
table_meta: Some(table_meta),
|
||||
columns: result.columns.clone(),
|
||||
column_types: None,
|
||||
@@ -85,6 +86,7 @@ async fn postgres_tsvector_generated_columns_are_readable_and_omitted_from_inser
|
||||
|
||||
let export_insert = build_export_insert_statements(BuildExportInsertStatementsOptions {
|
||||
database_type: Some(DatabaseType::Postgres),
|
||||
identifier_quote: None,
|
||||
schema: Some(schema.clone()),
|
||||
table_name: Some("articles".to_string()),
|
||||
qualified_table_name: None,
|
||||
|
||||
@@ -1201,6 +1201,7 @@ async fn live_sqlserver_query_result_export_streams_cte_query_to_csv() {
|
||||
export_table_name: None,
|
||||
export_column_types: None,
|
||||
column_comments: None,
|
||||
identifier_quote: None,
|
||||
numeric_column_right_align: false,
|
||||
};
|
||||
let done_seen = AtomicBool::new(false);
|
||||
|
||||
@@ -119,6 +119,7 @@ async fn live_sqlserver_xlsx_export_can_outlive_query_timeout_while_rows_keep_ar
|
||||
export_table_name: None,
|
||||
export_column_types: None,
|
||||
column_comments: None,
|
||||
identifier_quote: None,
|
||||
numeric_column_right_align: false,
|
||||
};
|
||||
let rows_exported = AtomicU64::new(0);
|
||||
|
||||
Reference in New Issue
Block a user