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: 309
Committed: Tue Jul 21 08:00:42 2020 UTC (3 years, 9 months ago) by tony
Content type: text/x-pascal
File size: 10632 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 FCharSetWidth: integer;
65 protected
66 procedure LoadMetaData(aAttachment: IAttachment; aTransaction: ITransaction;
67 relationName, columnName: AnsiString); override;
68 public
69 function GetCharSetID: cardinal; override;
70 function GetCodePage: TSystemCodePage; override;
71 function GetCharSetWidth: integer; override;
72 end;
73
74 { TFB30Array }
75
76 TFB30Array = class(TFBArray,IArray)
77 private
78 FAttachmentIntf: Firebird.IAttachment;
79 FTransactionIntf: Firebird.ITransaction;
80 FFirebird30ClientAPI: TFB30ClientAPI;
81 FSDL: ISDL;
82 protected
83 procedure AllocateBuffer; override;
84 procedure InternalGetSlice; override;
85 procedure InternalPutSlice(Force: boolean); override;
86 public
87 constructor Create(aAttachment: TFB30Attachment; aTransaction: TFB30Transaction; aField: IArrayMetaData); overload;
88 constructor Create(aAttachment: TFB30Attachment; aTransaction: TFB30Transaction; aField: IArrayMetaData; ArrayID: TISC_QUAD); overload;
89 end;
90
91 TSDLItem = class(TParamBlockItem,ISDLItem);
92
93 { TSDLBlock }
94
95 TSDLBlock = class (TCustomParamBlock<TSDLItem,ISDLItem>, ISDL)
96 public
97 constructor Create(api: TFBClientAPI);
98 end;
99
100 implementation
101
102 uses FBAttachment, FB30Statement;
103
104 const
105 sGetArrayMetaData = 'Select F.RDB$FIELD_LENGTH, F.RDB$FIELD_SCALE, F.RDB$FIELD_TYPE, '+
106 'F.RDB$DIMENSIONS, FD.RDB$DIMENSION, FD.RDB$LOWER_BOUND, FD.RDB$UPPER_BOUND, '+
107 'F.RDB$CHARACTER_SET_ID '+
108 'From RDB$FIELDS F JOIN RDB$RELATION_FIELDS RF '+
109 'On F.RDB$FIELD_NAME = RF.RDB$FIELD_SOURCE JOIN RDB$FIELD_DIMENSIONS FD '+
110 'On FD.RDB$FIELD_NAME = F.RDB$FIELD_NAME ' +
111 'Where RF.RDB$RELATION_NAME = ? and RF.RDB$FIELD_NAME = ? ' +
112 'UNION '+
113 'Select F.RDB$FIELD_LENGTH, F.RDB$FIELD_SCALE, F.RDB$FIELD_TYPE, '+
114 'F.RDB$DIMENSIONS, FD.RDB$DIMENSION, FD.RDB$LOWER_BOUND, FD.RDB$UPPER_BOUND, '+
115 'F.RDB$CHARACTER_SET_ID '+
116 'From RDB$FIELDS F JOIN RDB$PROCEDURE_PARAMETERS PP '+
117 'On F.RDB$FIELD_NAME = PP.RDB$FIELD_SOURCE JOIN RDB$FIELD_DIMENSIONS FD '+
118 'On FD.RDB$FIELD_NAME = F.RDB$FIELD_NAME ' +
119 'Where PP.RDB$PROCEDURE_NAME = ? and PP.RDB$PARAMETER_NAME = ? '+
120 'Order by 5 asc';
121
122
123 { TFB30ArrayMetaData }
124
125 {Assemble the array descriptor from the System Tables}
126
127 procedure TFB30ArrayMetaData.LoadMetaData(aAttachment: IAttachment;
128 aTransaction: ITransaction; relationName, columnName: AnsiString);
129 var stmt: IStatement;
130 CharWidth: integer;
131 begin
132 CharWidth := 0;
133 RelationName := AnsiUpperCase(RelationName);
134 ColumnName := AnsiUpperCase(ColumnName);
135 stmt := TFB30Statement.Create(aAttachment as TFB30Attachment,aTransaction,
136 sGetArrayMetaData ,aAttachment.GetSQLDialect);
137 with stmt do
138 begin
139 SQLParams[0].AsString := RelationName;
140 SQLParams[1].AsString := ColumnName;
141 SQLParams[2].AsString := RelationName;
142 SQLParams[3].AsString := ColumnName;
143 with OpenCursor do
144 if FetchNext then
145 begin
146 FillChar(FArrayDesc.array_desc_field_name,sizeof(FArrayDesc.array_desc_field_name),' ');
147 FillChar(FArrayDesc.array_desc_relation_name,sizeof(FArrayDesc.array_desc_relation_name),' ');
148 Move(columnName[1],FArrayDesc.array_desc_field_name,Length(columnName));
149 Move(relationName[1],FArrayDesc.array_desc_relation_name,length(relationName));
150 FArrayDesc.array_desc_length := Data[0].AsInteger;
151 FArrayDesc.array_desc_scale := Data[1].AsInteger;
152 FArrayDesc.array_desc_dtype := Data[2].AsInteger;
153 FArrayDesc.array_desc_dimensions := Data[3].AsInteger;
154 FArrayDesc.array_desc_flags := 0; {row major}
155 FCharSetID := Data[7].AsInteger;
156 if (FCharSetID > 1) and (aAttachment as TFB30Attachment).HasDefaultCharSet then
157 FCharSetID := (aAttachment as TFB30Attachment).CharSetID;
158 FCodePage := CP_NONE;
159 FAttachment.CharSetID2CodePage(FCharSetID,FCodePage);
160 FCharSetWidth := 1;
161 FAttachment.CharSetWidth(FCharSetID,FCharSetWidth);
162 if (FArrayDesc.array_desc_dtype in [blr_text,blr_cstring, blr_varying]) and
163 (FCharSetID = 0) then {This really shouldn't be necessary - but it is :(}
164 with aAttachment as TFBAttachment do
165 begin
166 if HasDefaultCharSet and FAttachment.CharSetWidth(CharSetID,CharWidth) then
167 FArrayDesc.array_desc_length := FArrayDesc.array_desc_length * CharWidth;
168 end;
169 repeat
170 with FArrayDesc.array_desc_bounds[Data[4].AsInteger] do
171 begin
172 array_bound_lower := Data[5].AsInteger;
173 array_bound_upper := Data[6].AsInteger;
174 end;
175 until not FetchNext;
176 end;
177 end;
178 end;
179
180 function TFB30ArrayMetaData.GetCharSetID: cardinal;
181 begin
182 Result := FCharSetID;
183 end;
184
185 function TFB30ArrayMetaData.GetCodePage: TSystemCodePage;
186 begin
187 Result := FCodePage;
188 end;
189
190 function TFB30ArrayMetaData.GetCharSetWidth: integer;
191 begin
192 Result := FCharSetWidth;
193 end;
194
195 { TFB30Array }
196
197 procedure TFB30Array.AllocateBuffer;
198
199 procedure AddVarInteger(aValue: integer);
200 begin
201 if (aValue >= -128) and (aValue <= 127) then
202 FSDL.Add(isc_sdl_tiny_integer).SetAsTinyInteger(aValue)
203 else
204 if (aValue >= -32768) and (aValue <= 32767) then
205 FSDL.Add(isc_sdl_short_integer).SetAsShortInteger(aValue)
206 else
207 FSDL.Add(isc_sdl_long_integer).SetAsInteger(aValue);
208 end;
209
210 var i: integer;
211 SDLItem: ISDLItem;
212 begin
213 inherited AllocateBuffer;
214 {Now set up the SDL}
215
216 FSDL := TSDLBlock.Create(FFirebird30ClientAPI);
217 with GetArrayDesc^ do
218 {The following is based on gen_SDL from Firebird src/dsql/array.cpp}
219 begin
220 SDLItem := FSDL.Add(isc_sdl_struct);
221 SDLItem.SetAsByte(array_desc_dtype);
222
223 case array_desc_dtype of
224 blr_short,blr_long,
225 blr_int64,blr_quad:
226 SDLItem.addShortInt(byte(array_desc_scale));
227
228 blr_text,blr_cstring, blr_varying:
229 SDLItem.addShortInteger(array_desc_length);
230 end;
231
232 FSDL.Add(isc_sdl_relation).SetAsString(array_desc_relation_name);
233 FSDL.Add(isc_sdl_field).SetAsString(array_desc_field_name);
234
235 for i := 0 to array_desc_dimensions - 1 do
236 begin
237 if array_desc_bounds[i].array_bound_lower = 1 then
238 FSDL.Add(isc_sdl_do1).SetAsTinyInteger(i)
239 else
240 begin
241 FSDL.Add(isc_sdl_do2).SetAsTinyInteger(i);
242 AddVarInteger(array_desc_bounds[i].array_bound_lower);
243 end;
244 AddVarInteger(array_desc_bounds[i].array_bound_upper);
245 end;
246
247 SDLItem := FSDL.Add(isc_sdl_element);
248 SDLItem.AddByte(1);
249 SDLItem := FSDL.Add(isc_sdl_scalar);
250 SDLItem.AddByte(0);
251 SDLItem.AddByte(array_desc_dimensions);
252 for i := 0 to array_desc_dimensions - 1 do
253 begin
254 SDLItem := FSDL.Add(isc_sdl_variable);
255 SDLItem.AddByte(i);
256 end;
257 FSDL.Add(isc_sdl_eoc);
258 end;
259 end;
260
261 procedure TFB30Array.InternalGetSlice;
262 begin
263 with FFirebird30ClientAPI do
264 begin
265 FAttachmentIntf.getSlice(StatusIntf,FTransactionIntf,
266 @FArrayID,
267 (FSDL as TSDLBlock).getDataLength,
268 BytePtr((FSDL as TSDLBlock).getBuffer),
269 0,nil,
270 FBufSize,BytePtr(FBuffer)
271 );
272 Check4DataBaseError;
273 end;
274 SignalActivity;
275 end;
276
277 procedure TFB30Array.InternalPutSlice(Force: boolean);
278 begin
279 with FFirebird30ClientAPI do
280 begin
281 FAttachmentIntf.putSlice(StatusIntf,FTransactionIntf, @FArrayID,
282 (FSDL as TSDLBlock).getDataLength,
283 BytePtr((FSDL as TSDLBlock).getBuffer),
284 0,nil,
285 FBufSize,BytePtr(FBuffer)
286 );
287 if not Force then
288 Check4DataBaseError;
289 end;
290 SignalActivity;
291 end;
292
293 constructor TFB30Array.Create(aAttachment: TFB30Attachment;
294 aTransaction: TFB30Transaction; aField: IArrayMetaData);
295 begin
296 inherited Create(aAttachment,aTransaction,aField);
297 FAttachmentIntf := aAttachment.AttachmentIntf;
298 FTransactionIntf := aTransaction.TransactionIntf;
299 FFirebird30ClientAPI := aAttachment.Firebird30ClientAPI;
300 end;
301
302 constructor TFB30Array.Create(aAttachment: TFB30Attachment;
303 aTransaction: TFB30Transaction; aField: IArrayMetaData; ArrayID: TISC_QUAD);
304 begin
305 inherited Create(aAttachment,aTransaction,aField,ArrayID);
306 FAttachmentIntf := aAttachment.AttachmentIntf;
307 FTransactionIntf := aTransaction.TransactionIntf;
308 FFirebird30ClientAPI := aAttachment.Firebird30ClientAPI;
309 end;
310
311 { TSDLBlock }
312
313 constructor TSDLBlock.Create(api: TFBClientAPI);
314 begin
315 inherited Create(api);
316 FDataLength := 1;
317 FBuffer^ := isc_sdl_version1;
318 end;
319
320 end.
321