Skip to content

Commit 5fb81cc

Browse files
authored
fix(schema-compiler): Move create table name check to underlying driver for Postgres, MySQL, Oracle (#9112)
* fix(schema-compiler): move create table name check to underlying driver for Postgres, MySQL, Oracle * override createTable in redshift * add tests for postgres & mysql drivers
1 parent 6d6df53 commit 5fb81cc

File tree

6 files changed

+81
-12
lines changed

6 files changed

+81
-12
lines changed

packages/cubejs-mysql-driver/src/MySqlDriver.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {
2222
IndexesSQL,
2323
DownloadTableMemoryData,
2424
DriverCapabilities,
25+
TableColumn,
2526
} from '@cubejs-backend/base-driver';
2627

2728
const GenericTypeToMySql: Record<GenericDataBaseType, string> = {
@@ -180,7 +181,7 @@ export class MySqlDriver extends BaseDriver implements DriverInterface {
180181

181182
protected primaryKeysQuery(conditionString?: string): string | null {
182183
return `SELECT
183-
TABLE_SCHEMA as ${this.quoteIdentifier('table_schema')},
184+
TABLE_SCHEMA as ${this.quoteIdentifier('table_schema')},
184185
TABLE_NAME as ${this.quoteIdentifier('table_name')},
185186
COLUMN_NAME as ${this.quoteIdentifier('column_name')}
186187
FROM
@@ -262,6 +263,14 @@ export class MySqlDriver extends BaseDriver implements DriverInterface {
262263
}
263264
}
264265

266+
public async createTable(quotedTableName: string, columns: TableColumn[]): Promise<void> {
267+
if (quotedTableName.length > 64) {
268+
throw new Error('MySQL can not work with table names longer than 64 symbols. ' +
269+
`Consider using the 'sqlAlias' attribute in your cube definition for ${quotedTableName}.`);
270+
}
271+
return super.createTable(quotedTableName, columns);
272+
}
273+
265274
public async query(query: string, values: unknown[]) {
266275
return this.withConnection(async (conn) => {
267276
await this.setTimeZone(conn);

packages/cubejs-mysql-driver/test/MySqlDriver.test.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,4 +116,18 @@ describe('MySqlDriver', () => {
116116
await tableData.release();
117117
}
118118
});
119+
120+
test('table name check', async () => {
121+
const tblName = 'really-really-really-looooooooooooooooooooooooooooooooooooooooooooooooooooong-table-name';
122+
try {
123+
await mySqlDriver.createTable(tblName, [{ name: 'id', type: 'bigint' }]);
124+
125+
throw new Error('createTable must throw an exception');
126+
} catch (e: any) {
127+
expect(e.message).toEqual(
128+
'MySQL can not work with table names longer than 64 symbols. ' +
129+
`Consider using the 'sqlAlias' attribute in your cube definition for ${tblName}.`
130+
);
131+
}
132+
});
119133
});

packages/cubejs-oracle-driver/driver/OracleDriver.js

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ const {
88
getEnv,
99
assertDataSource,
1010
} = require('@cubejs-backend/shared');
11-
const { BaseDriver } = require('@cubejs-backend/base-driver');
11+
const { BaseDriver, TableColumn } = require('@cubejs-backend/base-driver');
1212
const oracledb = require('oracledb');
1313
const { reduce } = require('ramda');
1414

@@ -95,13 +95,13 @@ class OracleDriver extends BaseDriver {
9595
, tc.data_type "data_type"
9696
, c.constraint_type "key_type"
9797
from all_tab_columns tc
98-
left join all_cons_columns cc
99-
on (tc.owner, tc.table_name, tc.column_name)
98+
left join all_cons_columns cc
99+
on (tc.owner, tc.table_name, tc.column_name)
100100
in ((cc.owner, cc.table_name, cc.column_name))
101-
left join all_constraints c
102-
on (tc.owner, tc.table_name, cc.constraint_name)
103-
in ((c.owner, c.table_name, c.constraint_name))
104-
and c.constraint_type
101+
left join all_constraints c
102+
on (tc.owner, tc.table_name, cc.constraint_name)
103+
in ((c.owner, c.table_name, c.constraint_name))
104+
and c.constraint_type
105105
in ('P','U')
106106
where tc.owner = user
107107
`);
@@ -121,6 +121,14 @@ class OracleDriver extends BaseDriver {
121121
await this.query('SELECT 1 FROM DUAL', {});
122122
}
123123

124+
async createTable(quotedTableName, columns) {
125+
if (quotedTableName.length > 128) {
126+
throw new Error('Oracle can not work with table names longer than 128 symbols. ' +
127+
`Consider using the 'sqlAlias' attribute in your cube definition for ${quotedTableName}.`);
128+
}
129+
return super.createTable(quotedTableName, columns);
130+
}
131+
124132
async query(query, values) {
125133
const conn = await this.getConnectionFromPool();
126134

packages/cubejs-postgres-driver/src/PostgresDriver.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import {
1616
BaseDriver,
1717
DownloadQueryResultsOptions, DownloadTableMemoryData, DriverInterface,
1818
GenericDataBaseType, IndexesSQL, TableStructure, StreamOptions,
19-
StreamTableDataWithTypes, QueryOptions, DownloadQueryResultsResult, DriverCapabilities,
19+
StreamTableDataWithTypes, QueryOptions, DownloadQueryResultsResult, DriverCapabilities, TableColumn,
2020
} from '@cubejs-backend/base-driver';
2121
import { QueryStream } from './QueryStream';
2222

@@ -118,7 +118,7 @@ export class PostgresDriver<Config extends PostgresDriverConfiguration = Postgre
118118
const dataSource =
119119
config.dataSource ||
120120
assertDataSource('default');
121-
121+
122122
this.pool = new Pool({
123123
idleTimeoutMillis: 30000,
124124
max:
@@ -146,9 +146,9 @@ export class PostgresDriver<Config extends PostgresDriverConfiguration = Postgre
146146
}
147147

148148
protected primaryKeysQuery(conditionString?: string): string | null {
149-
return `SELECT
149+
return `SELECT
150150
columns.table_schema as ${this.quoteIdentifier('table_schema')},
151-
columns.table_name as ${this.quoteIdentifier('table_name')},
151+
columns.table_name as ${this.quoteIdentifier('table_name')},
152152
columns.column_name as ${this.quoteIdentifier('column_name')}
153153
FROM information_schema.table_constraints tc
154154
JOIN information_schema.constraint_column_usage AS ccu USING (constraint_schema, constraint_name)
@@ -360,6 +360,14 @@ export class PostgresDriver<Config extends PostgresDriverConfiguration = Postgre
360360
}
361361
}
362362

363+
public async createTable(quotedTableName: string, columns: TableColumn[]): Promise<void> {
364+
if (quotedTableName.length > 63) {
365+
throw new Error('PostgreSQL can not work with table names longer than 63 symbols. ' +
366+
`Consider using the 'sqlAlias' attribute in your cube definition for ${quotedTableName}.`);
367+
}
368+
return super.createTable(quotedTableName, columns);
369+
}
370+
363371
// eslint-disable-next-line @typescript-eslint/no-unused-vars
364372
public async query<R = unknown>(query: string, values: unknown[], options?: QueryOptions): Promise<R[]> {
365373
const result = await this.queryResponse(query, values);

packages/cubejs-postgres-driver/test/PostgresDriver.test.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,20 @@ describe('PostgresDriver', () => {
142142
}
143143
});
144144

145+
test('table name check', async () => {
146+
const tblName = 'really-really-really-looooooooooooooooooooooooooooooooooooooooooooooooooooong-table-name';
147+
try {
148+
await driver.createTable(tblName, [{ name: 'id', type: 'bigint' }]);
149+
150+
throw new Error('createTable must throw an exception');
151+
} catch (e: any) {
152+
expect(e.message).toEqual(
153+
'PostgreSQL can not work with table names longer than 63 symbols. ' +
154+
`Consider using the 'sqlAlias' attribute in your cube definition for ${tblName}.`
155+
);
156+
}
157+
});
158+
145159
// Note: This test MUST be the last in the list.
146160
test('release', async () => {
147161
expect(async () => {

packages/cubejs-redshift-driver/src/RedshiftDriver.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
QueryTablesResult,
1616
StreamOptions,
1717
StreamTableDataWithTypes,
18+
TableColumn,
1819
UnloadOptions
1920
} from '@cubejs-backend/base-driver';
2021
import crypto from 'crypto';
@@ -240,6 +241,21 @@ export class RedshiftDriver extends PostgresDriver<RedshiftDriverConfiguration>
240241
}
241242
}
242243

244+
public override async createTable(quotedTableName: string, columns: TableColumn[]): Promise<void> {
245+
if (quotedTableName.length > 127) {
246+
throw new Error('Redshift can not work with table names longer than 127 symbols. ' +
247+
`Consider using the 'sqlAlias' attribute in your cube definition for ${quotedTableName}.`);
248+
}
249+
250+
// we can not call super.createTable(quotedTableName, columns)
251+
// because Postgres has 63 length check. So pasting the code from the base driver
252+
const createTableSql = this.createTableSql(quotedTableName, columns);
253+
await this.query(createTableSql, []).catch(e => {
254+
e.message = `Error during create table: ${createTableSql}: ${e.message}`;
255+
throw e;
256+
});
257+
}
258+
243259
/**
244260
* AWS Redshift doesn't have any special connection check.
245261
* And querying even system tables is billed.

0 commit comments

Comments
 (0)