forked from synopse/mORMot
-
Notifications
You must be signed in to change notification settings - Fork 0
/
SynDB.pas
8747 lines (8209 loc) · 370 KB
/
SynDB.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/// abstract database direct access classes
// - this unit is a part of the freeware Synopse framework,
// licensed under a MPL/GPL/LGPL tri-license; version 1.18
unit SynDB;
{
This file is part of Synopse framework.
Synopse framework. Copyright (C) 2019 Arnaud Bouchez
Synopse Informatique - https://synopse.info
*** BEGIN LICENSE BLOCK *****
Version: MPL 1.1/GPL 2.0/LGPL 2.1
The contents of this file are subject to the Mozilla Public License Version
1.1 (the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL
Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the License.
The Original Code is Synopse mORMot framework.
The Initial Developer of the Original Code is Arnaud Bouchez.
Portions created by the Initial Developer are Copyright (C) 2019
the Initial Developer. All Rights Reserved.
Contributor(s):
- Adam Siwon (asiwon)
- Alexander (volax)
- Alfred Glaenzer (alf)
- delphinium
- dominikcz
- Esteban Martin (EMartin)
- Joe (at jokusoftware)
- Maciej Izak (hnb)
Alternatively, the contents of this file may be used under the terms of
either the GNU General Public License Version 2 or later (the "GPL"), or
the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
in which case the provisions of the GPL or the LGPL are applicable instead
of those above. If you wish to allow use of your version of this file only
under the terms of either the GPL or the LGPL, and not to allow others to
use your version of this file under the terms of the MPL, indicate your
decision by deleting the provisions above and replace them with the notice
and other provisions required by the GPL or the LGPL. If you do not delete
the provisions above, a recipient may use your version of this file under
the terms of any one of the MPL, the GPL or the LGPL.
***** END LICENSE BLOCK *****
Version 1.14
- first public release, corresponding to SQLite3 Framework 1.14
Version 1.15
- SynDB unit extracted from previous SynOleDB.pas
- TQueryValue.As* methods now handle NULL column as 0 or ''
- added new TSQLDBRowVariantType custom variant type, allowing late binding
access to row columns (not for Delphi 5) - see RowData method
- fixed transaction handling in a safe abstract manner
- TSQLDBStatement class now expects a prepared statement behavior, therefore
TSQLDBStatementPrepared class has been merged into its parent class, and
inherited classes have been renamed TSQLDBStatementWithParams[AndColumns]
- new TSQLDBStatement.FetchAllAsJSON method for JSON retrieval as RawUTF8
- exposed FetchAllAsJSON method for ISQLDBRows interface
- made the code compatible with Delphi 5
- new TSQLDBConnectionProperties.SQLIso8601ToDate virtual method
- code refactoring for better metadata (database and table schemas) handling,
including GetTableNames, GetFields, GetFieldDefinitions and GetForeignKey
methods - will work with OleDB metadata and direct Oracle sys.all_* tables
- new TSQLDBConnectionProperties.SQLCreate/SQLAddColumn/SQLAddIndex virtual
methods (SQLCreate and SQLAddColumn will use the new protected SQLFieldCreate
virtual method to retrieve the SQL field definition from protected
fSQLCreateField[Max] properties) - as a result, SQL statement generation as
requested for mORMot is now much more generic than previously
- new overloaded TSQLDBStatement.Execute() method, able to mix % and ?
parameters in the SQL statement
- new TSQLDBStatement.BindNull() method
- new TSQLDBConnectionProperties.NewThreadSafeStatementPrepared and
TSQLDBConnection.NewStatementPrepared methods, able to be overridden to
implement a SQL statement caching (used e.g. for SynDBSQLite3)
- new TSQLDBConnection.ServerTimestamp property, which will return the
external database Server current date and time as TTimeLog/Int64 value
(current implementation handle Oracle, MSSQL and MySQL database engines -
with SQLite3, this will be the local PC time, just as for other DB engines)
- new overloaded TSQLDBStatement.Bind() method, which can bind an array
of const (i.e. an open list of Delphi arguments) to a statement
- new overloaded TSQLDBStatement.Bind() and ColumnToVarData() methods, able
to bind or retrieve values from a TVarData/TVarDataDynArray (used e.g.
for direct access to/from SQLite3 virtual table in the SQLite3DB unit)
- new ColumnTimestamp method for TSQLDBStatement/ISQLDBRows, returning a
TTimeLog/Int64 value for a date/time column
Version 1.16
- both TSQLDBStatement.FetchAllToJSON and FetchAllAsJSON methods now return
the number of rows data fetched (excluding field names)
- new class method TSQLDBConnectionProperties.GetFieldDefinition()
- new method TSQLDBStatement.FetchAllToCSVValues() for fast to-file CSV export
- new TSQLDBStatement.ColumnsToSQLInsert() and BindFromRows() methods to allow
fast data conversion/export between databases
- new TSQLDBConnectionProperties.SQLSelectAll method to retrieve a SELECT
statement according to a DB column expected layout
- new TSQLDBConnectionProperties.ClearConnectionPool method (could be used
to recreate all connections in case of DB or network failure/timeout)
- fixed issue in TSQLDBConnection.GetServerTimestamp method
Version 1.17
- code refactoring to allow direct ODBC connection implementation
- fixed random issue in TSQLDBConnection.GetServerTimestamp method (using
wrongly TTimeLog direct arithmetic, therefore raising EncodeTime() errors)
- fixed issue about creating unexisting NCLOB instead of CLOB/NCLOB
- fixed TQuery implementation to match the expected original behavior
(e.g. SQL.Clear) - also undefined buggy Last method (use ORDER DESC instead)
- fixed issue in TQuery when executing requests with parameters
- fixed issues in TQuery when translated SQL from named parameters to
positioned (?) parameters, and escaping strings
- enhanced MySQL DBMS back-end compatibility
- TQuery will now accept reused parameters in the SQL statement (just like
the original class)
- added TQueryValue.AsLargeInt property alias for better compatibility
- enhanced TSQLDBStatement.BindVariant() to handle varBoolean value as integer,
and to avoid most temporary conversions to string
- enhanced TSQLDBStatement.Bind(Params: TVarDataDynArray) to handle varDate,
and modified TQueryValue in consequence
- enhanced TSQLDBStatement.Bind(const Params: array of const) to accept
BLOB content, when transmitted after BinToBase64WithMagic() conversion,
and TDateTime parameters via Date[Time]ToSQL() encoding
- declared TSQLDBConnectionProperties.GetMainConnection() method as virtual,
then override it for thread-safe connections - see ticket [65e24b2de4]
- now TSQLDBStatement.ColumnToVarData method will store '' when TDateTime value
is 0, or a pure date or a pure time if the value is defined as such, just as
expected by http://www.sqlite.org/lang_datefunc.html - i.e. SQLite3DB
- added FieldSize optional parameter to TSQLDBStatement.ColumnType() method
(used e.g. by SynDBVCL to provide the expected field size on TDataSet)
- added TSQLDBStatement.ColumnBlobBytes() methods to retrieve TBytes BLOBs
- added TSQLDBConnection.InTransaction property
- added TSQLDBConnectionProperties.EngineName property
- added TSQLDBConnectionProperties.DBMS property, and huge code refactoring
among all SynDB* units for generic handling of DBMS-specific properties
- added TSQLDBConnectionProperties.AdaptSQLLimitForEngineList for handling
the LIMIT # statement in a database-agnostic form
- added TSQLDBConnectionProperties.BatchSendingAbilities property to define
the CRUD modes available in batch sending (see e.g. Oracle's array bind,
or MS SQL bulk insert feature)
- added direct access to the columns description via new property
TSQLDBStatementWithParamsAndColumns.Columns
- added TSQLDBColumnProperty.ColumnUnique property (mainly for
TSQLDBConnectionProperties.SQLFieldCreate to create proper SQL)
- new TSQLDBStatement.BindArray*() methods, introducing array binding for
faster database batch modifications (only implemented in SynDBOracle by now)
Version 1.18
- SQL statements are now cached by default - in some cases, it will increase
individual reading or writing speed by a factor of 4x
- TSQLDBConnectionProperties.Create will set ForcedSchemaName := 'dbo'
("DataBase Owner") by default for dMSSQL kind of database engine
- introducing TSQLDBConnectionProperties DefinitionTo/DefinitionToJSON/
DefinitionToFile methods and CreateFrom*() class methods to persist the
database connection properties, and the associated class, as JSON
- new TSQLDBConnectionProperties/TSQLDBConnection.OnProcess event handlers
- new TSQLDBConnectionProperties.OnStatementInfo event handler
- added TSQLDBConnectionProperties.StoreVoidStringAsNull, which will be
set e.g. for MS SQL and Jet databases which do not allow by default to
store '' values, but expect NULL instead
- TSQLDBConnection.Connect will now trigger OnProcess(speReconnected) and
update the new TSQLDBConnection.TotalConnectionCount property
- TSQLDBConnection.Disconnect will now flush internal statement cache
- TQuery.Execute() is now able to try to re-connect once in case of failure
- fixed issue with bound parameter in TQuery.Execute() for Unicode Delphi
- introducing new ISQLDBStatement interface, used by SQL statement cache
- avoid syntax error for some engines which do not accept an ending ';' in
SQL statements
- added RaiseExceptionOnError: boolean=false optional parameter to
TSQLDBConnection.NewStatementPrepared() method
- fixed TSQLDBConnection.NewStatementPrepared() so that a prepared statement
currently in use (e.g. for a mORMot virtual table external query with two
similar JOINed clauses) will create up to 9 cache slots - see [736295149a9]
- added TSQLDBConnection.LastErrorMessage and LastErrorException properties,
to retrieve the error when NewStatementPrepared() returned nil
- new TSQLDBConnection.ServerDateTime property, which will return the
external database Server current date and time as TDateTime value
- added TSQLDBConnectionProperties.ConnectionTimeOutMinutes property to
allow automatic recreation of all connections after an idle period of
time, to avoid potential broken connection issues - see [f024266c08]
- added TSQLDBConnectionProperties.ForcedSchemaName optional property
- added TSQLDBConnectionProperties.DBMSEngineName property
- added TSQLDBConnectionProperties.SQLGetIndex() and GetIndexes() methods
to retrieve advanced information about database indexes (e.g. for indexes
created after multiple columns)
- added TSQLDBConnectionProperties.SQLTableName() method
- added TSQLDBConnectionProperties.SQLSplitTableName() and SQLFullTableName()
- now TSQLDBConnectionProperties.SQLAddIndex() will handle schema name and
will ensure that the generated identifier won't be too long
- added TSQLDBConnectionProperties.IsSQLKeyword() method for [7fbbd53966]
- added TSQLDBConnectionProperties.ExecuteInlined() overloaded methods
- added TSQLDBConnectionProperties.LoggedSQLMaxSize property to limit the
logged SQL content as requested by [0b6006e4f5]
- added published TSQLDBConnectionProperties.DatabaseNameSafe property, to
replace TSQLDBConnectionProperties.DatabaseName, triming any internal
TSQLDBConnectionProperties.Password value for safety
- ESQLDBException will now append the current SQL statement to its message,
if TSQLDBConnectionProperties.LogSQLStatementOnException is defined, as
requested by [ea07928ae9]
- added TSQLDBConnectionPropertiesThreadSafe.ForceOnlyOneSharedConnection
property to by-pass internal thread-pool (e.g. for embedded engines)
- enhanced TSQLDBConnectionPropertiesThreadSafe.ThreadSafeConnection speed
- introducing TSQLDBColumnCreate(DynArray) types used when creating columns,
allowing to create 32 bit integer fields (identified as ftUnknown) if needed
- declared all TSQLDBConnectionProperties.SQL*() methods as virtual
- TSQLDBConnectionProperties.SQLAddIndex() will now generate IF NOT EXISTS
statements, if the corresponding DBMS supports it (only SQLite3 AFAIK),
and handle MSSQL as expected (i.e. without 'dbo.' in INDEX name)
- additional aDescending parameter to TSQLDBConnectionProperties.SQLAddIndex()
- added TSQLDBConnectionProperties.OnBatchInsert property and the corresponding
MultipleValuesInsert() protected method to implement INSERT multiple VALUES
- added dFirebird, dNexusDB, dPostgreSQL and dDB2 kind of database in
TSQLDBDefinition, including associated SQL requests to retrieve metadata
- let TSQLDBConnectionProperties.SQLTableName() handle quoted table names
- added TSQLDBConnection.NewTableFromRows() method to dump a SQL statement
result into a new table of any database (may be used for replication)
- "rowCount": is added in TSQLDBStatement.FetchAllToJSON at the end of the
non-expanded JSON content, if needed - improves client parsing performance
- TSQLDBStatement.FetchAllToJSON will now add column names (in non-expanded
JSON format) if no data row is returned - just like TSQLRequest.Execute
- TSQLDBConnectionProperties.SQLSelectAll() now handles spaces in table names
- TSQLDBStatement.GetParamValueAsText() will truncate to a given number of
chars the returned text
- added ForceBlobAsNull property to ISQLDBStatement (used e.g. by SynDBExplorer)
- added RewindToFirst optional parameter to TSQLDBStatement.FetchAllAsJSON()
and FetchAllToJSON() methods (could be used e.g. for TQuery.FetchAllAsJSON)
- added new TSQLDBStatement.ExecutePreparedAndFetchAllAsJSON() method for
direct retrieval of JSON rows from a prepared statement
- added new TSQLDBStatement.PrepareInlined() methods (used by mORMotDB.pas)
- added direct result export into optimized binary content, via the new
TSQLDBStatement.FetchAllToBinary() method (used e.g. by TSQLDBProxyConnection)
- new TSQLDBProxyConnectionProperties, TSQLDBProxyConnection and
TSQLDBProxyStatement abstract classes for generic mean of connection
remoting (to be used e.g. for background thread or remote execution)
- replaced confusing TVarData by a new dedicated TSQLVar memory structure,
shared with mORMot and mORMotSQLite3 units (includes methods refactoring)
- TSQLDBFieldType is now defined in SynCommons, and used by TSQLVar and all
database-related process (i.e. in mORMot and SynDB units)
- added Bind(TSQLVar) overloaded method to ISQLDBStatement/TSQLDBStatement
- added optional BoundType parameter to BindNull() method since some providers
(e.g. OleDB during MULTI INSERT statements - see ticket [e8c211062e581])
expect the column type to be set in BoundType, even for NULL values
- TSQLDBStatement.Bind(const Params: array of const) will accept variant
values for BLOB, as requested by [64f7d840e1bf]
- added missing ColumnToSQLVar() method to ISQLDBRows interface
- exposed FetchAllToJSON method for ISQLDBRows interface
- added TSQLDBStatement.ColumnsToBinary() method
- method TSQLDBStatement.ColumnTypeNativeToDB() is now public, and will
recognize "uniqueidentifier" data type as ftUTF8
- added TSQLDBStatementWithParams.BindFromRows() method
- new TSQLDBProxyStatementRandomAccess class for in-memory browsing of data
retrieved via TSQLDBStatement.FetchAllToBinary()
- added TSQLDBConnectionPropertiesThreadSafe.ThreadingMode property instead
of limited boolean property ForceOnlyOneSharedConnection
- added generic ReplaceParamsByNames() function, which allows 'END;' at the
end of a statement to fulfill ticket [4a7da3c6a1]
- added TSQLDBConnection[Properties].OnProgress callback event handler
- now trim any spaces when retrieving database schema text values
- fixed ticket [4c68975022] about broken SQL statement when logging active
- fixed ticket [545fbe7579] about TSQLDBConnection.LastErrorMessage not reset
- fixed ticket [d465da9843] when guessing SQLite3 column type from its
affinity - see http://www.sqlite.org/datatype3.html
- exception during Commit should leave transaction state - see [ca035b8f0da]
- fixed potential GPF after TSQLDBConnectionProperties.ExecuteNoResult() method call
- fixed TSQLDBConnectionProperties.SQLGetField() returned value for dFirebird
- fixed TSQLDBConnectionProperties.ColumnTypeNativeToDB() for dFirebird
- fixed unnecessary limitation to 64 params for TSQLDBStatementWithParams
- TSQLDBStatement.Bind() will now handle a nil parameter to SQL null bound value
- TSQLDBStatement.ColumnToVariant() will now handle VariantStringAsWideString
- function ReplaceParamsByNames() won't generate any SQL keyword parameters
(e.g. :AS :OF :BY), to be compliant with Oracle OCI expectations
- added property RollbackOnDisconnect, set to TRUE by default, to ensure
any pending uncommitted transaction is roll-backed - see [dc64fe169b]
- added TSQLDBConnectionProperties.SharedTransaction() method to implement
nested transactions, as long as the same connection is re-used
- added TSQLDBConnectionProperties.GetIndexesAndSetFieldsColumnIndexed()
internal method, used by some overridden GetFields() implementations
- ensure a primary key column on SQlite3 is identified as indexed
- added support for getting stored procedure information: TSQLDBProcColumnDefine,
TSQLDBProcColumnDefineDynArray, TSQLDBConnectionProperties.GetProcedureParameters
and SQLGetParameter methods - by EMartin
- added Informix DBMS (dInformix), tested against Informix 11.70 by EMartin
- fixed misallocation of the parameter direction in GetProcedureParameters
- enhancement parsing stored procedure name MS SQL Server (e.g. dbo.procname;1) in SQLSplitProcedureName
- fixed typo SQL statement for getting Firebird stored procedure parameters in SQLGetParameter
- added GetProcedureNames and SQLGetProcedure for listing stored procedure names from current connection
- addes GetViewNames and SQLGetViewNames for listing view names from current connection
- bug fix getting stored procedure parameters on Firebird 3
- small refactoring in TSQLDBConnectionProperties.ExceptionIsAboutConnection
- added support for dInformix and dMSSQL in TSQLDBConnectionProperties.ExceptionIsAboutConnection
- added error codes in TSQLDBConnectionProperties.ExceptionIsAboutConnection for dOracle
- avoid GPI in TSQLDBConnection.GetLastErrorWasAboutConnection when fErrorMessage is empty
- added support for dMySQL in TSQLDBConnectionProperties.ExceptionIsAboutConnection
- added property stripSemicolon to strip last semicolon in query (default = true)
}
{$I Synopse.inc} // define HASINLINE CPU32 CPU64 OWNNORMTOUPPER
interface
/// if defined, a TQuery class will be defined to emulate the BDE TQuery class
{$define EMULATES_TQUERY}
/// if defined, a set of classes will be defined to implement remote access
{$define WITH_PROXY}
{$ifdef LVCL}
{$undef EMULATES_TQUERY}
{$endif}
uses
{$ifdef MSWINDOWS}
Windows,
{$else}
{$ifdef KYLIX3}
LibC,
Types,
SynKylix,
{$endif}
{$ifdef FPC}
SynFPCLinux,
{$endif}
{$endif}
{$ifdef FPC}
dynlibs,
{$endif}
{$ifdef ISDELPHIXE2}System.SysUtils,{$else}SysUtils,{$endif}
Classes,
{$ifndef LVCL}
Contnrs,
{$endif}
{$ifndef DELPHI5OROLDER}
Variants,
{$endif}
SynCommons,
SynTable, // for TSynTableStatement
SynLog;
{ -------------- TSQLDB* generic classes and types }
type
// NOTE: TSQLDBFieldType is defined in SynCommons.pas (used by TSQLVar)
/// an array of RawUTF8, for each existing column type
// - used e.g. by SQLCreate method
// - ftUnknown maps int32 field (e.g. boolean), ftNull maps RawUTF8 index # field,
// ftUTF8 maps RawUTF8 blob field, other types map their default kind
// - for UTF-8 text, ftUTF8 will define the BLOB field, whereas ftNull will
// expect to be formated with an expected field length in ColumnAttr
// - the RowID definition will expect the ORM to create an unique identifier,
// and will use the ftInt64 type definition for this
// and send it with the INSERT statement (some databases, like Oracle, do not
// support standard's IDENTITY attribute) - see http://troels.arvin.dk/db/rdbms
TSQLDBFieldTypeDefinition = array[TSQLDBFieldType] of RawUTF8;
/// the diverse type of bound parameters during a statement execution
// - will be paramIn by default, which is the case 90% of time
// - could be set to paramOut or paramInOut if must be refereshed after
// execution (for calling a stored procedure expecting such parameters)
TSQLDBParamInOutType =
(paramIn, paramOut, paramInOut);
/// used to define a field/column layout in a table schema
// - for TSQLDBConnectionProperties.SQLCreate to describe the new table
// - for TSQLDBConnectionProperties.GetFields to retrieve the table layout
TSQLDBColumnDefine = packed record
/// the Column name
ColumnName: RawUTF8;
/// the Column type, as retrieved from the database provider
// - returned as plain text by GetFields method, to be used e.g. by
// TSQLDBConnectionProperties.GetFieldDefinitions method
// - SQLCreate will check for this value to override the default type
ColumnTypeNative: RawUTF8;
/// the Column default width (in chars or bytes) of ftUTF8 or ftBlob
// - can be set to value <0 for CLOB or BLOB column type, i.e. for
// a value without any maximal length
ColumnLength: PtrInt;
/// the Column data precision
// - used e.g. for numerical values
ColumnPrecision: PtrInt;
/// the Column data scale
// - used e.g. for numerical values
// - may be -1 if the metadata SQL statement returned NULL
ColumnScale: PtrInt;
/// the Column type, as recognized by our SynDB classes
// - should not be ftUnknown nor ftNull
ColumnType: TSQLDBFieldType;
/// specify if column is indexed
ColumnIndexed: boolean;
end;
/// used to define the column layout of a table schema
// - e.g. for TSQLDBConnectionProperties.GetFields
TSQLDBColumnDefineDynArray = array of TSQLDBColumnDefine;
/// used to describe extended Index definition of a table schema
TSQLDBIndexDefine = packed record
/// name of the index
IndexName: RawUTF8;
/// description of the index type
// - for MS SQL possible values are:
// $ HEAP | CLUSTERED | NONCLUSTERED | XML |SPATIAL
// - for Oracle:
// $ NORMAL | BITMAP | FUNCTION-BASED NORMAL | FUNCTION-BASED BITMAP | DOMAIN
// see @http://docs.oracle.com/cd/B19306_01/server.102/b14237/statviews_1069.htm
TypeDesc: RawUTF8;
/// Expression for the subset of rows included in the filtered index
// - only set for MS SQL - not retrieved for other DB types yet
Filter: RawUTF8;
/// comma separated list of indexed column names, in order of their definition
KeyColumns: RawUTF8;
/// comma separaded list of a nonkey column added to the index by using the CREATE INDEX INCLUDE clause
// - only set for MS SQL - not retrieved for other DB types yet
IncludedColumns: RawUTF8;
/// if Index is unique
IsUnique: boolean;
/// if Index is part of a PRIMARY KEY constraint
// - only set for MS SQL - not retrieved for other DB types yet
IsPrimaryKey: boolean;
/// if Index is part of a UNIQUE constraint
// - only set for MS SQL - not retrieved for other DB types yet
IsUniqueConstraint: boolean;
end;
/// used to describe extended Index definition of a table schema
// - e.g. for TSQLDBConnectionProperties.GetIndexes
TSQLDBIndexDefineDynArray = array of TSQLDBIndexDefine;
/// used to define a parameter/column layout in a stored procedure schema
// - for TSQLDBConnectionProperties.GetProcedureParameters to retrieve the stored procedure parameters
// - can be extended according to https://msdn.microsoft.com/en-us/library/ms711701(v=vs.85).aspx
TSQLDBProcColumnDefine = packed record
/// the Column name
ColumnName: RawUTF8;
/// the Column type, as retrieved from the database provider
// - used e.g. by TSQLDBConnectionProperties.GetProcedureParameters method
ColumnTypeNative: RawUTF8;
/// the Column default width (in chars or bytes) of ftUTF8 or ftBlob
// - can be set to value <0 for CLOB or BLOB column type, i.e. for
// a value without any maximal length
ColumnLength: PtrInt;
/// the Column data precision
// - used e.g. for numerical values
ColumnPrecision: PtrInt;
/// the Column data scale
// - used e.g. for numerical values
// - may be -1 if the metadata SQL statement returned NULL
ColumnScale: PtrInt;
/// the Column type, as recognized by our SynDB classes
// - should not be ftUnknown nor ftNull
ColumnType: TSQLDBFieldType;
/// defines the procedure column as a parameter or a result set column
ColumnParamType: TSQLDBParamInOutType;
end;
/// used to define the parameter/column layout of a stored procedure schema
// - e.g. for TSQLDBConnectionProperties.GetProcedureParameters
TSQLDBProcColumnDefineDynArray = array of TSQLDBProcColumnDefine;
/// possible column retrieval patterns
// - used by TSQLDBColumnProperty.ColumnValueState
TSQLDBStatementGetCol = (colNone, colNull, colWrongType, colDataFilled, colDataTruncated);
/// used to define a field/column layout
// - for TSQLDBConnectionProperties.SQLCreate to describe the table
// - for T*Statement.Execute/Column*() methods to map the IRowSet content
TSQLDBColumnProperty = packed record
/// the Column name
ColumnName: RawUTF8;
/// a general purpose integer value
// - for SQLCreate: default width (in WideChars or Bytes) of ftUTF8 or ftBlob;
// if set to 0, a CLOB or BLOB column type will be created - note that
// UTF-8 encoding is expected when calculating the maximum column byte size
// for the CREATE TABLE statement (e.g. for Oracle 1333=4000/3 is used)
// - for TOleDBStatement: the offset of this column in the IRowSet data,
// starting with a DBSTATUSENUM, the data, then its length (for inlined
// sftUTF8 and sftBlob only)
// - for TSQLDBOracleStatement: contains an offset to this column values
// inside fRowBuffer[] internal buffer
// - for TSQLDBDatasetStatement: maps TField pointer value
ColumnAttr: PtrUInt;
/// the Column type, used for storage
// - for SQLCreate: should not be ftUnknown nor ftNull
// - for TOleDBStatement: should not be ftUnknown
// - for SynDBOracle: never ftUnknown, may be ftNull (for SQLT_RSET)
ColumnType: TSQLDBFieldType;
/// set if the Column must exists (i.e. should not be null)
ColumnNonNullable: boolean;
/// set if the Column shall have unique value (add the corresponding constraint)
ColumnUnique: boolean;
/// set if the Column data is inlined within the main rows buffer
// - for TOleDBStatement: set if column was NOT defined as DBTYPE_BYREF
// which is the most common case, when column data < 4 KB
// - for TSQLDBOracleStatement: FALSE if column is an array of
// POCILobLocator (SQLT_CLOB/SQLT_BLOB) or POCIStmt (SQLT_RSET)
// - for TSQLDBODBCStatement: FALSE if bigger than 255 WideChar (ftUTF8) or
// 255 bytes (ftBlob)
ColumnValueInlined: boolean;
/// expected column data size
// - for TSQLDBOracleStatement/TOleDBStatement/TODBCStatement: used to store
// one column size (in bytes)
ColumnValueDBSize: cardinal;
/// optional character set encoding for ftUTF8 columns
// - for SQLT_STR/SQLT_CLOB (SynDBOracle): equals to the OCI char set
ColumnValueDBCharSet: integer;
/// internal DB column data type
// - for TSQLDBOracleStatement: used to store the DefineByPos() TypeCode,
// can be SQLT_STR/SQLT_CLOB, SQLT_FLT, SQLT_INT, SQLT_DAT, SQLT_BLOB,
// SQLT_BIN and SQLT_RSET
// - for TSQLDBODBCStatement: used to store the DataType as returned
// by ODBC.DescribeColW() - use private ODBC_TYPE_TO[ColumnType] to
// retrieve the marshalled type used during column retrieval
// - for TSQLDBFirebirdStatement: used to store XSQLVAR.sqltype
// - for TSQLDBDatasetStatement: indicates the TField class type, i.e.
// 0=TField, 1=TLargeIntField, 2=TWideStringField
ColumnValueDBType: smallint;
/// driver-specific encoding information
// - for SynDBOracle: used to store the ftUTF8 column encoding, i.e. for
// SQLT_CLOB, equals either to SQLCS_NCHAR or SQLCS_IMPLICIT
ColumnValueDBForm: byte;
/// may contain the current status of the column value
// - for SynDBODBC: state of the latest SQLGetData() call
ColumnDataState: TSQLDBStatementGetCol;
/// may contain the current column size for not FIXEDLENGTH_SQLDBFIELDTYPE
// - for SynDBODBC: size (in bytes) in corresponding fColData[]
// - TSQLDBProxyStatement: the actual maximum column size
ColumnDataSize: integer;
end;
PSQLDBColumnProperty = ^TSQLDBColumnProperty;
/// used to define a table/field column layout
TSQLDBColumnPropertyDynArray = array of TSQLDBColumnProperty;
/// used to define how a column to be created
TSQLDBColumnCreate = record
/// the data type
// - here, ftUnknown is used for Int32 values, ftInt64 for Int64 values,
// as expected by TSQLDBFieldTypeDefinition
DBType: TSQLDBFieldType;
/// the column name
Name: RawUTF8;
/// the width, e.g. for VARCHAR() types
Width: cardinal;
/// if the column should be unique
Unique: boolean;
/// if the column should be non null
NonNullable: boolean;
/// if the column is the ID primary key
PrimaryKey: boolean;
end;
/// used to define how a table is to be created
TSQLDBColumnCreateDynArray = array of TSQLDBColumnCreate;
/// identify a CRUD mode of a statement
TSQLDBStatementCRUD = (
cCreate, cRead, cUpdate, cDelete);
/// identify the CRUD modes of a statement
// - used e.g. for batch send abilities of a DB engine
TSQLDBStatementCRUDs = set of TSQLDBStatementCRUD;
/// the known database definitions
// - will be used e.g. for TSQLDBConnectionProperties.SQLFieldCreate(), or
// for OleDB/ODBC/ZDBC tuning according to the connected database engine
TSQLDBDefinition = (dUnknown, dDefault, dOracle, dMSSQL, dJet, dMySQL,
dSQLite, dFirebird, dNexusDB, dPostgreSQL, dDB2, dInformix);
/// set of the available database definitions
TSQLDBDefinitions = set of TSQLDBDefinition;
{$M+}
TSQLDBStatement = class;
{$M-}
{$ifndef LVCL}
{$ifndef DELPHI5OROLDER}
/// a custom variant type used to have direct access to a result row content
// - use ISQLDBRows.RowData method to retrieve such a Variant
TSQLDBRowVariantType = class(TSynInvokeableVariantType)
protected
procedure IntGet(var Dest: TVarData; const V: TVarData; Name: PAnsiChar); override;
procedure IntSet(const V, Value: TVarData; Name: PAnsiChar); override;
end;
{$endif}
{$endif}
/// generic interface to access a SQL query result rows
// - not all TSQLDBStatement methods are available, but only those to retrieve
// data from a statement result: the purpose of this interface is to make
// easy access to result rows, not provide all available features - therefore
// you only have access to the Step() and Column*() methods
ISQLDBRows = interface
['{11291095-9C15-4984-9118-974F1926DB9F}']
/// After a prepared statement has been prepared returning a ISQLDBRows
// interface, this method must be called one or more times to evaluate it
// - you shall call this method before calling any Column*() methods
// - return TRUE on success, with data ready to be retrieved by Column*()
// - return FALSE if no more row is available (e.g. if the SQL statement
// is not a SELECT but an UPDATE or INSERT command)
// - access the first or next row of data from the SQL Statement result:
// if SeekFirst is TRUE, will put the cursor on the first row of results,
// otherwise, it will fetch one row of data, to be called within a loop
// - should raise an Exception on any error
// - typical use may be:
// ! var Customer: Variant;
// ! begin
// ! with Props.Execute( 'select * from Sales.Customer where AccountNumber like ?', ['AW000001%'],@Customer) do
// ! while Step do // loop through all matching data rows
// ! assert(Copy(Customer.AccountNumber,1,8)='AW000001');
// ! end;
function Step(SeekFirst: boolean=false): boolean;
/// the column/field count of the current Row
function ColumnCount: integer;
/// the Column name of the current Row
// - Columns numeration (i.e. Col value) starts with 0
// - it's up to the implementation to ensure than all column names are unique
function ColumnName(Col: integer): RawUTF8;
/// returns the Column index of a given Column name
// - Columns numeration (i.e. Col value) starts with 0
// - returns -1 if the Column name is not found (via case insensitive search)
function ColumnIndex(const aColumnName: RawUTF8): integer;
/// the Column type of the current Row
// - FieldSize can be set to store the size in chars of a ftUTF8 column
// (0 means BLOB kind of TEXT column)
function ColumnType(Col: integer; FieldSize: PInteger=nil): TSQLDBFieldType;
/// returns TRUE if the column contains NULL
function ColumnNull(Col: integer): boolean;
/// return a Column integer value of the current Row, first Col is 0
function ColumnInt(Col: integer): Int64; overload;
/// return a Column floating point value of the current Row, first Col is 0
function ColumnDouble(Col: integer): double; overload;
/// return a Column floating point value of the current Row, first Col is 0
function ColumnDateTime(Col: integer): TDateTime; overload;
/// return a column date and time value of the current Row, first Col is 0
function ColumnTimestamp(Col: integer): TTimeLog; overload;
/// return a Column currency value of the current Row, first Col is 0
function ColumnCurrency(Col: integer): currency; overload;
/// return a Column UTF-8 encoded text value of the current Row, first Col is 0
function ColumnUTF8(Col: integer): RawUTF8; overload;
/// return a Column text value as generic VCL string of the current Row, first Col is 0
function ColumnString(Col: integer): string; overload;
/// return a Column as a blob value of the current Row, first Col is 0
function ColumnBlob(Col: integer): RawByteString; overload;
/// return a Column as a blob value of the current Row, first Col is 0
function ColumnBlobBytes(Col: integer): TBytes; overload;
/// return a Column as a TSQLVar value, first Col is 0
// - the specified Temp variable will be used for temporary storage of
// svtUTF8/svtBlob values
procedure ColumnToSQLVar(Col: Integer; var Value: TSQLVar;
var Temp: RawByteString);
{$ifndef LVCL}
/// return a Column as a variant
// - a ftUTF8 TEXT content will be mapped into a generic WideString variant
// for pre-Unicode version of Delphi, and a generic UnicodeString (=string)
// since Delphi 2009: you may not loose any data during charset conversion
// - a ftBlob BLOB content will be mapped into a TBlobData AnsiString variant
function ColumnVariant(Col: integer): Variant; overload;
/// return a Column as a variant, first Col is 0
// - this default implementation will call Column*() method above
// - a ftUTF8 TEXT content will be mapped into a generic WideString variant
// for pre-Unicode version of Delphi, and a generic UnicodeString (=string)
// since Delphi 2009: you may not loose any data during charset conversion
// - a ftBlob BLOB content will be mapped into a TBlobData AnsiString variant
function ColumnToVariant(Col: integer; var Value: Variant): TSQLDBFieldType; overload;
{$endif}
/// return a special CURSOR Column content as a SynDB result set
// - Cursors are not handled internally by mORMot, but some databases (e.g.
// Oracle) usually use such structures to get data from stored procedures
// - such columns are mapped as ftNull internally - so this method is the only
// one giving access to the data rows
// - see also BoundCursor() if you want to access a CURSOR out parameter
function ColumnCursor(Col: integer): ISQLDBRows; overload;
/// return a Column integer value of the current Row, from a supplied column name
function ColumnInt(const ColName: RawUTF8): Int64; overload;
/// return a Column floating point value of the current Row, from a supplied column name
function ColumnDouble(const ColName: RawUTF8): double; overload;
/// return a Column floating point value of the current Row, from a supplied column name
function ColumnDateTime(const ColName: RawUTF8): TDateTime; overload;
/// return a column date and time value of the current Row, from a supplied column name
function ColumnTimestamp(const ColName: RawUTF8): TTimeLog; overload;
/// return a Column currency value of the current Row, from a supplied column name
function ColumnCurrency(const ColName: RawUTF8): currency; overload;
/// return a Column UTF-8 encoded text value of the current Row, from a supplied column name
function ColumnUTF8(const ColName: RawUTF8): RawUTF8; overload;
/// return a Column text value as generic VCL string of the current Row, from a supplied column name
function ColumnString(const ColName: RawUTF8): string; overload;
/// return a Column as a blob value of the current Row, from a supplied column name
function ColumnBlob(const ColName: RawUTF8): RawByteString; overload;
/// return a Column as a blob value of the current Row, from a supplied column name
function ColumnBlobBytes(const ColName: RawUTF8): TBytes; overload;
{$ifndef LVCL}
/// return a Column as a variant, from a supplied column name
function ColumnVariant(const ColName: RawUTF8): Variant; overload;
/// return a Column as a variant, from a supplied column name
// - since a property getter can't be an overloaded method, we define one
// for the Column[] property
function GetColumnVariant(const ColName: RawUTF8): Variant;
/// return a special CURSOR Column content as a SynDB result set
// - Cursors are not handled internally by mORMot, but some databases (e.g.
// Oracle) usually use such structures to get data from strored procedures
// - such columns are mapped as ftNull internally - so this method is the only
// one giving access to the data rows
function ColumnCursor(const ColName: RawUTF8): ISQLDBRows; overload;
/// return a Column as a variant
// - this default property can be used to write simple code like this:
// ! procedure WriteFamily(const aName: RawUTF8);
// ! var I: ISQLDBRows;
// ! begin
// ! I := MyConnProps.Execute('select * from table where name=?',[aName]);
// ! while I.Step do
// ! writeln(I['FirstName'],' ',DateToStr(I['BirthDate']));
// ! end;
// - of course, using a variant and a column name will be a bit slower than
// direct access via the Column*() dedicated methods, but resulting code
// is fast in practice
property Column[const ColName: RawUTF8]: Variant read GetColumnVariant; default;
{$ifndef DELPHI5OROLDER}
/// create a TSQLDBRowVariantType able to access any field content via late binding
// - i.e. you can use Data.Name to access the 'Name' column of the current row
// - this Variant will point to the corresponding TSQLDBStatement instance,
// so it's not necessary to retrieve its value for each row; but once the
// associated ISQLDBRows instance is released, you won't be able to access
// its data - use RowDocVariant instead
// - typical use is:
// ! var Row: Variant;
// ! (...)
// ! with MyConnProps.Execute('select * from table where name=?',[aName]) do begin
// ! Row := RowData;
// ! while Step do
// ! writeln(Row.FirstName,Row.BirthDate);
// ! end;
function RowData: Variant;
/// create a TDocVariant custom variant containing all columns values
// - will create a "fast" TDocVariant object instance with all fields
procedure RowDocVariant(out aDocument: variant;
aOptions: TDocVariantOptions=JSON_OPTIONS_FAST);
{$endif DELPHI5OROLDER}
{$endif LVCL}
/// return the associated statement instance
function Instance: TSQLDBStatement;
// return all rows content as a JSON string
// - JSON data is retrieved with UTF-8 encoding
// - if Expanded is true, JSON data is an array of objects, for direct use
// with any Ajax or .NET client:
// & [ {"col1":val11,"col2":"val12"},{"col1":val21,... ]
// - if Expanded is false, JSON data is serialized (used in TSQLTableJSON)
// & { "FieldCount":1,"Values":["col1","col2",val11,"val12",val21,..] }
// - BLOB field value is saved as Base64, in the '"\uFFF0base64encodedbinary"'
// format and contains true BLOB data
// - you can go back to the first row of data before creating the JSON, if
// RewindToFirst is TRUE (could be used e.g. for TQuery.FetchAllAsJSON)
// - if ReturnedRowCount points to an integer variable, it will be filled with
// the number of row data returned (excluding field names)
// - similar to corresponding TSQLRequest.Execute method in SynSQLite3 unit
function FetchAllAsJSON(Expanded: boolean; ReturnedRowCount: PPtrInt=nil;
RewindToFirst: boolean=false): RawUTF8;
// append all rows content as a JSON stream
// - JSON data is added to the supplied TStream, with UTF-8 encoding
// - if Expanded is true, JSON data is an array of objects, for direct use
// with any Ajax or .NET client:
// & [ {"col1":val11,"col2":"val12"},{"col1":val21,... ]
// - if Expanded is false, JSON data is serialized (used in TSQLTableJSON)
// & { "FieldCount":1,"Values":["col1","col2",val11,"val12",val21,..] }
// - BLOB field value is saved as Base64, in the '"\uFFF0base64encodedbinary"'
// format and contains true BLOB data
// - similar to corresponding TSQLRequest.Execute method in SynSQLite3 unit
// - you can go back to the first row of data before creating the JSON, if
// RewindToFirst is TRUE (could be used e.g. for TQuery.FetchAllAsJSON)
// - returns the number of row data returned (excluding field names)
function FetchAllToJSON(JSON: TStream; Expanded: boolean;
RewindToFirst: boolean=false): PtrInt;
/// append all rows content as binary stream
// - will save the column types and name, then every data row in optimized
// binary format (faster and smaller than JSON)
// - you can specify a LIMIT for the data extent (default 0 meaning all data)
// - generates the format expected by TSQLDBProxyStatement
function FetchAllToBinary(Dest: TStream; MaxRowCount: cardinal=0;
DataRowPosition: PCardinalDynArray=nil): cardinal;
end;
/// generic interface to bind to prepared SQL query
// - inherits from ISQLDBRows, so gives access to the result columns data
// - not all TSQLDBStatement methods are available, but only those to bind
// parameters and retrieve data after execution
// - reference counting mechanism of this interface will feature statement
// cache (if available) for NewThreadSafeStatementPrepared() or PrepareInlined()
ISQLDBStatement = interface(ISQLDBRows)
['{EC27B81C-BD57-47D4-9711-ACFA27B583D7}']
/// bind a NULL value to a parameter
// - the leftmost SQL parameter has an index of 1
// - some providers (e.g. OleDB during MULTI INSERT statements) expect the
// proper column type to be set in BoundType, even for NULL values
procedure BindNull(Param: Integer; IO: TSQLDBParamInOutType=paramIn;
BoundType: TSQLDBFieldType=ftNull);
/// bind an integer value to a parameter
// - the leftmost SQL parameter has an index of 1
procedure Bind(Param: Integer; Value: Int64;
IO: TSQLDBParamInOutType=paramIn); overload;
/// bind a double value to a parameter
// - the leftmost SQL parameter has an index of 1
procedure Bind(Param: Integer; Value: double;
IO: TSQLDBParamInOutType=paramIn); overload;
/// bind a TDateTime value to a parameter
// - the leftmost SQL parameter has an index of 1
procedure BindDateTime(Param: Integer; Value: TDateTime;
IO: TSQLDBParamInOutType=paramIn); overload;
/// bind a currency value to a parameter
// - the leftmost SQL parameter has an index of 1
procedure BindCurrency(Param: Integer; Value: currency;
IO: TSQLDBParamInOutType=paramIn); overload;
/// bind a UTF-8 encoded string to a parameter
// - the leftmost SQL parameter has an index of 1
procedure BindTextU(Param: Integer; const Value: RawUTF8;
IO: TSQLDBParamInOutType=paramIn); overload;
/// bind a UTF-8 encoded buffer text (#0 ended) to a parameter
// - the leftmost SQL parameter has an index of 1
procedure BindTextP(Param: Integer; Value: PUTF8Char;
IO: TSQLDBParamInOutType=paramIn); overload;
/// bind a UTF-8 encoded string to a parameter
// - the leftmost SQL parameter has an index of 1
procedure BindTextS(Param: Integer; const Value: string;
IO: TSQLDBParamInOutType=paramIn); overload;
/// bind a UTF-8 encoded string to a parameter
// - the leftmost SQL parameter has an index of 1
procedure BindTextW(Param: Integer; const Value: WideString;
IO: TSQLDBParamInOutType=paramIn); overload;
/// bind a Blob buffer to a parameter
// - the leftmost SQL parameter has an index of 1
procedure BindBlob(Param: Integer; Data: pointer; Size: integer;
IO: TSQLDBParamInOutType=paramIn); overload;
/// bind a Blob buffer to a parameter
// - the leftmost SQL parameter has an index of 1
procedure BindBlob(Param: Integer; const Data: RawByteString;
IO: TSQLDBParamInOutType=paramIn); overload;
/// bind a Variant value to a parameter
// - the leftmost SQL parameter has an index of 1
// - will call all virtual Bind*() methods from the Data type
// - if DataIsBlob is TRUE, will call BindBlob(RawByteString(Data)) instead
// of BindTextW(WideString(Variant)) - used e.g. by TQuery.AsBlob/AsBytes
procedure BindVariant(Param: Integer; const Data: Variant; DataIsBlob: boolean;
IO: TSQLDBParamInOutType=paramIn);
/// bind one TSQLVar value
// - the leftmost SQL parameter has an index of 1
procedure Bind(Param: Integer; const Data: TSQLVar;
IO: TSQLDBParamInOutType=paramIn); overload;
/// bind one RawUTF8 encoded value
// - the leftmost SQL parameter has an index of 1
// - the value should match the BindArray() format, i.e. be stored as in SQL
// (i.e. number, 'quoted string', 'YYYY-MM-DD hh:mm:ss', null)
procedure Bind(Param: Integer; ParamType: TSQLDBFieldType; const Value: RawUTF8;
ValueAlreadyUnquoted: boolean; IO: TSQLDBParamInOutType=paramIn); overload;
/// bind an array of const values
// - parameters marked as ? should be specified as method parameter in Params[]
// - BLOB parameters can be bound with this method, when set after encoding
// via BinToBase64WithMagic() call
// - TDateTime parameters can be bound with this method, when encoded via
// a DateToSQL() or DateTimeToSQL() call
procedure Bind(const Params: array of const;
IO: TSQLDBParamInOutType=paramIn); overload;
/// bind an array of fields from an existing SQL statement
// - can be used e.g. after ColumnsToSQLInsert() method call for fast data
// conversion between tables
procedure BindFromRows(const Fields: TSQLDBFieldTypeDynArray;
Rows: TSQLDBStatement);
/// bind a special CURSOR parameter to be returned as a SynDB result set
// - Cursors are not handled internally by mORMot, but some databases (e.g.
// Oracle) usually use such structures to get data from strored procedures
// - such parameters are mapped as ftUnknown
// - use BoundCursor() method to retrieve the corresponding ISQLDBRows after
// execution of the statement
procedure BindCursor(Param: integer);
/// return a special CURSOR parameter content as a SynDB result set
// - this method is not about a column, but a parameter defined with
// BindCursor() before method execution
// - Cursors are not handled internally by mORMot, but some databases (e.g.
// Oracle) usually use such structures to get data from strored procedures
// - this method allow direct access to the data rows after execution
function BoundCursor(Param: Integer): ISQLDBRows;
/// bind an array of values to a parameter
// - the leftmost SQL parameter has an index of 1
// - values are stored as in SQL (i.e. number, 'quoted string',
// 'YYYY-MM-DD hh:mm:ss', null)
// - this default implementation will raise an exception if the engine
// does not support array binding
procedure BindArray(Param: Integer; ParamType: TSQLDBFieldType;
const Values: TRawUTF8DynArray; ValuesCount: integer); overload;
/// bind an array of integer values to a parameter
// - the leftmost SQL parameter has an index of 1
// - this default implementation will raise an exception if the engine
// does not support array binding
procedure BindArray(Param: Integer; const Values: array of Int64); overload;
/// bind an array of double values to a parameter
// - the leftmost SQL parameter has an index of 1
// - this default implementation will raise an exception if the engine
// does not support array binding
procedure BindArray(Param: Integer; const Values: array of double); overload;
/// bind an array of TDateTime values to a parameter
// - the leftmost SQL parameter has an index of 1
// - values are stored as in SQL (i.e. 'YYYY-MM-DD hh:mm:ss')
// - this default implementation will raise an exception if the engine
// does not support array binding
procedure BindArrayDateTime(Param: Integer; const Values: array of TDateTime);
/// bind an array of currency values to a parameter
// - the leftmost SQL parameter has an index of 1
// - this default implementation will raise an exception if the engine
// does not support array binding
procedure BindArrayCurrency(Param: Integer; const Values: array of currency);
/// bind an array of RawUTF8 values to a parameter
// - the leftmost SQL parameter has an index of 1
// - values are stored as in SQL (i.e. 'quoted string')
// - this default implementation will raise an exception if the engine
// does not support array binding
procedure BindArray(Param: Integer; const Values: array of RawUTF8); overload;
{$ifndef LVCL}
/// retrieve the parameter content, after SQL execution
// - the leftmost SQL parameter has an index of 1
// - to be used e.g. with stored procedures:
// ! query := 'BEGIN TEST_PKG.DUMMY(?, ?, ?, ?, ?); END;';
// ! stmt := Props.NewThreadSafeStatementPrepared(query, false);
// ! stmt.Bind(1, in1, paramIn);
// ! stmt.BindTextU(2, in2, paramIn);
// ! stmt.BindTextU(3, in3, paramIn);
// ! stmt.BindTextS(4, '', paramOut); // to be retrieved with out1: string
// ! stmt.Bind(5, 0, paramOut); // to be retrieved with out2: integer
// ! stmt.ExecutePrepared;
// ! stmt.ParamToVariant(4, out1, true);
// ! stmt.ParamToVariant(5, out2, true);
// - the parameter should have been bound with IO=paramOut or IO=paramInOut
// if CheckIsOutParameter is TRUE
function ParamToVariant(Param: Integer; var Value: Variant;
CheckIsOutParameter: boolean=true): TSQLDBFieldType;
{$endif}
/// execute a prepared SQL statement
// - parameters marked as ? should have been already bound with Bind*() functions
// - should raise an Exception on any error
// - after execution, you can access any returned data via ISQLDBRows methods
procedure ExecutePrepared;
// execute a prepared SQL statement and return all rows content as a JSON string
// - JSON data is retrieved with UTF-8 encoding
// - if Expanded is true, JSON data is an array of objects, for direct use
// with any Ajax or .NET client:
// & [ {"col1":val11,"col2":"val12"},{"col1":val21,... ]
// - if Expanded is false, JSON data is serialized (used in TSQLTableJSON)
// & { "FieldCount":1,"Values":["col1","col2",val11,"val12",val21,..] }
// - BLOB field value is saved as Base64, in the '"\uFFF0base64encodedbinary"'
// format and contains true BLOB data
procedure ExecutePreparedAndFetchAllAsJSON(Expanded: boolean; out JSON: RawUTF8);
function GetForceBlobAsNull: boolean;
procedure SetForceBlobAsNull(value: boolean);
/// if set, any BLOB field won't be retrieved, and forced to be null
// - this may be used to speed up fetching the results for SQL requests
// with * statements
property ForceBlobAsNull: boolean read GetForceBlobAsNull write SetForceBlobAsNull;
function GetForceDateWithMS: boolean;
procedure SetForceDateWithMS(value: boolean);
/// if set, any ftDate field will contain the milliseconds information
// when serialized into ISO-8601 text
// - this setting is private to each statement, since may vary depending
// on data definition (e.g. ORM TDateTime/TDateTimeMS)
property ForceDateWithMS: boolean read GetForceDateWithMS write SetForceDateWithMS;
/// gets a number of updates made by latest executed statement
function UpdateCount: Integer;
end;
{$ifdef WITH_PROXY}
/// proxy commands implemented by TSQLDBProxyConnectionProperties.Process()
// - method signature expect "const Input" and "var Output" arguments
// - Input is not used for cConnect, cDisconnect, cGetForeignKeys,
// cTryStartTransaction, cCommit, cRollback and cServerTimestamp
// - Input is the TSQLDBProxyConnectionProperties instance for cInitialize
// - Input is the RawUTF8 table name for most cGet* metadata commands
// - Input is the SQL statement and associated bound parameters for cExecute,
// cExecuteToBinary, cExecuteToJSON, and cExecuteToExpandedJSON, encoded as
// TSQLDBProxyConnectionCommandExecute record
// - Output is not used for cConnect, cDisconnect, cCommit, cRollback and cExecute
// - Output is TSQLDBDefinition (i.e. DBMS type) for cInitialize
// - Output is TTimeLog for cServerTimestamp
// - Output is boolean for cTryStartTransaction
// - Output is TSQLDBColumnDefineDynArray for cGetFields
// - Output is TSQLDBIndexDefineDynArray for cGetIndexes
// - Output is TSynNameValue (fForeignKeys) for cGetForeignKeys
// - Output is TRawUTF8DynArray for cGetTableNames
// - Output is RawByteString result data for cExecuteToBinary
// - Output is UpdateCount: integer text for cExecute