1 |
tony |
402 |
unit UdrSelectInto; |
2 |
|
|
|
3 |
|
|
{ |
4 |
|
|
create or alter procedure select_into ( |
5 |
|
|
select_statement blob sub_type 1 not null, |
6 |
|
|
table_name varchar(63) not null, |
7 |
|
|
table_type varchar(25) not null -- 'global temporary preserve', 'global temporary[ delete]', <empty string> for standard table |
8 |
|
|
) returns ( |
9 |
|
|
status varchar(100) |
10 |
|
|
) |
11 |
|
|
external name 'selectinto!select_into' |
12 |
|
|
engine udr; |
13 |
|
|
} |
14 |
|
|
|
15 |
|
|
interface |
16 |
|
|
|
17 |
|
|
uses Classes, SysUtils, IB, FBUDRController, FBUDRIntf; |
18 |
|
|
|
19 |
|
|
type |
20 |
|
|
TSelectInto = class(TFBUDRExecuteProcedure) |
21 |
|
|
public |
22 |
|
|
procedure Execute(context: IFBUDRExternalContext; |
23 |
|
|
ProcMetadata: IFBUDRProcMetadata; |
24 |
|
|
InputParams: IFBUDRInputParams; |
25 |
|
|
OutputData: IFBUDROutputData); override; |
26 |
|
|
end; |
27 |
|
|
|
28 |
|
|
|
29 |
|
|
implementation |
30 |
|
|
|
31 |
|
|
uses StrUtils, IBUtils; |
32 |
|
|
|
33 |
|
|
function SQLType2Name(SQLType: Cardinal) : AnsiString; |
34 |
|
|
begin |
35 |
|
|
case SQLType of |
36 |
|
|
SQL_VARYING: Result := 'VARCHAR'; |
37 |
|
|
SQL_TEXT: Result := 'CHAR'; |
38 |
|
|
SQL_DOUBLE: Result := 'DOUBLE PRECISION'; |
39 |
|
|
SQL_FLOAT: Result := 'FLOAT'; |
40 |
|
|
SQL_LONG: Result := 'INTEGER'; |
41 |
|
|
SQL_SHORT: Result := 'SMALLINT'; |
42 |
|
|
SQL_TIMESTAMP: Result := 'TIMESTAMP'; |
43 |
|
|
SQL_TIMESTAMP_TZ: Result := 'TIMESTAMP WITH TIMEZONE'; |
44 |
|
|
SQL_TIMESTAMP_TZ_EX: Result := 'TIMESTAMP WITH TIMEZONE'; |
45 |
|
|
SQL_BLOB: Result := 'BLOB'; |
46 |
|
|
SQL_D_FLOAT: Result := 'FLOAT'; |
47 |
|
|
SQL_TYPE_TIME: Result := 'TIME'; |
48 |
|
|
SQL_TYPE_DATE: Result := 'DATE'; |
49 |
|
|
SQL_INT64: Result := 'BIGINT'; |
50 |
|
|
SQL_TIME_TZ: Result := 'TIME WITH TIMEZONE'; |
51 |
|
|
SQL_TIME_TZ_EX: Result := 'TIME WITH TIMEZONE'; |
52 |
|
|
SQL_DEC16: Result := 'DECFLOAT(16)'; |
53 |
|
|
SQL_DEC34: Result := 'DECFLOAT(34)'; |
54 |
|
|
SQL_INT128: Result := 'INT128'; |
55 |
|
|
SQL_NULL: Result := 'VARCHAR(1)'; |
56 |
|
|
SQL_BOOLEAN: Result := 'BOOLEAN'; |
57 |
|
|
else |
58 |
|
|
Result := 'UNKNOWN'; |
59 |
|
|
end |
60 |
|
|
end; |
61 |
|
|
|
62 |
|
|
function Fld2SQLTypeDef(SQLType: Cardinal; SubType: Integer; Size: Cardinal; Scale: Integer; CharSetClause: String) : AnsiString; |
63 |
|
|
var |
64 |
|
|
TypeDef: AnsiString; |
65 |
|
|
begin |
66 |
|
|
TypeDef := SQLType2Name(SQLType); |
67 |
|
|
|
68 |
|
|
if Scale < 0 then |
69 |
|
|
case SQLType of |
70 |
|
|
SQL_SHORT: TypeDef := format('NUMERIC(4,%d)', [-Scale]); |
71 |
|
|
SQL_LONG: TypeDef := format('NUMERIC(9,%d)', [-Scale]); |
72 |
|
|
SQL_DOUBLE: TypeDef := format('NUMERIC(15,%d)', [-Scale]); |
73 |
|
|
SQL_INT64: TypeDef := format('NUMERIC(18,%d)', [-Scale]); |
74 |
|
|
SQL_INT128: TypeDef := format('NUMERIC(35,%d)', [-Scale]); |
75 |
|
|
end |
76 |
|
|
else |
77 |
|
|
case SQLType of |
78 |
|
|
SQL_VARYING, |
79 |
|
|
SQL_TEXT: TypeDef := format(TypeDef + '(%d) %s', [Size, CharSetClause]); |
80 |
|
|
SQL_BLOB: TypeDef := format(TypeDef + ' SUB_TYPE %d %s', [SubType, CharSetClause]); |
81 |
|
|
end; |
82 |
|
|
Result := TypeDef; |
83 |
|
|
end; |
84 |
|
|
|
85 |
|
|
procedure TSelectInto.Execute(context: IFBUDRExternalContext; ProcMetadata: IFBUDRProcMetadata; InputParams: IFBUDRInputParams; OutputData: IFBUDROutputData); |
86 |
|
|
var |
87 |
|
|
Statement: IStatement; |
88 |
|
|
TX2: ITransaction; |
89 |
|
|
Dialect, DefaultCharSetID, i: Integer; |
90 |
|
|
SelectSQL, TableName, TableType: AnsiString; |
91 |
|
|
TypeDef, TypeDefs, CharSetClause, Command, CommitAction, SQL: AnsiString; |
92 |
|
|
begin |
93 |
|
|
TypeDefs := ''; |
94 |
|
|
with context do |
95 |
|
|
begin |
96 |
|
|
// prepare and analyse select_statement and create DDL of target table columns |
97 |
|
|
SelectSQL := InputParams.ByName('select_statement').AsString; |
98 |
|
|
Dialect := GetAttachment.GetSQLDialect; |
99 |
|
|
DefaultCharSetID := context.GetAttachment.getCharSetID; |
100 |
|
|
CharSetClause := ''; |
101 |
|
|
|
102 |
|
|
Statement := GetAttachment.Prepare(GetTransaction, SelectSQL); |
103 |
|
|
with Statement.MetaData do |
104 |
|
|
begin |
105 |
|
|
for i := 0 to Count -1 do |
106 |
|
|
begin |
107 |
|
|
with ColMetaData[i] do |
108 |
|
|
begin |
109 |
|
|
case GetSQLType of SQL_VARYING, |
110 |
|
|
SQL_TEXT, |
111 |
|
|
SQL_BLOB: if (DefaultCharSetID <> getCharSetID) then |
112 |
|
|
CharSetClause := 'CHARACTER SET ' + GetAttachment.GetCharsetName(getCharSetID); |
113 |
|
|
end; |
114 |
|
|
TypeDef := Fld2SQLTypeDef(GetSQLType, SQLSubtype, Size, Scale, CharSetClause); |
115 |
|
|
TypeDefs := TypeDefs + ','#13#10 + QuoteIdentifierIfNeeded(Dialect, Name) + ' ' + TypeDef; |
116 |
|
|
end; |
117 |
|
|
end; |
118 |
|
|
Delete(TypeDefs, 1, 1); |
119 |
|
|
end; |
120 |
|
|
|
121 |
|
|
// create target table DDL |
122 |
|
|
TableName := InputParams.ByName('table_name').AsString; |
123 |
|
|
TableType := UpperCase(InputParams.ByName('table_type').AsString); |
124 |
|
|
|
125 |
|
|
// default: recreate standard table |
126 |
|
|
Command := 'RECREATE '; |
127 |
|
|
|
128 |
|
|
// global temporary? |
129 |
|
|
CommitAction := ''; |
130 |
|
|
if AnsiContainsStr(TableType, 'GLOBAL TEMPORARY') then |
131 |
|
|
begin |
132 |
|
|
Command := Command + 'GLOBAL TEMPORARY'; |
133 |
|
|
if AnsiContainsStr(TableType, 'PRESERVE') then |
134 |
|
|
CommitAction := 'ON COMMIT PRESERVE ROWS'; |
135 |
|
|
end; |
136 |
|
|
|
137 |
|
|
// create target table within own TX, needs to be committed separately |
138 |
|
|
SQL := SQL + format('%s TABLE %s (%s) %s', [Command, TableName, TypeDefs, CommitAction]); |
139 |
|
|
TX2 := GetAttachment.StartTransaction([isc_tpb_write, isc_tpb_nowait, isc_tpb_read_committed], taCommit); |
140 |
|
|
GetAttachment.ExecImmediate(TX2, SQL); |
141 |
|
|
TX2.Commit(); |
142 |
|
|
|
143 |
|
|
// fill target table |
144 |
|
|
SQL := format('INSERT INTO %s %s;', [TableName, SelectSQL]); |
145 |
|
|
GetAttachment.ExecImmediate(GetTransaction, SQL); |
146 |
|
|
end; |
147 |
|
|
OutputData.ByName('status').AsString := 'ok'; |
148 |
|
|
end; |
149 |
|
|
|
150 |
|
|
initialization |
151 |
|
|
|
152 |
|
|
FBRegisterUDRProcedure('select_into', TSelectInto); |
153 |
|
|
|
154 |
|
|
end. |