Lokasi ngalangkungan proxy:   [ UP ]  
[Ngawartoskeun bug]   [Panyetelan cookie]                
Skip to content

Commit 916365f

Browse files
taozhi8833998claude
andcommitted
feat(db2): support DECLARE GLOBAL TEMPORARY TABLE statement
Add support for DB2's DECLARE GLOBAL TEMPORARY TABLE syntax including: - Subquery form: DECLARE GLOBAL TEMPORARY TABLE ... AS (SELECT ...) - Column definition form: DECLARE GLOBAL TEMPORARY TABLE ... (col INT, ...) - Options: WITH DATA, WITH REPLACE, DEFINITION ONLY - ON COMMIT PRESERVE/DELETE ROWS - ON ROLLBACK PRESERVE/DELETE ROWS - NOT LOGGED - IN tablespace Fixes taozhi8833998#2630 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 6271a0f commit 916365f

3 files changed

Lines changed: 140 additions & 4 deletions

File tree

pegjs/db2.pegjs

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ cmd_stmt
121121
/ set_stmt
122122
/ lock_stmt
123123
/ unlock_stmt
124+
/ declare_stmt
124125

125126
create_stmt
126127
= create_table_stmt
@@ -380,6 +381,83 @@ use_stmt
380381
};
381382
}
382383

384+
// DB2 DECLARE GLOBAL TEMPORARY TABLE statement
385+
declare_stmt
386+
= KW_DECLARE __ KW_GLOBAL __ KW_TEMPORARY __ KW_TABLE __ t:table_name __
387+
KW_AS __ LPAREN __ s:union_stmt __ RPAREN __
388+
opts:declare_global_temp_table_opts? {
389+
if (t) tableList.add(`declare::${t.db}::${t.table}`);
390+
return {
391+
tableList: Array.from(tableList),
392+
columnList: columnListTableAlias(columnList),
393+
ast: {
394+
type: 'declare',
395+
declare: [{
396+
keyword: 'global temporary table',
397+
name: t,
398+
as: 'as',
399+
prefix: 'global temporary table',
400+
definition: s.ast,
401+
definition_type: 'subquery',
402+
...(opts || {})
403+
}]
404+
}
405+
}
406+
}
407+
/ KW_DECLARE __ KW_GLOBAL __ KW_TEMPORARY __ KW_TABLE __ t:table_name __
408+
c:create_table_definition __
409+
opts:declare_global_temp_table_opts? {
410+
if (t) tableList.add(`declare::${t.db}::${t.table}`);
411+
return {
412+
tableList: Array.from(tableList),
413+
columnList: columnListTableAlias(columnList),
414+
ast: {
415+
type: 'declare',
416+
declare: [{
417+
keyword: 'global temporary table',
418+
name: t,
419+
prefix: 'global temporary table',
420+
definition: c,
421+
definition_type: 'columns',
422+
...(opts || {})
423+
}]
424+
}
425+
}
426+
}
427+
428+
declare_global_temp_table_opts
429+
= head:declare_global_temp_table_opt tail:(__ declare_global_temp_table_opt)* {
430+
let result = head
431+
for (let i = 0; i < tail.length; i++) {
432+
result = { ...result, ...tail[i][1] }
433+
}
434+
return result
435+
}
436+
437+
declare_global_temp_table_opt
438+
= KW_WITH __ kw:('DATA'i / 'NO'i __ 'DATA'i) {
439+
const value = Array.isArray(kw) ? kw.filter(k => k && k.trim()).join(' ') : kw
440+
return { with_data: value.toLowerCase() }
441+
}
442+
/ KW_WITH __ 'REPLACE'i {
443+
return { with_replace: 'replace' }
444+
}
445+
/ 'DEFINITION'i __ 'ONLY'i {
446+
return { definition_only: 'definition only' }
447+
}
448+
/ KW_ON __ 'COMMIT'i __ action:('PRESERVE'i / 'DELETE'i) __ 'ROWS'i {
449+
return { on_commit: `${action.toLowerCase()} rows` }
450+
}
451+
/ KW_ON __ 'ROLLBACK'i __ action:('PRESERVE'i / 'DELETE'i) __ 'ROWS'i {
452+
return { on_rollback: `${action.toLowerCase()} rows` }
453+
}
454+
/ KW_NOT __ 'LOGGED'i {
455+
return { not_logged: 'not logged' }
456+
}
457+
/ KW_IN __ ts:ident_name {
458+
return { in_tablespace: ts }
459+
}
460+
383461
alter_table_stmt
384462
= KW_ALTER __
385463
KW_TABLE __

src/command.js

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,8 @@ function declareToSQL(stmt) {
138138
const { type, declare, symbol } = stmt
139139
const result = [toUpper(type)]
140140
const info = declare.map(dec => {
141-
const { at, name, as, constant, datatype, not_null, prefix, definition, keyword } = dec
142-
const declareInfo = [[at, name].filter(hasVal).join(''), toUpper(as), toUpper(constant)]
141+
const { at, name, as, constant, datatype, not_null, prefix, definition, definition_type, keyword } = dec
142+
const declareInfo = [[at, typeof name === 'string' ? name : tableToSQL(name)].filter(hasVal).join(''), toUpper(as), toUpper(constant)]
143143
switch (keyword) {
144144
case 'variable':
145145
declareInfo.push(columnDataType(datatype), exprToSQL(dec.collate), toUpper(not_null))
@@ -151,11 +151,27 @@ function declareToSQL(stmt) {
151151
case 'table':
152152
declareInfo.push(toUpper(prefix), `(${definition.map(createDefinitionToSQL).join(', ')})`)
153153
break
154+
case 'global temporary table':
155+
declareInfo.unshift(toUpper(prefix))
156+
if (definition_type === 'subquery') {
157+
declareInfo.push(`(${astToSQL(definition)})`)
158+
} else if (definition_type === 'columns') {
159+
declareInfo.push(`(${definition.map(createDefinitionToSQL).join(', ')})`)
160+
}
161+
// Add DB2-specific options
162+
if (dec.definition_only) declareInfo.push(toUpper(dec.definition_only))
163+
if (dec.with_data) declareInfo.push('WITH', toUpper(dec.with_data))
164+
if (dec.with_replace) declareInfo.push('WITH', toUpper(dec.with_replace))
165+
if (dec.on_commit) declareInfo.push('ON COMMIT', toUpper(dec.on_commit))
166+
if (dec.on_rollback) declareInfo.push('ON ROLLBACK', toUpper(dec.on_rollback))
167+
if (dec.not_logged) declareInfo.push(toUpper(dec.not_logged))
168+
if (dec.in_tablespace) declareInfo.push('IN', dec.in_tablespace)
169+
break
154170
default:
155171
break
156172
}
157173
return declareInfo.filter(hasVal).join(' ')
158-
}).join(`${symbol} `)
174+
}).join(`${symbol || ''} `)
159175
result.push(info)
160176
return result.join(' ')
161177
}

test/db2.spec.js

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,49 @@ describe('db2', () => {
1616
sql = 'SELECT * FROM "FGVST2"."CONTACT_TABLE25" FETCH FIRST 10 ROWS ONLY'
1717
expect(getParsedSql(sql)).to.be.equal('SELECT * FROM FGVST2.CONTACT_TABLE25 FETCH FIRST 10 ROWS ONLY')
1818
})
19-
19+
20+
describe('declare global temporary table', () => {
21+
it('should support declare global temporary table with subquery and WITH DATA WITH REPLACE', () => {
22+
const sql = 'declare global temporary table soldoutitems as (select * from items where a = 0) with data with replace'
23+
expect(getParsedSql(sql)).to.be.equal('DECLARE GLOBAL TEMPORARY TABLE soldoutitems AS (SELECT * FROM items WHERE a = 0) WITH DATA WITH REPLACE')
24+
})
25+
26+
it('should support declare global temporary table with column definitions', () => {
27+
const sql = 'declare global temporary table temp_table (col1 integer, col2 varchar(30))'
28+
expect(getParsedSql(sql)).to.be.equal('DECLARE GLOBAL TEMPORARY TABLE temp_table (col1 INTEGER, col2 VARCHAR(30))')
29+
})
30+
31+
it('should support declare global temporary table with ON COMMIT PRESERVE ROWS', () => {
32+
const sql = 'declare global temporary table temp_table (col1 integer) on commit preserve rows'
33+
expect(getParsedSql(sql)).to.be.equal('DECLARE GLOBAL TEMPORARY TABLE temp_table (col1 INTEGER) ON COMMIT PRESERVE ROWS')
34+
})
35+
36+
it('should support declare global temporary table with ON COMMIT DELETE ROWS', () => {
37+
const sql = 'declare global temporary table temp_table (col1 integer) on commit delete rows'
38+
expect(getParsedSql(sql)).to.be.equal('DECLARE GLOBAL TEMPORARY TABLE temp_table (col1 INTEGER) ON COMMIT DELETE ROWS')
39+
})
40+
41+
it('should support declare global temporary table with NOT LOGGED', () => {
42+
const sql = 'declare global temporary table temp_table (col1 integer) not logged'
43+
expect(getParsedSql(sql)).to.be.equal('DECLARE GLOBAL TEMPORARY TABLE temp_table (col1 INTEGER) NOT LOGGED')
44+
})
45+
46+
it('should support declare global temporary table with multiple options', () => {
47+
const sql = 'declare global temporary table temp_table (col1 integer) on commit preserve rows not logged with replace'
48+
expect(getParsedSql(sql)).to.be.equal('DECLARE GLOBAL TEMPORARY TABLE temp_table (col1 INTEGER) WITH REPLACE ON COMMIT PRESERVE ROWS NOT LOGGED')
49+
})
50+
51+
it('should support declare global temporary table with DEFINITION ONLY', () => {
52+
const sql = 'declare global temporary table temp_table as (select * from items) definition only'
53+
expect(getParsedSql(sql)).to.be.equal('DECLARE GLOBAL TEMPORARY TABLE temp_table AS (SELECT * FROM items) DEFINITION ONLY')
54+
})
55+
56+
it('should support declare global temporary table with schema prefix', () => {
57+
const sql = 'declare global temporary table "session".temp_table (col1 integer)'
58+
expect(getParsedSql(sql)).to.be.equal('DECLARE GLOBAL TEMPORARY TABLE session.temp_table (col1 INTEGER)')
59+
})
60+
})
61+
2062
SQL_LIST = [
2163
{
2264
title: 'except multiple select stmt',

0 commit comments

Comments
 (0)