diff --git a/packages/cubejs-mysql-driver/src/MySqlDriver.ts b/packages/cubejs-mysql-driver/src/MySqlDriver.ts index ee8f7722bfdaf..6b40761bda964 100644 --- a/packages/cubejs-mysql-driver/src/MySqlDriver.ts +++ b/packages/cubejs-mysql-driver/src/MySqlDriver.ts @@ -22,6 +22,7 @@ import { IndexesSQL, DownloadTableMemoryData, DriverCapabilities, + TableColumn, } from '@cubejs-backend/base-driver'; const GenericTypeToMySql: Record = { @@ -180,7 +181,7 @@ export class MySqlDriver extends BaseDriver implements DriverInterface { protected primaryKeysQuery(conditionString?: string): string | null { return `SELECT - TABLE_SCHEMA as ${this.quoteIdentifier('table_schema')}, + TABLE_SCHEMA as ${this.quoteIdentifier('table_schema')}, TABLE_NAME as ${this.quoteIdentifier('table_name')}, COLUMN_NAME as ${this.quoteIdentifier('column_name')} FROM @@ -262,6 +263,14 @@ export class MySqlDriver extends BaseDriver implements DriverInterface { } } + public async createTable(quotedTableName: string, columns: TableColumn[]): Promise { + if (quotedTableName.length > 64) { + throw new Error('MySQL can not work with table names longer than 64 symbols. ' + + `Consider using the 'sqlAlias' attribute in your cube definition for ${quotedTableName}.`); + } + return super.createTable(quotedTableName, columns); + } + public async query(query: string, values: unknown[]) { return this.withConnection(async (conn) => { await this.setTimeZone(conn); diff --git a/packages/cubejs-mysql-driver/test/MySqlDriver.test.ts b/packages/cubejs-mysql-driver/test/MySqlDriver.test.ts index fdd04bf39c3f1..fc2154dfee1cb 100644 --- a/packages/cubejs-mysql-driver/test/MySqlDriver.test.ts +++ b/packages/cubejs-mysql-driver/test/MySqlDriver.test.ts @@ -116,4 +116,18 @@ describe('MySqlDriver', () => { await tableData.release(); } }); + + test('table name check', async () => { + const tblName = 'really-really-really-looooooooooooooooooooooooooooooooooooooooooooooooooooong-table-name'; + try { + await mySqlDriver.createTable(tblName, [{ name: 'id', type: 'bigint' }]); + + throw new Error('createTable must throw an exception'); + } catch (e: any) { + expect(e.message).toEqual( + 'MySQL can not work with table names longer than 64 symbols. ' + + `Consider using the 'sqlAlias' attribute in your cube definition for ${tblName}.` + ); + } + }); }); diff --git a/packages/cubejs-oracle-driver/driver/OracleDriver.js b/packages/cubejs-oracle-driver/driver/OracleDriver.js index 48e78992b8d45..bd3c36a34d2e0 100644 --- a/packages/cubejs-oracle-driver/driver/OracleDriver.js +++ b/packages/cubejs-oracle-driver/driver/OracleDriver.js @@ -8,7 +8,7 @@ const { getEnv, assertDataSource, } = require('@cubejs-backend/shared'); -const { BaseDriver } = require('@cubejs-backend/base-driver'); +const { BaseDriver, TableColumn } = require('@cubejs-backend/base-driver'); const oracledb = require('oracledb'); const { reduce } = require('ramda'); @@ -95,13 +95,13 @@ class OracleDriver extends BaseDriver { , tc.data_type "data_type" , c.constraint_type "key_type" from all_tab_columns tc - left join all_cons_columns cc - on (tc.owner, tc.table_name, tc.column_name) + left join all_cons_columns cc + on (tc.owner, tc.table_name, tc.column_name) in ((cc.owner, cc.table_name, cc.column_name)) - left join all_constraints c - on (tc.owner, tc.table_name, cc.constraint_name) - in ((c.owner, c.table_name, c.constraint_name)) - and c.constraint_type + left join all_constraints c + on (tc.owner, tc.table_name, cc.constraint_name) + in ((c.owner, c.table_name, c.constraint_name)) + and c.constraint_type in ('P','U') where tc.owner = user `); @@ -121,6 +121,14 @@ class OracleDriver extends BaseDriver { await this.query('SELECT 1 FROM DUAL', {}); } + async createTable(quotedTableName, columns) { + if (quotedTableName.length > 128) { + throw new Error('Oracle can not work with table names longer than 128 symbols. ' + + `Consider using the 'sqlAlias' attribute in your cube definition for ${quotedTableName}.`); + } + return super.createTable(quotedTableName, columns); + } + async query(query, values) { const conn = await this.getConnectionFromPool(); diff --git a/packages/cubejs-postgres-driver/src/PostgresDriver.ts b/packages/cubejs-postgres-driver/src/PostgresDriver.ts index c3b5e1c4ad93c..e9a5a0dacb162 100644 --- a/packages/cubejs-postgres-driver/src/PostgresDriver.ts +++ b/packages/cubejs-postgres-driver/src/PostgresDriver.ts @@ -16,7 +16,7 @@ import { BaseDriver, DownloadQueryResultsOptions, DownloadTableMemoryData, DriverInterface, GenericDataBaseType, IndexesSQL, TableStructure, StreamOptions, - StreamTableDataWithTypes, QueryOptions, DownloadQueryResultsResult, DriverCapabilities, + StreamTableDataWithTypes, QueryOptions, DownloadQueryResultsResult, DriverCapabilities, TableColumn, } from '@cubejs-backend/base-driver'; import { QueryStream } from './QueryStream'; @@ -118,7 +118,7 @@ export class PostgresDriver { + if (quotedTableName.length > 63) { + throw new Error('PostgreSQL can not work with table names longer than 63 symbols. ' + + `Consider using the 'sqlAlias' attribute in your cube definition for ${quotedTableName}.`); + } + return super.createTable(quotedTableName, columns); + } + // eslint-disable-next-line @typescript-eslint/no-unused-vars public async query(query: string, values: unknown[], options?: QueryOptions): Promise { const result = await this.queryResponse(query, values); diff --git a/packages/cubejs-postgres-driver/test/PostgresDriver.test.ts b/packages/cubejs-postgres-driver/test/PostgresDriver.test.ts index d7034c80d6e94..6e5d4510109d6 100644 --- a/packages/cubejs-postgres-driver/test/PostgresDriver.test.ts +++ b/packages/cubejs-postgres-driver/test/PostgresDriver.test.ts @@ -142,6 +142,20 @@ describe('PostgresDriver', () => { } }); + test('table name check', async () => { + const tblName = 'really-really-really-looooooooooooooooooooooooooooooooooooooooooooooooooooong-table-name'; + try { + await driver.createTable(tblName, [{ name: 'id', type: 'bigint' }]); + + throw new Error('createTable must throw an exception'); + } catch (e: any) { + expect(e.message).toEqual( + 'PostgreSQL can not work with table names longer than 63 symbols. ' + + `Consider using the 'sqlAlias' attribute in your cube definition for ${tblName}.` + ); + } + }); + // Note: This test MUST be the last in the list. test('release', async () => { expect(async () => { diff --git a/packages/cubejs-redshift-driver/src/RedshiftDriver.ts b/packages/cubejs-redshift-driver/src/RedshiftDriver.ts index 8f031d61d3e16..ecc39bd31e167 100644 --- a/packages/cubejs-redshift-driver/src/RedshiftDriver.ts +++ b/packages/cubejs-redshift-driver/src/RedshiftDriver.ts @@ -15,6 +15,7 @@ import { QueryTablesResult, StreamOptions, StreamTableDataWithTypes, + TableColumn, UnloadOptions } from '@cubejs-backend/base-driver'; import crypto from 'crypto'; @@ -240,6 +241,21 @@ export class RedshiftDriver extends PostgresDriver } } + public override async createTable(quotedTableName: string, columns: TableColumn[]): Promise { + if (quotedTableName.length > 127) { + throw new Error('Redshift can not work with table names longer than 127 symbols. ' + + `Consider using the 'sqlAlias' attribute in your cube definition for ${quotedTableName}.`); + } + + // we can not call super.createTable(quotedTableName, columns) + // because Postgres has 63 length check. So pasting the code from the base driver + const createTableSql = this.createTableSql(quotedTableName, columns); + await this.query(createTableSql, []).catch(e => { + e.message = `Error during create table: ${createTableSql}: ${e.message}`; + throw e; + }); + } + /** * AWS Redshift doesn't have any special connection check. * And querying even system tables is billed.