Skip to content

Commit 7954103

Browse files
committed
[WIP] feat(clickhouse): Use ClickHouse query with parameters via HTTP interface
1 parent 4c41fa7 commit 7954103

File tree

3 files changed

+41
-10
lines changed

3 files changed

+41
-10
lines changed

packages/cubejs-clickhouse-driver/src/ClickHouseDriver.ts

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,15 @@ export class ClickHouseDriver extends BaseDriver implements DriverInterface {
230230
});
231231
}
232232

233+
protected prepareParams(values: unknown[]): Record<string, string> {
234+
return Object.fromEntries(values.map((value, idx) => {
235+
const paramName = this.paramName(idx);
236+
const paramKey = `param_${paramName}`;
237+
const preparedValue = formatQueryParams(value);
238+
return [paramKey, preparedValue];
239+
}));
240+
}
241+
233242
protected queryResponse(query: string, values?: unknown[]) {
234243
// todo drop this
235244
console.log('queryResponse call', query, values);
@@ -251,12 +260,7 @@ export class ClickHouseDriver extends BaseDriver implements DriverInterface {
251260
// https://clickhouse.com/docs/en/interfaces/cli#cli-queries-with-parameters
252261
// https://clickhouse.com/docs/en/interfaces/http#cli-queries-with-parameters
253262

254-
const paramsValues = Object.fromEntries((values ?? []).map((value, idx) => {
255-
const paramName = this.paramName(idx);
256-
const paramKey = `param_${paramName}`;
257-
const preparedValue = formatQueryParams(value);
258-
return [paramKey, preparedValue];
259-
}));
263+
const paramsValues = this.prepareParams(values ?? []);
260264

261265
// todo drop this
262266
console.log('queryResponse prepared', formattedQuery, paramsValues);
@@ -359,11 +363,19 @@ export class ClickHouseDriver extends BaseDriver implements DriverInterface {
359363
// eslint-disable-next-line @typescript-eslint/no-unused-vars
360364
{ highWaterMark }: StreamOptions
361365
): Promise<StreamTableDataWithTypes> {
366+
// todo drop this
367+
console.log('stream call', query, values);
368+
362369
// eslint-disable-next-line no-underscore-dangle
363370
const conn = await (<any> this.pool)._factory.create();
364371

365372
try {
366-
const formattedQuery = sqlstring.format(query, values);
373+
// const formattedQuery = sqlstring.format(query, values);
374+
const formattedQuery = query;
375+
const paramsValues = this.prepareParams(values ?? []);
376+
377+
// todo drop this
378+
console.log('stream prepared', formattedQuery, paramsValues);
367379

368380
return await new Promise((resolve, reject) => {
369381
const options = {
@@ -377,12 +389,15 @@ export class ClickHouseDriver extends BaseDriver implements DriverInterface {
377389
//
378390
//
379391
...(this.readOnlyMode ? {} : { join_use_nulls: 1 }),
392+
393+
// Add parameter values to query string
394+
...paramsValues,
380395
}
381396
};
382397

383398
const originalStream = conn.query(formattedQuery, options, (err: Error | null, result: any) => {
384399
if (err) {
385-
reject(err);
400+
reject(new Error(`Failed during stream createion; query: ${query}; values: ${values}`, { cause: err }));
386401
} else {
387402
const rowStream = new HydrationStream(result.meta);
388403
originalStream.pipe(rowStream);

packages/cubejs-schema-compiler/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
"uuid": "^8.3.2"
5858
},
5959
"devDependencies": {
60+
"@clickhouse/client-common": "^1.8.0",
6061
"@cubejs-backend/apla-clickhouse": "^1.7.0",
6162
"@cubejs-backend/linter": "^1.0.0",
6263
"@cubejs-backend/query-orchestrator": "1.1.3",

packages/cubejs-schema-compiler/test/integration/clickhouse/ClickHouseDbRunner.js

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { formatQueryParams } from '@clickhouse/client-common';
12
/* eslint-disable */
23
import ClickHouse from '@cubejs-backend/apla-clickhouse';
34
import { GenericContainer } from 'testcontainers';
@@ -136,13 +137,27 @@ export class ClickHouseDbRunner extends BaseDbRunner {
136137
} : {};
137138

138139
for (const [query, params] of queries) {
139-
requests.push(clickHouse.querying(formatSql(query, params), {
140+
// TODO get rid of sqlstring
141+
// TODO migrate to upstream clickhouse client
142+
const preparedQ = query;
143+
const preparedV = Object.fromEntries(params.map((value, idx) => {
144+
const paramName = `p${idx}`;
145+
const paramKey = `param_${paramName}`;
146+
const preparedValue = formatQueryParams(value);
147+
return [paramKey, preparedValue];
148+
}));
149+
console.log("ClickHOuse testQueries prepared", preparedQ, preparedV);
150+
requests.push(clickHouse.querying(preparedQ, {
140151
dataObjects: true,
141152
queryOptions: {
142153
session_id: clickHouse.sessionId,
143154
join_use_nulls: '1',
144-
...extendedDateTimeResultsOptions
155+
...extendedDateTimeResultsOptions,
156+
// Add parameter values to query string
157+
...preparedV,
145158
}
159+
}).catch((err) => {
160+
throw new Error(`Failed during query; query: ${query}; params: ${params}`, { cause: err });
146161
}));
147162
}
148163

0 commit comments

Comments
 (0)