11import { ColumnMetaData , QueryResult } from "@ibm/mapepire-js" ;
2+ import { Token } from "../../language/sql/types" ;
3+ import { tokenIs } from "../../language/sql/statement" ;
24
3- export function queryResultToRpgDs ( result : QueryResult < any > , source : string = 'Name' ) : string {
5+ export function queryResultToRpgDs ( result : QueryResult < any > , source : string = 'Name' ) : string {
46 let content = `dcl-ds row_t qualified template;\n` ;
57 for ( let i = 0 ; i < result . metadata . column_count ; i ++ ) {
68 const name = columnToRpgFieldName ( result . metadata . columns [ i ] , source ) ;
@@ -10,7 +12,7 @@ export function queryResultToRpgDs(result: QueryResult<any>, source: string = 'N
1012 return content ;
1113}
1214
13- export function columnToRpgFieldName ( column : ColumnMetaData , source : string = 'Name' ) : string {
15+ export function columnToRpgFieldName ( column : ColumnMetaData , source : string = 'Name' ) : string {
1416 let name = source === 'Label' ? column . label . toLowerCase ( ) . trim ( ) : column . name . toLowerCase ( ) . trim ( ) ;
1517 name = name . replace ( / \u00fc / g, "u" ) // ü -> u
1618 . replace ( / \u00e4 / g, "a" ) // ä -> a
@@ -24,14 +26,14 @@ export function columnToRpgFieldName(column: ColumnMetaData, source: string = 'N
2426 . replace ( / \s + / g, "_" ) // remaining whitespaces to underscore
2527 . replace ( / [ ^ a - z A - Z 0 - 9 _ ] / g, "" ) // remove non-alphanumeric chars
2628 . replace ( / \_ + / i, "_" ) // replace multiple underscores with single underscore
27- . trim ( ) ;
29+ . trim ( ) ;
2830 if ( ! isNaN ( + name . charAt ( 0 ) ) ) {
2931 name = `col` + name ;
3032 }
3133 return name ;
3234}
3335
34- export function columnToRpgDefinition ( column : ColumnMetaData ) : string {
36+ export function columnToRpgDefinition ( column : ColumnMetaData ) : string {
3537 switch ( column . type ) {
3638 case `NUMERIC` :
3739 return `zoned(${ column . precision } ${ column . scale > 0 ? ' : ' + column . scale : '' } )` ;
@@ -59,3 +61,106 @@ export function columnToRpgDefinition(column: ColumnMetaData) : string {
5961 return `// type:${ column . type } precision:${ column . precision } scale:${ column . scale } ` ;
6062 }
6163}
64+
65+ export function queryResultToUdtf ( result : QueryResult < any > , sqlStatement : string , tokens : Token [ ] ) : string {
66+ let columnDefinitions = '' ;
67+ for ( let i = 0 ; i < result . metadata . column_count ; i ++ ) {
68+ const column = result . metadata . columns [ i ] ;
69+ columnDefinitions += ` ${ column . name } ${ columnToSqlDefinition ( column ) } ` ;
70+ if ( i < result . metadata . column_count - 1 ) {
71+ columnDefinitions += ',\n' ;
72+ } else {
73+ columnDefinitions += '\n' ;
74+ }
75+ }
76+
77+ if ( tokens . length > 4 &&
78+ tokenIs ( tokens [ 0 ] , `word` , `UDTF` ) &&
79+ tokenIs ( tokens [ 1 ] , `colon` , `:` ) &&
80+ tokenIs ( tokens [ 2 ] , `statementType` , `SELECT` ) &&
81+ tokenIs ( tokens [ 3 ] , `asterisk` , `*` ) ) {
82+ const prefixEnd = ( tokens [ 3 ] . range . start - tokens [ 0 ] . range . start ) - ( tokens [ 1 ] . range . start - tokens [ 0 ] . range . start ) - 2 ;
83+ const suffixStart = ( tokens [ 3 ] . range . start - tokens [ 0 ] . range . start ) - ( tokens [ 1 ] . range . start - tokens [ 0 ] . range . start ) ;
84+ const columns = result . metadata . columns . map ( column => column . name ) . join ( `,\n ` )
85+ sqlStatement = `${ sqlStatement . substring ( 0 , prefixEnd ) } ${ columns } \n ${ sqlStatement . substring ( suffixStart ) } ` ;
86+ }
87+
88+ return `CREATE OR REPLACE FUNCTION MyFunction()\n`
89+ + ` RETURNS TABLE (\n`
90+ + columnDefinitions
91+ + ` )\n`
92+ + ` NOT DETERMINISTIC\n`
93+ + ` NO EXTERNAL ACTION\n`
94+ + ` READS SQL DATA\n`
95+ + ` SET OPTION COMMIT = *NONE,\n`
96+ + ` DBGVIEW = *SOURCE,\n`
97+ + ` DYNUSRPRF = *USER,\n`
98+ + ` USRPRF = *USER\n`
99+ + ` BEGIN\n`
100+ + ` RETURN ${ sqlStatement } ;\n`
101+ + ` END;` ;
102+ }
103+
104+ /**
105+ * Based on built-in types: https://www.ibm.com/docs/en/i/7.6.0?topic=statements-create-table
106+ */
107+ export function columnToSqlDefinition ( column : ColumnMetaData ) : string {
108+ switch ( column . type ) {
109+ case 'SMALLINT' :
110+ return `SMALLINT` ;
111+ case 'INTEGER' :
112+ return `INTEGER` ;
113+ case 'BIGINT' :
114+ return `BIGINT` ;
115+ case 'DECIMAL' :
116+ return `DECIMAL(${ column . precision } ,${ column . scale } )` ;
117+ case 'NUMERIC' :
118+ return `NUMERIC(${ column . precision } ,${ column . scale } )` ;
119+ case 'REAL' :
120+ return `REAL` ;
121+ case 'DOUBLE' :
122+ return `DOUBLE` ;
123+ case 'DECFLOAT' :
124+ return `DECFLOAT(${ column . precision } )` ;
125+ case 'CHAR' :
126+ return `CHAR(${ column . precision } )` ;
127+ case 'VARCHAR' :
128+ return `VARCHAR(${ column . precision } )` ;
129+ case 'CLOB' :
130+ return `CLOB(${ column . precision } )` ;
131+ case 'GRAPHIC' :
132+ return `GRAPHIC(${ column . precision } )` ;
133+ case 'VARGRAPHIC' :
134+ return `VARGRAPHIC(${ column . precision } )` ;
135+ case 'DBCLOB' :
136+ return `DBCLOB(${ column . precision } )` ;
137+ case 'NCHAR' :
138+ return `NCHAR(${ column . precision } )` ;
139+ case 'NVARCHAR' :
140+ return `NVARCHAR(${ column . precision } )` ;
141+ case 'NCLOB' :
142+ return `NCLOB(${ column . precision } )` ;
143+ case 'BINARY' :
144+ return `BINARY(${ column . precision } )` ;
145+ case 'VARBINARY' :
146+ return `VARBINARY(${ column . precision } )` ;
147+ case 'BLOB' :
148+ return `BLOB(${ column . precision } )` ;
149+ case 'DATE' :
150+ return `DATE` ;
151+ case 'TIME' :
152+ return `TIME` ;
153+ case 'TIMESTAMP' :
154+ return `TIMESTAMP(${ column . scale } )` ;
155+ case 'DATALINK' :
156+ return `DATALINK(${ column . precision } )` ;
157+ case 'ROWID' :
158+ return `ROWID` ;
159+ case 'XML' :
160+ return `XML` ;
161+ case 'BOOLEAN' :
162+ return `BOOLEAN` ;
163+ default :
164+ return `-- type:${ column . type } precision:${ column . precision } scale:${ column . scale } */` ;
165+ }
166+ }
0 commit comments