diff --git a/apps/desktop/src/components/grid/DataGrid.vue b/apps/desktop/src/components/grid/DataGrid.vue
index ba084ca4ec..f1ab7ac673 100644
--- a/apps/desktop/src/components/grid/DataGrid.vue
+++ b/apps/desktop/src/components/grid/DataGrid.vue
@@ -265,7 +265,7 @@ import { buildColumnIndexMap, columnIndexColorClass, columnIndexMetadataRequestC
import { supportsTableStructureEditing } from "@/lib/database/databaseCapabilities";
import { rememberDataGridConditionHistory } from "@/lib/dataGrid/dataGridConditionHistory";
import { restoreDataGridLocalColumnFilters, serializeDataGridLocalColumnFilters } from "@/lib/dataGrid/dataGridLocalColumnFilterState";
-import { effectiveDatabaseTypeForConnection } from "@/lib/database/jdbcDialect";
+import { effectiveDatabaseTypeForConnection, gaussdbCountQueryDopHint } from "@/lib/database/jdbcDialect";
import { mongoCollectionSupportsIndexes, supportsMongoIndexMutations } from "@/lib/mongo/mongoCapabilities";
import { refreshLoadedMongoIndexes } from "@/lib/mongo/mongoIndexMetadata";
import { isProtectedMongoIndex, mongoDropAllIndexesPreview, mongoDropIndexFailureCount, mongoDropIndexPreview } from "@/lib/sidebar/mongoCollectionMutation";
@@ -3286,6 +3286,7 @@ async function lastPage() {
async function buildCurrentCountTarget(): Promise<{ sql: string; schema?: string } | undefined> {
if (props.countSql) return { sql: props.countSql, schema: props.schema };
if (props.tableMeta) {
+ const countHint = resolvedDatabaseType.value === "gaussdb" && props.connectionId ? gaussdbCountQueryDopHint(connectionStore.getConfig(props.connectionId)) : undefined;
const sql = await buildDataGridCountSql({
databaseType: props.databaseType,
identifierQuote: connectionStore.connectionIdentifierQuote?.(props.connectionId),
@@ -3294,6 +3295,7 @@ async function buildCurrentCountTarget(): Promise<{ sql: string; schema?: string
schema: props.tableMeta.schema,
tableName: props.tableMeta.tableName,
whereInput: currentWhereInput(),
+ countHint,
});
return {
sql,
diff --git a/apps/desktop/src/i18n/locales/en.ts b/apps/desktop/src/i18n/locales/en.ts
index 0a35d478ff..4fe1edff76 100644
--- a/apps/desktop/src/i18n/locales/en.ts
+++ b/apps/desktop/src/i18n/locales/en.ts
@@ -922,6 +922,8 @@ export default {
gaussdbTargetServerTypeSlave: "Slave (standby)",
gaussdbTargetServerTypeAny: "Any (no preference)",
gaussdbTargetServerTypeHint: "Controls which node in a GaussDB cluster the JDBC driver connects to. Master tries the primary, slave tries a standby, any connects to whichever is available. Only applies in M (JDBC) mode.",
+ gaussdbCountQueryDop: "COUNT(*) parallelism",
+ gaussdbCountQueryDopHint: "Sets the query_dop (degree of parallelism) for COUNT(*) queries on large tables. Higher values use more resources. Set to 1 (default) to disable the optimizer hint.",
saveAndConnect: "Save & Connect",
save: "Save",
editTitle: "Edit Connection",
@@ -2121,6 +2123,7 @@ export default {
noResults: "No results",
edit: "Edit",
delete: "Delete",
+ disabled: "Disabled",
back: "Back",
},
dateTimePicker: {
diff --git a/apps/desktop/src/i18n/locales/es.ts b/apps/desktop/src/i18n/locales/es.ts
index 86c70e2cdf..2bf2d06a91 100644
--- a/apps/desktop/src/i18n/locales/es.ts
+++ b/apps/desktop/src/i18n/locales/es.ts
@@ -740,6 +740,8 @@ export default withEnglishFallback({
gaussdbTargetServerTypeSlave: "Réplica (en espera)",
gaussdbTargetServerTypeAny: "Cualquiera (sin preferencia)",
gaussdbTargetServerTypeHint: "Controla a qué nodo del clúster GaussDB se conecta el controlador JDBC. Se aplica solo al modo M (JDBC).",
+ gaussdbCountQueryDop: "Paralelismo de COUNT(*)",
+ gaussdbCountQueryDopHint: "Establece query_dop (grado de paralelismo) para consultas COUNT(*) en tablas grandes. Los valores más altos usan más recursos. Establezca 1 (predeterminado) para desactivar la sugerencia del optimizador.",
saveAndConnect: "Guardar y conectar",
save: "Guardar",
editTitle: "Editar conexión",
@@ -2056,6 +2058,7 @@ export default withEnglishFallback({
noResults: "Sin resultados",
edit: "Editar",
delete: "Eliminar",
+ disabled: "Desactivado",
back: "Volver",
},
dateTimePicker: {
diff --git a/apps/desktop/src/i18n/locales/it.ts b/apps/desktop/src/i18n/locales/it.ts
index eea46cff3c..323e4f7aeb 100644
--- a/apps/desktop/src/i18n/locales/it.ts
+++ b/apps/desktop/src/i18n/locales/it.ts
@@ -739,6 +739,8 @@ export default withEnglishFallback({
gaussdbTargetServerTypeSlave: "Slave (standby)",
gaussdbTargetServerTypeAny: "Qualsiasi (nessuna preferenza)",
gaussdbTargetServerTypeHint: "Controlla il nodo del cluster GaussDB a cui si connette il driver JDBC. Si applica solo alla modalità M (JDBC).",
+ gaussdbCountQueryDop: "Parallelismo COUNT(*)",
+ gaussdbCountQueryDopHint: "Imposta query_dop (grado di parallelismo) per le query COUNT(*) su tabelle di grandi dimensioni. Valori più elevati usano più risorse. Imposta 1 (predefinito) per disabilitare l'hint dell'ottimizzatore.",
saveAndConnect: "Salva & Connetti",
save: "Salva",
editTitle: "Modifica Connessione",
@@ -2054,6 +2056,7 @@ export default withEnglishFallback({
noResults: "Nessun risultato",
edit: "Modifica",
delete: "Elimina",
+ disabled: "Disabilitato",
back: "Indietro",
},
dateTimePicker: {
diff --git a/apps/desktop/src/i18n/locales/ja.ts b/apps/desktop/src/i18n/locales/ja.ts
index 07e09163e6..0e07073a25 100644
--- a/apps/desktop/src/i18n/locales/ja.ts
+++ b/apps/desktop/src/i18n/locales/ja.ts
@@ -705,6 +705,8 @@ export default withEnglishFallback({
gaussdbTargetServerTypeSlave: "スレーブ(スタンバイ)",
gaussdbTargetServerTypeAny: "任意(優先なし)",
gaussdbTargetServerTypeHint: "JDBC ドライバーが接続する GaussDB クラスターのノードを制御します。M モード(JDBC)にのみ適用されます。",
+ gaussdbCountQueryDop: "COUNT(*) の並列度",
+ gaussdbCountQueryDopHint: "大規模テーブルの COUNT(*) クエリに query_dop(並列度)を設定します。値を大きくするとより多くのリソースを使用します。オプティマイザーヒントを無効にするには 1(既定値)を設定します。",
saveAndConnect: "保存して接続",
save: "保存",
editTitle: "接続を編集",
@@ -2081,6 +2083,7 @@ export default withEnglishFallback({
noResults: "結果なし",
edit: "編集",
delete: "削除",
+ disabled: "無効",
back: "戻る",
},
dateTimePicker: {
diff --git a/apps/desktop/src/i18n/locales/ko.ts b/apps/desktop/src/i18n/locales/ko.ts
index a82e355f96..c902eb9293 100644
--- a/apps/desktop/src/i18n/locales/ko.ts
+++ b/apps/desktop/src/i18n/locales/ko.ts
@@ -814,6 +814,8 @@ export default withEnglishFallback({
gaussdbTargetServerTypeSlave: "슬레이브(대기)",
gaussdbTargetServerTypeAny: "임의(선호 없음)",
gaussdbTargetServerTypeHint: "JDBC 드라이버가 연결할 GaussDB 클러스터 노드를 제어합니다. M 모드(JDBC)에만 적용됩니다.",
+ gaussdbCountQueryDop: "COUNT(*) 병렬 처리 수준",
+ gaussdbCountQueryDopHint: "대형 테이블의 COUNT(*) 쿼리에 query_dop(병렬 처리 수준)를 설정합니다. 값이 클수록 더 많은 리소스를 사용합니다. 옵티마이저 힌트를 비활성화하려면 1(기본값)로 설정하세요.",
saveAndConnect: "저장 후 연결",
save: "저장",
editTitle: "연결 편집",
@@ -1974,6 +1976,7 @@ export default withEnglishFallback({
noResults: "결과 없음",
edit: "편집",
delete: "삭제",
+ disabled: "비활성화",
back: "뒤로",
},
dateTimePicker: {
diff --git a/apps/desktop/src/i18n/locales/pt-BR.ts b/apps/desktop/src/i18n/locales/pt-BR.ts
index a2f90ee760..a62759b48f 100644
--- a/apps/desktop/src/i18n/locales/pt-BR.ts
+++ b/apps/desktop/src/i18n/locales/pt-BR.ts
@@ -740,6 +740,8 @@ export default withEnglishFallback({
gaussdbTargetServerTypeSlave: "Slave (standby)",
gaussdbTargetServerTypeAny: "Qualquer (sem preferência)",
gaussdbTargetServerTypeHint: "Controla a qual nó do cluster GaussDB o driver JDBC se conecta. Aplica-se apenas ao modo M (JDBC).",
+ gaussdbCountQueryDop: "Paralelismo de COUNT(*)",
+ gaussdbCountQueryDopHint: "Define query_dop (grau de paralelismo) para consultas COUNT(*) em tabelas grandes. Valores maiores usam mais recursos. Defina como 1 (padrão) para desativar a dica do otimizador.",
saveAndConnect: "Salvar e Conectar",
save: "Salvar",
editTitle: "Editar Conexão",
@@ -2056,6 +2058,7 @@ export default withEnglishFallback({
noResults: "Sem resultados",
edit: "Editar",
delete: "Excluir",
+ disabled: "Desativado",
back: "Voltar",
},
dateTimePicker: {
diff --git a/apps/desktop/src/i18n/locales/zh-CN.ts b/apps/desktop/src/i18n/locales/zh-CN.ts
index 47cd22a920..f155b0f3ee 100644
--- a/apps/desktop/src/i18n/locales/zh-CN.ts
+++ b/apps/desktop/src/i18n/locales/zh-CN.ts
@@ -846,6 +846,8 @@ export default withEnglishFallback({
gaussdbTargetServerTypeSlave: "备节点(Standby)",
gaussdbTargetServerTypeAny: "任意(不指定)",
gaussdbTargetServerTypeHint: "控制 JDBC 驱动连接到 GaussDB 集群中的哪个节点。主节点优先连接主库,备节点连接备库,任意节点连接可用节点。仅适用于 M 模式(JDBC)。",
+ gaussdbCountQueryDop: "COUNT(*) 并行度",
+ gaussdbCountQueryDopHint: "设置 COUNT(*) 查询的 query_dop(并行度),用于大表行数统计。较高的值会消耗更多资源。设置为 1(默认)则不传入优化器提示。",
saveAndConnect: "保存并连接",
save: "保存",
editTitle: "编辑连接",
@@ -2045,6 +2047,7 @@ export default withEnglishFallback({
noResults: "无结果",
edit: "编辑",
delete: "删除",
+ disabled: "禁用",
back: "返回",
},
dateTimePicker: {
diff --git a/apps/desktop/src/i18n/locales/zh-TW.ts b/apps/desktop/src/i18n/locales/zh-TW.ts
index 92d1e2b5e9..0c554e11ff 100644
--- a/apps/desktop/src/i18n/locales/zh-TW.ts
+++ b/apps/desktop/src/i18n/locales/zh-TW.ts
@@ -739,6 +739,8 @@ export default withEnglishFallback({
gaussdbTargetServerTypeSlave: "備節點(Standby)",
gaussdbTargetServerTypeAny: "任意(不指定)",
gaussdbTargetServerTypeHint: "控制 JDBC 驅動程式連線到 GaussDB 叢集中的哪個節點。僅適用於 M 模式(JDBC)。",
+ gaussdbCountQueryDop: "COUNT(*) 平行度",
+ gaussdbCountQueryDopHint: "設定大型資料表 COUNT(*) 查詢的 query_dop(平行度)。較高的值會使用更多資源。設定為 1(預設值)可停用最佳化器提示。",
saveAndConnect: "儲存並連線",
save: "儲存",
editTitle: "編輯連線",
@@ -2055,6 +2057,7 @@ export default withEnglishFallback({
noResults: "無結果",
edit: "編輯",
delete: "刪除",
+ disabled: "停用",
back: "返回",
},
dateTimePicker: {
diff --git a/apps/desktop/src/lib/__tests__/database/jdbcDialect.spec.ts b/apps/desktop/src/lib/__tests__/database/jdbcDialect.spec.ts
index 6444dd1902..2d860d1f04 100644
--- a/apps/desktop/src/lib/__tests__/database/jdbcDialect.spec.ts
+++ b/apps/desktop/src/lib/__tests__/database/jdbcDialect.spec.ts
@@ -11,11 +11,14 @@ import {
connectionUsesDatabaseObjectTreeMode,
effectiveDatabaseTypeForConnection,
gaussdbConnectionMode,
+ gaussdbCountQueryDop,
+ gaussdbCountQueryDopHint,
gaussdbIdentifierQuoteOverride,
gaussdbIdentifierQuoteStyle,
gaussdbTargetServerType,
inferJdbcDialect,
setGaussdbConnectionMode,
+ setGaussdbCountQueryDop,
setGaussdbIdentifierQuoteStyle,
setGaussdbTargetServerType,
supportsGaussdbIdentifierQuoteStyle,
@@ -236,6 +239,24 @@ describe("GaussDB connection mode", () => {
expect(gaussdbTargetServerType(connection)).toBe("any");
expect(connection.external_config).toEqual({ gaussdbTargetServerType: "any" });
});
+
+ it("keeps count query parallelism disabled until explicitly configured", () => {
+ const connection = { db_type: "gaussdb", external_config: { retained: true } } as ConnectionConfig;
+
+ expect(gaussdbCountQueryDop(connection)).toBe(1);
+ expect(gaussdbCountQueryDopHint(connection)).toBeUndefined();
+
+ setGaussdbCountQueryDop(connection, 8);
+ expect(connection.external_config).toEqual({ retained: true, gaussdbCountQueryDop: 8 });
+ expect(gaussdbCountQueryDopHint(connection)).toBe("/*+ set(query_dop 8) */");
+
+ connection.external_config = { retained: true, gaussdbCountQueryDop: 32 };
+ expect(gaussdbCountQueryDop(connection)).toBe(1);
+ expect(gaussdbCountQueryDopHint(connection)).toBeUndefined();
+
+ setGaussdbCountQueryDop(connection, 1);
+ expect(connection.external_config).toEqual({ retained: true });
+ });
});
describe("query execution schema", () => {
diff --git a/apps/desktop/src/lib/dataGrid/dataGridSql.ts b/apps/desktop/src/lib/dataGrid/dataGridSql.ts
index c76e591f8f..7b9cccdef2 100644
--- a/apps/desktop/src/lib/dataGrid/dataGridSql.ts
+++ b/apps/desktop/src/lib/dataGrid/dataGridSql.ts
@@ -108,6 +108,9 @@ export interface DataGridCountSqlOptions {
schema?: string;
tableName: string;
whereInput?: string;
+ /** Optional optimizer hint injected between SELECT and the select list.
+ * Example: "/*+ set(query_dop 32) */" for GaussDB parallel COUNT(*). */
+ countHint?: string;
}
export interface HiveTablePropertiesSqlOptions {
diff --git a/apps/desktop/src/lib/database/jdbcDialect.ts b/apps/desktop/src/lib/database/jdbcDialect.ts
index f67e283bfb..24ded4d738 100644
--- a/apps/desktop/src/lib/database/jdbcDialect.ts
+++ b/apps/desktop/src/lib/database/jdbcDialect.ts
@@ -7,9 +7,11 @@ type JdbcDialectConnection = Partial
& Partial>, value: GaussdbCountQueryDop) {
+ const external = externalConfigRecord(connection.external_config);
+ if (value === 1) {
+ delete external[GAUSSDB_COUNT_QUERY_DOP_KEY];
+ } else {
+ external[GAUSSDB_COUNT_QUERY_DOP_KEY] = value;
+ }
+ connection.external_config = Object.keys(external).length > 0 ? external : undefined;
+}
+
+export function gaussdbCountQueryDopHint(connection: JdbcDialectConnection | undefined): string | undefined {
+ const dop = gaussdbCountQueryDop(connection);
+ return dop > 1 ? `/*+ set(query_dop ${dop}) */` : undefined;
+}
+
function isJdbcAseProfile(connection?: JdbcDialectConnection): boolean {
if (connection?.db_type !== "jdbc") return false;
const explicitIdentity = [connection.driver_profile, connection.driver_label, connection.database_info?.productName].filter(Boolean).join("\n");
diff --git a/apps/desktop/src/stores/__tests__/queryStore.hiddenPrimaryKey.spec.ts b/apps/desktop/src/stores/__tests__/queryStore.hiddenPrimaryKey.spec.ts
index 6deb52a078..4c859acfa7 100644
--- a/apps/desktop/src/stores/__tests__/queryStore.hiddenPrimaryKey.spec.ts
+++ b/apps/desktop/src/stores/__tests__/queryStore.hiddenPrimaryKey.spec.ts
@@ -1284,6 +1284,59 @@ describe("queryStore hidden primary key editing", () => {
expect(tab.resultTotalRowCountLoading).toBe(false);
});
+ it.each([
+ ["disabled by default", undefined, undefined],
+ ["explicitly enabled", { gaussdbCountQueryDop: 8 }, "/*+ set(query_dop 8) */"],
+ ])("keeps GaussDB count parallelism %s", async (_label, externalConfig, expectedCountHint) => {
+ editorSettings.autoCalculateTotalRows = true;
+ getConnectionConfig.mockReturnValue({
+ id: "gaussdb-1",
+ name: "GaussDB",
+ db_type: "gaussdb",
+ database: "app",
+ query_timeout_secs: 30,
+ external_config: externalConfig,
+ });
+ executeMulti.mockResolvedValue([
+ {
+ columns: ["id", "name"],
+ rows: Array.from({ length: 100 }, (_, index) => [index + 1, `user-${index + 1}`]),
+ affected_rows: 0,
+ execution_time_ms: 1,
+ },
+ ]);
+
+ const { useQueryStore } = await import("@/stores/queryStore");
+ const store = useQueryStore();
+ const tabId = store.createTab("gaussdb-1", "app", "users", "data", "public");
+ store.setTableMeta(tabId, {
+ schema: "public",
+ tableName: "users",
+ columns: [
+ { name: "id", data_type: "int", is_nullable: false, is_primary_key: true, column_default: null, extra: null },
+ { name: "name", data_type: "varchar", is_nullable: true, is_primary_key: false, column_default: null, extra: null },
+ ],
+ primaryKeys: ["id"],
+ });
+
+ await store.executeTabSql(tabId, "SELECT id, name FROM users LIMIT 100", {
+ pagination: { limit: 100, offset: 0 },
+ });
+
+ await vi.waitFor(() =>
+ expect(buildDataGridCountSql).toHaveBeenCalledWith({
+ databaseType: "gaussdb",
+ identifierQuote: undefined,
+ catalog: undefined,
+ database: undefined,
+ schema: "public",
+ tableName: "users",
+ whereInput: undefined,
+ countHint: expectedCountHint,
+ }),
+ );
+ });
+
it("stops appending when a SQL Server query has no bounded next-page plan", async () => {
getConnectionConfig.mockReturnValue({ id: "sqlserver-1", name: "SQL Server", db_type: "sqlserver", database: "app", query_timeout_secs: 30 });
analyzeEditableQueryEditability.mockResolvedValue({ editable: false, reason: "complex-query" });
diff --git a/apps/desktop/src/stores/queryStore.ts b/apps/desktop/src/stores/queryStore.ts
index 21b61d5bd1..bfedacc243 100644
--- a/apps/desktop/src/stores/queryStore.ts
+++ b/apps/desktop/src/stores/queryStore.ts
@@ -43,7 +43,7 @@ import { dataTabExecutionDatabase } from "@/lib/table/dataTabExecutionDatabase";
import { tableOpenPageLimit } from "@/lib/table/tableOpenPageLimit";
import { getCachedTableMetadata, loadTableIndexes, loadTableMetadata, type TableMetadataRequest } from "@/lib/metadata/tableMetadataCache";
import { buildTableSelectSql, quoteTableDataIdentifier } from "@/lib/table/tableSelectSql";
-import { connectionObjectTreeNodeSchema, connectionQueryExecutionSchema, connectionUsesDatabaseObjectTreeMode, effectiveDatabaseTypeForConnection, metadataSchemaForConnection } from "@/lib/database/jdbcDialect";
+import { connectionObjectTreeNodeSchema, connectionQueryExecutionSchema, connectionUsesDatabaseObjectTreeMode, effectiveDatabaseTypeForConnection, gaussdbCountQueryDopHint, metadataSchemaForConnection } from "@/lib/database/jdbcDialect";
import { frontendQueryTimeoutDelayMs, frontendQueryTimeoutSecsForSql, queryTimeoutSecsForConnection } from "@/lib/sql/queryTimeout";
import { queryResultNameFromPreamble, queryResultSourceLabel } from "@/lib/sql/queryResultSource";
import { beginDataGridNativeSelectionBlock, finishDataGridNativeSelectionBlock } from "@/lib/dataGrid/dataGridNativeSelection";
@@ -4866,6 +4866,7 @@ export const useQueryStore = defineStore("query", () => {
schema: tableMeta.schema,
tableName: tableMeta.tableName,
whereInput: current.whereInput?.trim() || undefined,
+ countHint: effectiveDbType === "gaussdb" ? gaussdbCountQueryDopHint(useConnectionStore().getConfig(current.connectionId)) : undefined,
};
})()
: undefined;
diff --git a/crates/dbx-core/src/data_grid_sql.rs b/crates/dbx-core/src/data_grid_sql.rs
index 1f6517a020..72aab6940e 100644
--- a/crates/dbx-core/src/data_grid_sql.rs
+++ b/crates/dbx-core/src/data_grid_sql.rs
@@ -258,6 +258,10 @@ pub struct DataGridCountSqlOptions {
pub table_name: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub where_input: Option,
+ /// Optional optimizer hint injected between SELECT and the select list.
+ /// Example: "/*+ set(query_dop 32) */" for GaussDB parallel COUNT(*).
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub count_hint: Option,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
@@ -815,7 +819,9 @@ pub fn build_data_grid_count_sql(options: DataGridCountSqlOptions) -> String {
};
let predicate = crate::sql_dialect::normalize_where_input(options.where_input.as_deref());
let where_clause = if predicate.is_empty() { String::new() } else { format!(" WHERE ({predicate})") };
- format!("SELECT COUNT(*) AS cnt FROM {table}{where_clause}")
+ let hint = options.count_hint.as_deref().unwrap_or("");
+ let hint_part = if hint.is_empty() { String::new() } else { format!(" {hint}") };
+ format!("SELECT{hint_part} COUNT(*) AS cnt FROM {table}{where_clause}")
}
pub fn build_hive_table_properties_sql(options: HiveTablePropertiesSqlOptions) -> String {
@@ -3104,6 +3110,7 @@ mod tests {
schema: Some("SS".to_string()),
table_name: "SS_User".to_string(),
where_input: Some("SSUSR_IsActive = 'Y'".to_string()),
+ count_hint: None,
}),
"SELECT COUNT(*) AS cnt FROM \"SS\".\"SS_User\" WHERE (SSUSR_IsActive = 'Y')"
);
@@ -4204,6 +4211,7 @@ mod tests {
schema: Some("public".to_string()),
table_name: "users".to_string(),
where_input: Some("WHERE active = true;".to_string()),
+ count_hint: None,
}),
"SELECT COUNT(*) AS cnt FROM \"public\".\"users\" WHERE (active = true)"
);
@@ -4216,6 +4224,7 @@ mod tests {
schema: Some("sales".to_string()),
table_name: "orders".to_string(),
where_input: Some("WHERE active = true;".to_string()),
+ count_hint: None,
}),
"SELECT COUNT(*) AS cnt FROM `iceberg_catalog`.`sales`.`orders` WHERE (active = true)"
);
@@ -4229,6 +4238,7 @@ mod tests {
schema: None,
table_name: "orders".to_string(),
where_input: Some("WHERE active = true;".to_string()),
+ count_hint: None,
}),
"SELECT COUNT(*) AS cnt FROM `iceberg_catalog`.`sales`.`orders` WHERE (active = true)"
);
@@ -4241,6 +4251,7 @@ mod tests {
schema: None,
table_name: "orders".to_string(),
where_input: None,
+ count_hint: None,
}),
"SELECT COUNT(*) AS cnt FROM `hive_catalog`.`orders`"
);
@@ -4253,6 +4264,7 @@ mod tests {
schema: Some("cqbq_ls".to_string()),
table_name: "ANALYZE".to_string(),
where_input: None,
+ count_hint: None,
}),
"SELECT COUNT(*) AS cnt FROM `cqbq_ls`.`ANALYZE`"
);
@@ -4265,6 +4277,7 @@ mod tests {
schema: Some("schema_01".to_string()),
table_name: "table_01".to_string(),
where_input: None,
+ count_hint: None,
}),
"SELECT COUNT(*) AS cnt FROM schema_01.table_01"
);
@@ -4277,11 +4290,72 @@ mod tests {
schema: Some("App Schema".to_string()),
table_name: "order".to_string(),
where_input: None,
+ count_hint: None,
}),
"SELECT COUNT(*) AS cnt FROM `App Schema`.`order`"
);
}
+ #[test]
+ fn builds_grid_count_sql_with_optimizer_hint() {
+ // GaussDB with optimizer hint
+ assert_eq!(
+ build_data_grid_count_sql(DataGridCountSqlOptions {
+ database_type: Some(DatabaseType::Gaussdb),
+ identifier_quote: Some("\"".to_string()),
+ catalog: None,
+ database: None,
+ schema: Some("schema_01".to_string()),
+ table_name: "table_01".to_string(),
+ where_input: None,
+ count_hint: Some("/*+ set(query_dop 32) */".to_string()),
+ }),
+ "SELECT /*+ set(query_dop 32) */ COUNT(*) AS cnt FROM schema_01.table_01"
+ );
+ // GaussDB with hint and WHERE clause
+ assert_eq!(
+ build_data_grid_count_sql(DataGridCountSqlOptions {
+ database_type: Some(DatabaseType::Gaussdb),
+ identifier_quote: None,
+ catalog: None,
+ database: None,
+ schema: Some("sec_acct".to_string()),
+ table_name: "main_sec_acct_info".to_string(),
+ where_input: Some("status = 'active'".to_string()),
+ count_hint: Some("/*+ set(query_dop 32) */".to_string()),
+ }),
+ "SELECT /*+ set(query_dop 32) */ COUNT(*) AS cnt FROM \"sec_acct\".\"main_sec_acct_info\" WHERE (status = 'active')"
+ );
+ // Non-GaussDB database with hint (should still work)
+ assert_eq!(
+ build_data_grid_count_sql(DataGridCountSqlOptions {
+ database_type: Some(DatabaseType::Postgres),
+ identifier_quote: None,
+ catalog: None,
+ database: None,
+ schema: Some("public".to_string()),
+ table_name: "users".to_string(),
+ where_input: None,
+ count_hint: Some("/*+ set(query_dop 32) */".to_string()),
+ }),
+ "SELECT /*+ set(query_dop 32) */ COUNT(*) AS cnt FROM \"public\".\"users\""
+ );
+ // No hint (default) — unchanged behavior
+ assert_eq!(
+ build_data_grid_count_sql(DataGridCountSqlOptions {
+ database_type: Some(DatabaseType::Gaussdb),
+ identifier_quote: None,
+ catalog: None,
+ database: None,
+ schema: Some("schema_01".to_string()),
+ table_name: "table_01".to_string(),
+ where_input: None,
+ count_hint: None,
+ }),
+ "SELECT COUNT(*) AS cnt FROM \"schema_01\".\"table_01\""
+ );
+ }
+
#[test]
fn builds_hive_table_properties_sql() {
assert_eq!(