ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/fbintf/client/3.0/FB30Array.pas
Revision: 308
Committed: Sat Jul 18 10:26:30 2020 UTC (3 years, 9 months ago) by tony
Content type: text/x-pascal
File size: 10378 byte(s)
Log Message:
Fixes Merged

File Contents

# Content
1 (*
2 * Firebird Interface (fbintf). The fbintf components provide a set of
3 * Pascal language bindings for the Firebird API.
4 *
5 * The contents of this file are subject to the Initial Developer's
6 * Public License Version 1.0 (the "License"); you may not use this
7 * file except in compliance with the License. You may obtain a copy
8 * of the License here:
9 *
10 * http://www.firebirdsql.org/index.php?op=doc&id=idpl
11 *
12 * Software distributed under the License is distributed on an "AS
13 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14 * implied. See the License for the specific language governing rights
15 * and limitations under the License.
16 *
17 * The Initial Developer of the Original Code is Tony Whyman.
18 *
19 * The Original Code is (C) 2016 Tony Whyman, MWA Software
20 * (http://www.mwasoftware.co.uk).
21 *
22 * All Rights Reserved.
23 *
24 * Contributor(s): ______________________________________.
25 *
26 *)
27 unit FB30Array;
28 {$IFDEF MSWINDOWS}
29 {$DEFINE WINDOWS}
30 {$ENDIF}
31
32 {$IFDEF FPC}
33 {$mode delphi}
34 {$codepage UTF8}
35 {$interfaces COM}
36 {$ENDIF}
37
38 interface
39
40 uses
41 Classes, SysUtils, Firebird, IB, FBArray, IBHeader, FB30Attachment, FBClientAPI,
42 FB30Transaction, FBParamBlock, FB30ClientAPI;
43
44 type
45
46 ISDLItem = interface(IParameterBlockItem)
47 ['{a34b6064-5ae9-4fc1-85c3-f145f069b607}']
48 procedure addByte(aValue: byte);
49 procedure addShortInt(aValue: ShortInt);
50 procedure addShortInteger(aValue: integer);
51 procedure SetAsShortInteger(aValue: integer);
52 procedure SetAsTinyInteger(aValue: integer);
53 end;
54
55 ISDL = interface(IParameterBlock<ISDLItem>)
56 ['{52ae1f5f-657b-4b14-81aa-7b3658454f4c}']
57 end;
58
59 { TFB30ArrayMetaData }
60
61 TFB30ArrayMetaData = class(TFBArrayMetaData,IArrayMetaData)
62 private
63 FCodePage: TSystemCodePage;
64 protected
65 procedure LoadMetaData(aAttachment: IAttachment; aTransaction: ITransaction;
66 relationName, columnName: AnsiString); override;
67 public
68 function GetCharSetID: cardinal; override;
69 function GetCodePage: TSystemCodePage; override;
70 end;
71
72 { TFB30Array }
73
74 TFB30Array = class(TFBArray,IArray)
75 private
76 FAttachmentIntf: Firebird.IAttachment;
77 FTransactionIntf: Firebird.ITransaction;
78 FFirebird30ClientAPI: TFB30ClientAPI;
79 FSDL: ISDL;
80 protected
81 procedure AllocateBuffer; override;
82 procedure InternalGetSlice; override;
83 procedure InternalPutSlice(Force: boolean); override;
84 public
85 constructor Create(aAttachment: TFB30Attachment; aTransaction: TFB30Transaction; aField: IArrayMetaData); overload;
86 constructor Create(aAttachment: TFB30Attachment; aTransaction: TFB30Transaction; aField: IArrayMetaData; ArrayID: TISC_QUAD); overload;
87 end;
88
89 TSDLItem = class(TParamBlockItem,ISDLItem);
90
91 { TSDLBlock }
92
93 TSDLBlock = class (TCustomParamBlock<TSDLItem,ISDLItem>, ISDL)
94 public
95 constructor Create(api: TFBClientAPI);
96 end;
97
98 implementation
99
100 uses FBAttachment, FB30Statement;
101
102 const
103 sGetArrayMetaData = 'Select F.RDB$FIELD_LENGTH, F.RDB$FIELD_SCALE, F.RDB$FIELD_TYPE, '+
104 'F.RDB$DIMENSIONS, FD.RDB$DIMENSION, FD.RDB$LOWER_BOUND, FD.RDB$UPPER_BOUND, '+
105 'F.RDB$CHARACTER_SET_ID '+
106 'From RDB$FIELDS F JOIN RDB$RELATION_FIELDS RF '+
107 'On F.RDB$FIELD_NAME = RF.RDB$FIELD_SOURCE JOIN RDB$FIELD_DIMENSIONS FD '+
108 'On FD.RDB$FIELD_NAME = F.RDB$FIELD_NAME ' +
109 'Where RF.RDB$RELATION_NAME = ? and RF.RDB$FIELD_NAME = ? ' +
110 'UNION '+
111 'Select F.RDB$FIELD_LENGTH, F.RDB$FIELD_SCALE, F.RDB$FIELD_TYPE, '+
112 'F.RDB$DIMENSIONS, FD.RDB$DIMENSION, FD.RDB$LOWER_BOUND, FD.RDB$UPPER_BOUND, '+
113 'F.RDB$CHARACTER_SET_ID '+
114 'From RDB$FIELDS F JOIN RDB$PROCEDURE_PARAMETERS PP '+
115 'On F.RDB$FIELD_NAME = PP.RDB$FIELD_SOURCE JOIN RDB$FIELD_DIMENSIONS FD '+
116 'On FD.RDB$FIELD_NAME = F.RDB$FIELD_NAME ' +
117 'Where PP.RDB$PROCEDURE_NAME = ? and PP.RDB$PARAMETER_NAME = ? '+
118 'Order by 5 asc';
119
120
121 { TFB30ArrayMetaData }
122
123 {Assemble the array descriptor from the System Tables}
124
125 procedure TFB30ArrayMetaData.LoadMetaData(aAttachment: IAttachment;
126 aTransaction: ITransaction; relationName, columnName: AnsiString);
127 var stmt: IStatement;
128 CharWidth: integer;
129 begin
130 CharWidth := 0;
131 RelationName := AnsiUpperCase(RelationName);
132 ColumnName := AnsiUpperCase(ColumnName);
133 stmt := TFB30Statement.Create(aAttachment as TFB30Attachment,aTransaction,
134 sGetArrayMetaData ,aAttachment.GetSQLDialect);
135 with stmt do
136 begin
137 SQLParams[0].AsString := RelationName;
138 SQLParams[1].AsString := ColumnName;
139 SQLParams[2].AsString := RelationName;
140 SQLParams[3].AsString := ColumnName;
141 with OpenCursor do
142 if FetchNext then
143 begin
144 FillChar(FArrayDesc.array_desc_field_name,sizeof(FArrayDesc.array_desc_field_name),' ');
145 FillChar(FArrayDesc.array_desc_relation_name,sizeof(FArrayDesc.array_desc_relation_name),' ');
146 Move(columnName[1],FArrayDesc.array_desc_field_name,Length(columnName));
147 Move(relationName[1],FArrayDesc.array_desc_relation_name,length(relationName));
148 FArrayDesc.array_desc_length := Data[0].AsInteger;
149 FArrayDesc.array_desc_scale := Data[1].AsInteger;
150 FArrayDesc.array_desc_dtype := Data[2].AsInteger;
151 FArrayDesc.array_desc_dimensions := Data[3].AsInteger;
152 FArrayDesc.array_desc_flags := 0; {row major}
153 FCharSetID := Data[7].AsInteger;
154 if (FCharSetID > 1) and (aAttachment as TFB30Attachment).HasDefaultCharSet then
155 FCharSetID := (aAttachment as TFB30Attachment).CharSetID;
156 FCodePage := CP_NONE;
157 FAttachment.CharSetID2CodePage(FCharSetID,FCodePage);
158 if (FArrayDesc.array_desc_dtype in [blr_text,blr_cstring, blr_varying]) and
159 (FCharSetID = 0) then {This really shouldn't be necessary - but it is :(}
160 with aAttachment as TFBAttachment do
161 begin
162 if HasDefaultCharSet and FAttachment.CharSetWidth(CharSetID,CharWidth) then
163 FArrayDesc.array_desc_length := FArrayDesc.array_desc_length * CharWidth;
164 end;
165 repeat
166 with FArrayDesc.array_desc_bounds[Data[4].AsInteger] do
167 begin
168 array_bound_lower := Data[5].AsInteger;
169 array_bound_upper := Data[6].AsInteger;
170 end;
171 until not FetchNext;
172 end;
173 end;
174 end;
175
176 function TFB30ArrayMetaData.GetCharSetID: cardinal;
177 begin
178 Result := FCharSetID;
179 end;
180
181 function TFB30ArrayMetaData.GetCodePage: TSystemCodePage;
182 begin
183 Result := FCodePage;
184 end;
185
186 { TFB30Array }
187
188 procedure TFB30Array.AllocateBuffer;
189
190 procedure AddVarInteger(aValue: integer);
191 begin
192 if (aValue >= -128) and (aValue <= 127) then
193 FSDL.Add(isc_sdl_tiny_integer).SetAsTinyInteger(aValue)
194 else
195 if (aValue >= -32768) and (aValue <= 32767) then
196 FSDL.Add(isc_sdl_short_integer).SetAsShortInteger(aValue)
197 else
198 FSDL.Add(isc_sdl_long_integer).SetAsInteger(aValue);
199 end;
200
201 var i: integer;
202 SDLItem: ISDLItem;
203 begin
204 inherited AllocateBuffer;
205 {Now set up the SDL}
206
207 FSDL := TSDLBlock.Create(FFirebird30ClientAPI);
208 with GetArrayDesc^ do
209 {The following is based on gen_SDL from Firebird src/dsql/array.cpp}
210 begin
211 SDLItem := FSDL.Add(isc_sdl_struct);
212 SDLItem.SetAsByte(array_desc_dtype);
213
214 case array_desc_dtype of
215 blr_short,blr_long,
216 blr_int64,blr_quad:
217 SDLItem.addShortInt(byte(array_desc_scale));
218
219 blr_text,blr_cstring, blr_varying:
220 SDLItem.addShortInteger(array_desc_length);
221 end;
222
223 FSDL.Add(isc_sdl_relation).SetAsString(array_desc_relation_name);
224 FSDL.Add(isc_sdl_field).SetAsString(array_desc_field_name);
225
226 for i := 0 to array_desc_dimensions - 1 do
227 begin
228 if array_desc_bounds[i].array_bound_lower = 1 then
229 FSDL.Add(isc_sdl_do1).SetAsTinyInteger(i)
230 else
231 begin
232 FSDL.Add(isc_sdl_do2).SetAsTinyInteger(i);
233 AddVarInteger(array_desc_bounds[i].array_bound_lower);
234 end;
235 AddVarInteger(array_desc_bounds[i].array_bound_upper);
236 end;
237
238 SDLItem := FSDL.Add(isc_sdl_element);
239 SDLItem.AddByte(1);
240 SDLItem := FSDL.Add(isc_sdl_scalar);
241 SDLItem.AddByte(0);
242 SDLItem.AddByte(array_desc_dimensions);
243 for i := 0 to array_desc_dimensions - 1 do
244 begin
245 SDLItem := FSDL.Add(isc_sdl_variable);
246 SDLItem.AddByte(i);
247 end;
248 FSDL.Add(isc_sdl_eoc);
249 end;
250 end;
251
252 procedure TFB30Array.InternalGetSlice;
253 begin
254 with FFirebird30ClientAPI do
255 begin
256 FAttachmentIntf.getSlice(StatusIntf,FTransactionIntf,
257 @FArrayID,
258 (FSDL as TSDLBlock).getDataLength,
259 BytePtr((FSDL as TSDLBlock).getBuffer),
260 0,nil,
261 FBufSize,BytePtr(FBuffer)
262 );
263 Check4DataBaseError;
264 end;
265 SignalActivity;
266 end;
267
268 procedure TFB30Array.InternalPutSlice(Force: boolean);
269 begin
270 with FFirebird30ClientAPI do
271 begin
272 FAttachmentIntf.putSlice(StatusIntf,FTransactionIntf, @FArrayID,
273 (FSDL as TSDLBlock).getDataLength,
274 BytePtr((FSDL as TSDLBlock).getBuffer),
275 0,nil,
276 FBufSize,BytePtr(FBuffer)
277 );
278 if not Force then
279 Check4DataBaseError;
280 end;
281 SignalActivity;
282 end;
283
284 constructor TFB30Array.Create(aAttachment: TFB30Attachment;
285 aTransaction: TFB30Transaction; aField: IArrayMetaData);
286 begin
287 inherited Create(aAttachment,aTransaction,aField);
288 FAttachmentIntf := aAttachment.AttachmentIntf;
289 FTransactionIntf := aTransaction.TransactionIntf;
290 FFirebird30ClientAPI := aAttachment.Firebird30ClientAPI;
291 end;
292
293 constructor TFB30Array.Create(aAttachment: TFB30Attachment;
294 aTransaction: TFB30Transaction; aField: IArrayMetaData; ArrayID: TISC_QUAD);
295 begin
296 inherited Create(aAttachment,aTransaction,aField,ArrayID);
297 FAttachmentIntf := aAttachment.AttachmentIntf;
298 FTransactionIntf := aTransaction.TransactionIntf;
299 FFirebird30ClientAPI := aAttachment.Firebird30ClientAPI;
300 end;
301
302 { TSDLBlock }
303
304 constructor TSDLBlock.Create(api: TFBClientAPI);
305 begin
306 inherited Create(api);
307 FDataLength := 1;
308 FBuffer^ := isc_sdl_version1;
309 end;
310
311 end.
312