Skip to content

Commit

Permalink
fix(db2): use docker compose & set default schema as username (#16307)
Browse files Browse the repository at this point in the history
  • Loading branch information
lohart13 committed Jul 27, 2023
1 parent 0fd05d4 commit c59011c
Show file tree
Hide file tree
Showing 15 changed files with 118 additions and 144 deletions.
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ If you have Docker installed, use any of the following commands to start fresh l
- `yarn start-mysql-oldest` (for MySQL 5.7) or `yarn start-mysql-latest` (for MySQL 8.0)
- `yarn start-postgres-oldest` (for Postgres 11) or `yarn start-postgres-latest` (for Postgres 15)
- `yarn start-mssql-oldest` (for MSSQL 2017) or `yarn start-mssql-latest` (for MSSQL 2022)
- `yarn start-db2-oldest`
- `yarn start-db2-oldest` (for Db2 11.5.5.1) or `yarn start-db2-latest` (for Db2 11.5.8.0)

_Note:_ if you're using Windows, make sure you run these from Git Bash (or another MinGW environment), since these commands will execute bash scripts. Recall that [it's very easy to include Git Bash as your default integrated terminal on Visual Studio Code](https://code.visualstudio.com/docs/editor/integrated-terminal).

Expand Down
20 changes: 20 additions & 0 deletions dev/db2/latest/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
services:
db2-latest:
container_name: sequelize-db2-latest
image: icr.io/db2_community/db2:11.5.8.0
privileged: true
env_file: ../.env_list
environment:
DBNAME: testdb
ports:
- 50000:50000
healthcheck:
test: su - db2inst1 -c "db2 connect to testdb; db2 select 1 from sysibm.sysdummy1" || exit 1
start_period: 15s
interval: 10s
timeout: 5s
retries: 10

networks:
default:
name: sequelize-db2-latest-network
35 changes: 5 additions & 30 deletions dev/db2/latest/start.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,11 @@
set -Eeuxo pipefail # https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/
cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" # https://stackoverflow.com/a/17744637

export DIALECT=db2
SEQ_DB="${SEQ_DB:-testdb}"
# db2 db names must be uppercase
SEQ_DB=$(echo "$SEQ_DB" | awk '{print toupper($0)}')
docker compose -p sequelize-db2-latest down --remove-orphans
docker compose -p sequelize-db2-latest up -d

mkdir -p Docker
if [ ! "$(sudo docker ps -q -f name=db2server)" ]; then
if [ "$(sudo docker ps -aq -f status=exited -f name=db2server)" ];
then
# cleanup
sudo docker rm -f db2server
sudo rm -rf /Docker
fi
# TODO: use docker compose so renovate can automatically update this version
sudo docker run -h db2server --name db2server --restart=always --detach --privileged=true -p 50000:50000 --env "DBNAME=$SEQ_DB" --env-file ../.env_list -v /Docker:/database ibmcom/db2-amd64:11.5.8.0
count=1
while true
do
if (sudo docker logs db2server | grep 'Setup has completed')
then
sudo docker exec db2server bash -c "su db2inst1 & disown"
break
fi
if [ $count -gt 30 ]; then
echo "Error: Db2 docker setup has not completed in 10 minutes."
break
fi
sleep 20
let "count=count+1"
done
fi
sleep 150

./../../wait-until-healthy.sh sequelize-db2-latest

DIALECT=db2 ts-node ../../check-connection.ts
6 changes: 5 additions & 1 deletion dev/db2/latest/stop.sh
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
sudo docker stop db2server
#!/usr/bin/env bash
set -Eeuxo pipefail # https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/
cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" # https://stackoverflow.com/a/17744637

docker compose -p sequelize-db2-latest down --remove-orphans

echo "Local latest supported Db2 instance stopped (if it was running)."
20 changes: 20 additions & 0 deletions dev/db2/oldest/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
services:
db2-oldest:
container_name: sequelize-db2-oldest
image: icr.io/db2_community/db2:11.5.5.1
privileged: true
env_file: ../.env_list
environment:
DBNAME: testdb
ports:
- 50000:50000
healthcheck:
test: su - db2inst1 -c "db2 connect to testdb; db2 select 1 from sysibm.sysdummy1" || exit 1
start_period: 15s
interval: 10s
timeout: 5s
retries: 10

networks:
default:
name: sequelize-db2-oldest-network
34 changes: 5 additions & 29 deletions dev/db2/oldest/start.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,11 @@
set -Eeuxo pipefail # https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/
cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" # https://stackoverflow.com/a/17744637

export DIALECT=db2
SEQ_DB="${SEQ_DB:-testdb}"
# db2 db names must be uppercase
SEQ_DB=$(echo "$SEQ_DB" | awk '{print toupper($0)}')
docker compose -p sequelize-db2-oldest down --remove-orphans
docker compose -p sequelize-db2-oldest up -d

mkdir -p Docker
if [ ! "$(sudo docker ps -q -f name=db2server)" ]; then
if [ "$(sudo docker ps -aq -f status=exited -f name=db2server)" ];
then
# cleanup
sudo docker rm -f db2server
sudo rm -rf /Docker
fi
sudo docker run -h db2server --name db2server --restart=always --detach --privileged=true -p 50000:50000 --env "DBNAME=$SEQ_DB" --env-file ../.env_list -v /Docker:/database ibmcom/db2-amd64:11.5.6.0a
count=1
while true
do
if (sudo docker logs db2server | grep 'Setup has completed')
then
sudo docker exec db2server bash -c "su db2inst1 & disown"
break
fi
if [ $count -gt 30 ]; then
echo "Error: Db2 docker setup has not completed in 10 minutes."
break
fi
sleep 20
let "count=count+1"
done
fi
sleep 150

./../../wait-until-healthy.sh sequelize-db2-oldest

DIALECT=db2 ts-node ../../check-connection.ts
6 changes: 5 additions & 1 deletion dev/db2/oldest/stop.sh
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
sudo docker stop db2server
#!/usr/bin/env bash
set -Eeuxo pipefail # https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/
cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" # https://stackoverflow.com/a/17744637

docker compose -p sequelize-db2-oldest down --remove-orphans

echo "Local oldest supported Db2 instance stopped (if it was running)."
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@
"start-mssql-latest": "bash dev/mssql/latest/start.sh",
"start-db2-oldest": "bash dev/db2/oldest/start.sh",
"start-db2-latest": "bash dev/db2/latest/start.sh",
"start-oldest": "concurrently \"npm:start-*(!db2)-oldest\" && npm run start-db2-oldest",
"start-latest": "concurrently \"npm:start-*(!db2)-latest\" && npm run start-db2-latest",
"start-oldest": "concurrently \"npm:start-*-oldest\"",
"start-latest": "concurrently \"npm:start-*-latest\"",
"stop-mariadb": "bash dev/mariadb/oldest/stop.sh; bash dev/mariadb/latest/stop.sh",
"stop-mysql": "bash dev/mysql/oldest/stop.sh; bash dev/mysql/latest/stop.sh",
"stop-postgres": "bash dev/postgres/oldest/stop.sh; bash dev/postgres/latest/stop.sh",
"stop-mssql": "bash dev/mssql/oldest/stop.sh; bash dev/mssql/latest/stop.sh",
"stop-db2": "bash dev/db2/oldest/stop.sh; bash dev/db2/latest/stop.sh",
"stop-all": "concurrently \"npm:stop-*(!all|db2)\" && npm run stop-db2",
"stop-all": "concurrently \"npm:stop-*(!all)\"",
"----------------------------------------- SSCCEs ------------------------------------------": "",
"sscce": "ts-node sscce.ts",
"sscce-mariadb": "cross-env DIALECT=mariadb yarn sscce",
Expand Down
3 changes: 1 addition & 2 deletions packages/core/src/dialects/db2/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,7 @@ export class Db2Dialect extends AbstractDialect {
}

getDefaultSchema(): string {
// TODO: what is the default schema in DB2?
return '';
return this.sequelize.config.username.toUpperCase();
}

static getDefaultPort() {
Expand Down
34 changes: 18 additions & 16 deletions packages/core/src/dialects/db2/query-generator-typescript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,21 @@ export class Db2QueryGeneratorTypeScript extends AbstractQueryGenerator {
const table = this.extractTableDetails(tableName);

return joinSQLFragments([
'SELECT NAME AS "Name", TBNAME AS "Table", TBCREATOR AS "Schema",',
'TRIM(COLTYPE) AS "Type", LENGTH AS "Length", SCALE AS "Scale",',
'NULLS AS "IsNull", DEFAULT AS "Default", COLNO AS "Colno",',
'IDENTITY AS "IsIdentity", KEYSEQ AS "KeySeq", REMARKS AS "Comment"',
'FROM',
'SYSIBM.SYSCOLUMNS',
`WHERE TBNAME = ${this.escape(table.tableName)}`,
'AND TBCREATOR =',
table.schema ? this.escape(table.schema) : 'USER',
';',
'SELECT COLNAME AS "Name",',
'TABNAME AS "Table",',
'TABSCHEMA AS "Schema",',
'TYPENAME AS "Type",',
'LENGTH AS "Length",',
'SCALE AS "Scale",',
'NULLS AS "IsNull",',
'DEFAULT AS "Default",',
'COLNO AS "Colno",',
'IDENTITY AS "IsIdentity",',
'KEYSEQ AS "KeySeq",',
'REMARKS AS "Comment"',
'FROM SYSCAT.COLUMNS',
`WHERE TABNAME = ${this.escape(table.tableName)}`,
`AND TABSCHEMA = ${this.escape(table.schema)}`,
]);
}

Expand All @@ -51,8 +56,7 @@ export class Db2QueryGeneratorTypeScript extends AbstractQueryGenerator {
'LEFT JOIN SYSCAT.KEYCOLUSE fk ON r.REFKEYNAME = fk.CONSTNAME',
'LEFT JOIN SYSCAT.CHECKS ck ON c.CONSTNAME = ck.CONSTNAME AND c.TABNAME = ck.TABNAME AND c.TABSCHEMA = ck.TABSCHEMA',
`WHERE c.TABNAME = ${this.escape(table.tableName)}`,
'AND c.TABSCHEMA =',
table.schema ? this.escape(table.schema) : 'USER',
`AND c.TABSCHEMA = ${this.escape(table.schema)}`,
options?.constraintName ? `AND c.CONSTNAME = ${this.escape(options.constraintName)}` : '',
'ORDER BY c.CONSTNAME',
]);
Expand All @@ -72,8 +76,7 @@ export class Db2QueryGeneratorTypeScript extends AbstractQueryGenerator {
'FROM SYSCAT.INDEXES i',
'INNER JOIN SYSCAT.INDEXCOLUSE c ON i.INDNAME = c.INDNAME AND i.INDSCHEMA = c.INDSCHEMA',
`WHERE TABNAME = ${this.escape(table.tableName)}`,
'AND TABSCHEMA =',
table.schema ? this.escape(table.schema) : 'USER',
`AND TABSCHEMA = ${this.escape(table.schema)}`,
'ORDER BY i.INDNAME, c.COLSEQ;',
]);
}
Expand Down Expand Up @@ -120,8 +123,7 @@ export class Db2QueryGeneratorTypeScript extends AbstractQueryGenerator {
'WHERE R.CONSTNAME = C.CONSTNAME AND R.TABSCHEMA = C.TABSCHEMA',
'AND R.TABNAME = C.TABNAME',
`AND R.TABNAME = ${this.escape(table.tableName)}`,
'AND R.TABSCHEMA =',
table.schema ? this.escape(table.schema) : 'CURRENT SCHEMA',
`AND R.TABSCHEMA = ${this.escape(table.schema)}`,
columnName && `AND C.COLNAME = ${this.escape(columnName)}`,
'GROUP BY R.REFTABSCHEMA,',
'R.REFTABNAME, R.TABSCHEMA, R.TABNAME, R.CONSTNAME, R.PK_COLNAMES',
Expand Down
24 changes: 4 additions & 20 deletions packages/core/src/dialects/db2/query-generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -204,17 +204,13 @@ export class Db2QueryGenerator extends Db2QueryGeneratorTypeScript {
}

showTablesQuery() {
return 'SELECT TABNAME AS "tableName", TRIM(TABSCHEMA) AS "tableSchema" FROM SYSCAT.TABLES WHERE TABSCHEMA = USER AND TYPE = \'T\' ORDER BY TABSCHEMA, TABNAME';
return `SELECT TABNAME AS "tableName", TRIM(TABSCHEMA) AS "tableSchema" FROM SYSCAT.TABLES WHERE TABSCHEMA = ${this.escape(this.dialect.getDefaultSchema())} AND TYPE = 'T' ORDER BY TABSCHEMA, TABNAME`;
}

tableExistsQuery(table) {
const tableName = table.tableName || table;
// The default schema is the authorization ID of the owner of the plan or package.
// https://www.ibm.com/docs/en/db2-for-zos/12?topic=concepts-db2-schemas-schema-qualifiers
const schemaName = table.schema || this.sequelize.config.username.toUpperCase();
tableExistsQuery(tableName) {
const table = this.extractTableDetails(tableName);

// https://www.ibm.com/docs/en/db2-for-zos/11?topic=tables-systables
return `SELECT name FROM sysibm.systables WHERE NAME = ${this.escape(tableName)} AND CREATOR = ${this.escape(schemaName)}`;
return `SELECT TABNAME as "name" FROM SYSCAT.TABLES WHERE TABNAME = ${this.escape(table.tableName)} AND TABSCHEMA = ${this.escape(table.schema)}`;
}

addColumnQuery(table, key, dataType, options) {
Expand Down Expand Up @@ -811,15 +807,3 @@ export class Db2QueryGenerator extends Db2QueryGeneratorTypeScript {
return uniqno;
}
}

/**
* @param {string} identifier
* @deprecated use "escape" or "escapeString" on QueryGenerator
*/
function wrapSingleQuote(identifier) {
if (identifier) {
return `'${identifier}'`;
}

return '';
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,10 @@ describe('QueryGenerator#describeTableQuery', () => {
AND prop.name = 'MS_Description'
WHERE t.TABLE_NAME = N'myTable' AND t.TABLE_SCHEMA = N'dbo'`,
sqlite: 'PRAGMA TABLE_INFO(`myTable`)',
db2: `SELECT NAME AS "Name", TBNAME AS "Table", TBCREATOR AS "Schema",
TRIM(COLTYPE) AS "Type", LENGTH AS "Length", SCALE AS "Scale",
NULLS AS "IsNull", DEFAULT AS "Default", COLNO AS "Colno",
IDENTITY AS "IsIdentity", KEYSEQ AS "KeySeq", REMARKS AS "Comment"
FROM SYSIBM.SYSCOLUMNS
WHERE TBNAME = 'myTable' AND TBCREATOR = USER;`,
db2: `SELECT COLNAME AS "Name", TABNAME AS "Table", TABSCHEMA AS "Schema",
TYPENAME AS "Type", LENGTH AS "Length", SCALE AS "Scale", NULLS AS "IsNull",
DEFAULT AS "Default", COLNO AS "Colno", IDENTITY AS "IsIdentity", KEYSEQ AS "KeySeq",
REMARKS AS "Comment" FROM SYSCAT.COLUMNS WHERE TABNAME = 'myTable' AND TABSCHEMA = 'DB2INST1'`,
ibmi: `SELECT
QSYS2.SYSCOLUMNS.*,
QSYS2.SYSCST.CONSTRAINT_NAME,
Expand Down Expand Up @@ -135,12 +133,10 @@ describe('QueryGenerator#describeTableQuery', () => {
AND prop.name = 'MS_Description'
WHERE t.TABLE_NAME = N'MyModels' AND t.TABLE_SCHEMA = N'dbo'`,
sqlite: 'PRAGMA TABLE_INFO(`MyModels`)',
db2: `SELECT NAME AS "Name", TBNAME AS "Table", TBCREATOR AS "Schema",
TRIM(COLTYPE) AS "Type", LENGTH AS "Length", SCALE AS "Scale",
NULLS AS "IsNull", DEFAULT AS "Default", COLNO AS "Colno",
IDENTITY AS "IsIdentity", KEYSEQ AS "KeySeq", REMARKS AS "Comment"
FROM SYSIBM.SYSCOLUMNS
WHERE TBNAME = 'MyModels' AND TBCREATOR = USER;`,
db2: `SELECT COLNAME AS "Name", TABNAME AS "Table", TABSCHEMA AS "Schema",
TYPENAME AS "Type", LENGTH AS "Length", SCALE AS "Scale", NULLS AS "IsNull",
DEFAULT AS "Default", COLNO AS "Colno", IDENTITY AS "IsIdentity", KEYSEQ AS "KeySeq",
REMARKS AS "Comment" FROM SYSCAT.COLUMNS WHERE TABNAME = 'MyModels' AND TABSCHEMA = 'DB2INST1'`,
ibmi: `SELECT
QSYS2.SYSCOLUMNS.*,
QSYS2.SYSCST.CONSTRAINT_NAME,
Expand Down Expand Up @@ -208,12 +204,10 @@ describe('QueryGenerator#describeTableQuery', () => {
AND prop.name = 'MS_Description'
WHERE t.TABLE_NAME = N'myTable' AND t.TABLE_SCHEMA = N'mySchema'`,
sqlite: 'PRAGMA TABLE_INFO(`mySchema.myTable`)',
db2: `SELECT NAME AS "Name", TBNAME AS "Table", TBCREATOR AS "Schema",
TRIM(COLTYPE) AS "Type", LENGTH AS "Length", SCALE AS "Scale",
NULLS AS "IsNull", DEFAULT AS "Default", COLNO AS "Colno",
IDENTITY AS "IsIdentity", KEYSEQ AS "KeySeq", REMARKS AS "Comment"
FROM SYSIBM.SYSCOLUMNS
WHERE TBNAME = 'myTable' AND TBCREATOR = 'mySchema';`,
db2: `SELECT COLNAME AS "Name", TABNAME AS "Table", TABSCHEMA AS "Schema",
TYPENAME AS "Type", LENGTH AS "Length", SCALE AS "Scale", NULLS AS "IsNull",
DEFAULT AS "Default", COLNO AS "Colno", IDENTITY AS "IsIdentity", KEYSEQ AS "KeySeq",
REMARKS AS "Comment" FROM SYSCAT.COLUMNS WHERE TABNAME = 'myTable' AND TABSCHEMA = 'mySchema'`,
ibmi: `SELECT
QSYS2.SYSCOLUMNS.*,
QSYS2.SYSCST.CONSTRAINT_NAME,
Expand Down Expand Up @@ -282,12 +276,10 @@ describe('QueryGenerator#describeTableQuery', () => {
AND prop.name = 'MS_Description'
WHERE t.TABLE_NAME = N'myTable' AND t.TABLE_SCHEMA = N'dbo'`,
sqlite: 'PRAGMA TABLE_INFO(`myTable`)',
db2: `SELECT NAME AS "Name", TBNAME AS "Table", TBCREATOR AS "Schema",
TRIM(COLTYPE) AS "Type", LENGTH AS "Length", SCALE AS "Scale",
NULLS AS "IsNull", DEFAULT AS "Default", COLNO AS "Colno",
IDENTITY AS "IsIdentity", KEYSEQ AS "KeySeq", REMARKS AS "Comment"
FROM SYSIBM.SYSCOLUMNS
WHERE TBNAME = 'myTable' AND TBCREATOR = USER;`,
db2: `SELECT COLNAME AS "Name", TABNAME AS "Table", TABSCHEMA AS "Schema",
TYPENAME AS "Type", LENGTH AS "Length", SCALE AS "Scale", NULLS AS "IsNull",
DEFAULT AS "Default", COLNO AS "Colno", IDENTITY AS "IsIdentity", KEYSEQ AS "KeySeq",
REMARKS AS "Comment" FROM SYSCAT.COLUMNS WHERE TABNAME = 'myTable' AND TABSCHEMA = 'DB2INST1'`,
ibmi: `SELECT
QSYS2.SYSCOLUMNS.*,
QSYS2.SYSCST.CONSTRAINT_NAME,
Expand Down Expand Up @@ -360,12 +352,10 @@ describe('QueryGenerator#describeTableQuery', () => {
AND prop.name = 'MS_Description'
WHERE t.TABLE_NAME = N'myTable' AND t.TABLE_SCHEMA = N'mySchema'`,
sqlite: 'PRAGMA TABLE_INFO(`mySchema.myTable`)',
db2: `SELECT NAME AS "Name", TBNAME AS "Table", TBCREATOR AS "Schema",
TRIM(COLTYPE) AS "Type", LENGTH AS "Length", SCALE AS "Scale",
NULLS AS "IsNull", DEFAULT AS "Default", COLNO AS "Colno",
IDENTITY AS "IsIdentity", KEYSEQ AS "KeySeq", REMARKS AS "Comment"
FROM SYSIBM.SYSCOLUMNS
WHERE TBNAME = 'myTable' AND TBCREATOR = 'mySchema';`,
db2: `SELECT COLNAME AS "Name", TABNAME AS "Table", TABSCHEMA AS "Schema",
TYPENAME AS "Type", LENGTH AS "Length", SCALE AS "Scale", NULLS AS "IsNull",
DEFAULT AS "Default", COLNO AS "Colno", IDENTITY AS "IsIdentity", KEYSEQ AS "KeySeq",
REMARKS AS "Comment" FROM SYSCAT.COLUMNS WHERE TABNAME = 'myTable' AND TABSCHEMA = 'mySchema'`,
ibmi: `SELECT
QSYS2.SYSCOLUMNS.*,
QSYS2.SYSCST.CONSTRAINT_NAME,
Expand Down

0 comments on commit c59011c

Please sign in to comment.