Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Comment: |
|
---|---|
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
f641049835f641bb3c24132c552346b7 |
User & Date: | ab 2012-07-26 09:32:19 |
2012-07-26
| ||
09:33 | performance benchmark now includes either OFF, either FULL synchronous mode for SQlite3 engine on file check-in: 3ccbcc1e29 user: ab tags: trunk | |
09:32 |
| |
2012-07-25
| ||
15:51 |
| |
Changes to SQLite3/SQLite3Commons.pas.
605 606 607 608 609 610 611 612 613 614 615 616 617 618 .... 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 .... 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 .... 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 ..... 11145 11146 11147 11148 11149 11150 11151 11152 11153 11154 11155 11156 11157 11158 11159 11160 11161 11162 11163 ..... 11166 11167 11168 11169 11170 11171 11172 11173 11174 11175 11176 11177 11178 11179 11180 11181 11182 11183 11184 11185 11186 11187 11188 11189 11190 11191 ..... 11356 11357 11358 11359 11360 11361 11362 11363 11364 11365 11366 11367 11368 11369 11370 ..... 13262 13263 13264 13265 13266 13267 13268 13269 13270 13271 13272 13273 13274 13275 13276 ..... 13278 13279 13280 13281 13282 13283 13284 13285 13286 13287 13288 13289 13290 13291 13292 13293 13294 13295 ..... 14500 14501 14502 14503 14504 14505 14506 14507 14508 14509 14510 14511 14512 14513 14514 ..... 19183 19184 19185 19186 19187 19188 19189 19190 19191 19192 19193 19194 19195 19196 19197 |
Weak interface assignment (with small performance penalty and memory use), corresponding to the ARC's Zeroing Weak pointers model - CopyObject() procedure now handle TCollection kind of object not only as sub properties - introducing TInterfacedCollection dedicated class, properly handling collection item creation on the Server side, with interface-based services: all contract operations shall use it instead of TCollection - added TSQLTable.FieldLengthMax() and ExpandAsSynUnicode() methods - added BlobToBytes() function and TSQLTable.GetBytes/GetStream methods - added virtual TSQLRestServer.FlushInternalDBCache method and dedicated TSQLRestServerStaticInMemoryExternal class, to properly handle external DB modification for virtual tables (i.e. flush SQL/JSON cache as expected) - added TSQLRestServerStatic.InternalBatchStart / InternalBatchStop methods to handle fast grouped sending to remote database engine (e.g. Oracle ................................................................................ /// save the table values in JSON format // - JSON data is added to TStream, with UTF-8 encoding // - if Expand 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 Expand is false, JSON data is serialized (used in TSQLTableJSON) // & { "FieldCount":1,"Values":["col1","col2",val11,"val12",val21,..] } // - RowFirst and RowLast can be used to ask for a specified row extent // of the returned data (by default, all rows are retrieved) procedure GetJSONValues(JSON: TStream; Expand: boolean; RowFirst: integer=0; RowLast: integer=0); overload; /// same as above, but returning result into a RawUTF8 function GetJSONValues(Expand: boolean): RawUTF8; overload; /// save the table in CSV format ................................................................................ /// get the FIRST field value of the FIRST row, from a JSON content // - e.g. usefull to get an ID without converting a JSON content into a TSQLTableJSON function UnJSONFirstField(var P: PUTF8Char): RawUTF8; /// returns TRUE if the JSON content is in expanded format // - i.e. as plain [{"ID":10,"FirstName":"John","LastName":"Smith"}...] // - i.e. not as '{"FieldCount":3,"Values":["ID","FirstName","LastName",...']} function IsNotAjaxJSON(P: PUTF8Char): Boolean; /// get the number of rows stored in the not-expanded JSON content function GetRowCountNotExpanded(P: PUTF8Char; FieldCount: integer; var RowCount: integer): PUTF8Char; /// go to the end of a field name in a JSON '"FieldName":Value' pair // - returns nil if P was not formatted as expected ................................................................................ (** return the UTF-8 encoded JSON objects for the values contained in the current published fields of a TSQLRecord child - only simple fields (i.e. not TSQLRawBlob/TSQLRecordMany) are retrieved: BLOB fields are ignored (use direct access via dedicated methods instead) - if Expand is true, JSON data is an object, for direct use with any Ajax or .NET client: ! {"col1":val11,"col2":"val12"} - if Expand is false, JSON data is serialized (as used in TSQLTableJSON) ! { "FieldCount":1,"Values":["col1","col2",val11,"val12",val21,..] } - if withID is true, then the first ID field value is included *) procedure GetJSONValues(JSON: TStream; Expand: boolean; withID: boolean; Occasion: TSQLOccasion); overload; /// same as above, but returning result into a RawUTF8 // - if UsingStream is not set, it will use a temporary THeapMemoryStream instance function GetJSONValues(Expand: boolean; withID: boolean; Occasion: TSQLOccasion; UsingStream: TCustomMemoryStream=nil): RawUTF8; overload; ................................................................................ inc(P); until false; end; end; function UnJSONFirstField(var P: PUTF8Char): RawUTF8; // expand=true: [ {"col1":val11} ] -> val11 // expand=false: { "FieldCount":1,"Values":["col1",val11] } -> vall11 begin result := ''; if P=nil then exit; if Expect(P,'{"FieldCount":') then begin // not expanded format if GetJSONIntegerVar(P)<>1 then exit; // wrong field count while P^<>'[' do if P^=#0 then exit else inc(P); // go to ["col1" inc(P); // go to "col1" end else begin // expanded format ................................................................................ end; GetJSONField(P,P); // ignore field name result := GetJSONField(P,P); // get field value end; function IsNotAjaxJSON(P: PUTF8Char): Boolean; begin result := Expect(P,'{"FieldCount":'); end; function IsNotExpanded(var P: PUTF8Char; var FieldCount: integer): boolean; begin if not IsNotAjaxJSON(P) then begin result := false; exit; end; inc(P,14); FieldCount := GetJSONIntegerVar(P); result := (FieldCount<>0) and Expect(P,',"Values":['); end; function GetRowCountNotExpanded(P: PUTF8Char; FieldCount: integer; var RowCount: integer): PUTF8Char; begin RowCount := 0; result := P; // no data at all of unexpected end repeat ................................................................................ result := false; // error on parsing if (self=nil) or (Buffer=nil) then exit; // go to start of object P := GotoNextNotSpace(Buffer); if IsNotExpanded(P,fFieldCount) then begin // A. Not Expanded format (* {"FieldCount":9,"Values":["ID","Int","Test","Unicode","Ansi","ValFloat","ValWord", "ValDate","Next",0,0,"abcde+�ef+�+�","abcde+�ef+�+�","abcde+�ef+�+�", 3.14159265300000E+0000,1203,"2009-03-10T21:19:36",0,..]} *) // 1. get RowCount and DataLen DataLen := GetRowCountNotExpanded(P,FieldCount,fRowCount)-P; // also check P^ format if DataLen=0 then begin fRowCount := 0; exit; ................................................................................ Freemem(tmp); end; end; end; procedure TSQLRecord.FillFrom(P: PUTF8Char); (* two possible formats = first not expanded, 2nd is expanded (most usefull) {"FieldCount":9,"Values":["ID","Int","Test","Unicode","Ansi","ValFloat","ValWord", "ValDate","Next",0,0,"abcde+�ef+�+�","abcde+�ef+�+�","abcde+�ef+�+�", 3.14159265300000E+0000,1203,"2009-03-10T21:19:36",0]} {"ID":0,"Int":0,"Test":"abcde+�ef+�+�","Unicode":"abcde+�ef+�+�","Ansi": "abcde+�ef+�+�","ValFloat": 3.14159265300000E+0000,"ValWord":1203, "ValDate":"2009-03-10T21:19:36","Next":0} *) var F: array[0..MAX_SQLFIELDS-1] of PUTF8Char; // store field/property names i, n: integer; ................................................................................ Value: PUTF8Char; begin // go to start of object if P=nil then exit; while P^<>'{' do if P^=#0 then exit else inc(P); if Expect(P,'{"FieldCount":') then begin // not expanded format n := GetJSONIntegerVar(P)-1; if (cardinal(n)>high(F)) or not Expect(P,',"Values":[') then exit; for i := 0 to n do F[i] := GetJSONField(P,P); // get field names for i := 0 to n do begin Prop := F[i]; // share shortstring on stack with code below FillValue(Prop,GetJSONField(P,P)); // set properties from values end; ................................................................................ procedure TSQLModel.SetTableProps(aTable: TSQLRecordClass; aIndex: integer; Last, VirtualsRemain: boolean); var f, R: integer; Props: TSQLRecordProperties; PT: PTypeInfo; begin Props := aTable.RecordProps; if not VirtualsRemain then Props.Kind := rSQLite3; // reset to internal table at model creation if Props.Model=nil then begin Props.Model := self; Props.ModelTableIndex := aIndex; end; TableProps[aIndex] := Props; fTablesName[aIndex] := Props.SQLTableName; ................................................................................ W.Add(','); end; result := fValue.Count; end else result := FindWhereEqual(WhereField,WhereValue,GetJSONValuesEvent,W); if (result=0) and W.Expand then begin // we want the field names at least, even with no data Expand := false; // {"FieldCount":2,"Values":["col1","col2"]} W.Expand := false; W.CancelAll; fStoredClassProps.SetJSONWriterColumnNames(W); end; W.CancelLastComma; // cancel last ',' // end the JSON object W.Add(']'); |
> > | | | | | | | | | | | | | |
605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 .... 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 .... 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 .... 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 ..... 11147 11148 11149 11150 11151 11152 11153 11154 11155 11156 11157 11158 11159 11160 11161 11162 11163 11164 11165 ..... 11168 11169 11170 11171 11172 11173 11174 11175 11176 11177 11178 11179 11180 11181 11182 11183 11184 11185 11186 11187 11188 11189 11190 11191 11192 11193 ..... 11358 11359 11360 11361 11362 11363 11364 11365 11366 11367 11368 11369 11370 11371 11372 ..... 13264 13265 13266 13267 13268 13269 13270 13271 13272 13273 13274 13275 13276 13277 13278 ..... 13280 13281 13282 13283 13284 13285 13286 13287 13288 13289 13290 13291 13292 13293 13294 13295 13296 13297 ..... 14502 14503 14504 14505 14506 14507 14508 14509 14510 14511 14512 14513 14514 14515 14516 ..... 19185 19186 19187 19188 19189 19190 19191 19192 19193 19194 19195 19196 19197 19198 19199 |
Weak interface assignment (with small performance penalty and memory use), corresponding to the ARC's Zeroing Weak pointers model - CopyObject() procedure now handle TCollection kind of object not only as sub properties - introducing TInterfacedCollection dedicated class, properly handling collection item creation on the Server side, with interface-based services: all contract operations shall use it instead of TCollection - changed the non expanded JSON format to use lowercase first column names: {"fieldCount":1,"values":["col1"... instead of {"FieldCount":1,"Values":[.. - added TSQLTable.FieldLengthMax() and ExpandAsSynUnicode() methods - added BlobToBytes() function and TSQLTable.GetBytes/GetStream methods - added virtual TSQLRestServer.FlushInternalDBCache method and dedicated TSQLRestServerStaticInMemoryExternal class, to properly handle external DB modification for virtual tables (i.e. flush SQL/JSON cache as expected) - added TSQLRestServerStatic.InternalBatchStart / InternalBatchStop methods to handle fast grouped sending to remote database engine (e.g. Oracle ................................................................................ /// save the table values in JSON format // - JSON data is added to TStream, with UTF-8 encoding // - if Expand 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 Expand is false, JSON data is serialized (used in TSQLTableJSON) // & { "fieldCount":1,"values":["col1","col2",val11,"val12",val21,..] } // - RowFirst and RowLast can be used to ask for a specified row extent // of the returned data (by default, all rows are retrieved) procedure GetJSONValues(JSON: TStream; Expand: boolean; RowFirst: integer=0; RowLast: integer=0); overload; /// same as above, but returning result into a RawUTF8 function GetJSONValues(Expand: boolean): RawUTF8; overload; /// save the table in CSV format ................................................................................ /// get the FIRST field value of the FIRST row, from a JSON content // - e.g. usefull to get an ID without converting a JSON content into a TSQLTableJSON function UnJSONFirstField(var P: PUTF8Char): RawUTF8; /// returns TRUE if the JSON content is in expanded format // - i.e. as plain [{"ID":10,"FirstName":"John","LastName":"Smith"}...] // - i.e. not as '{"fieldCount":3,"values":["ID","FirstName","LastName",...']} function IsNotAjaxJSON(P: PUTF8Char): Boolean; /// get the number of rows stored in the not-expanded JSON content function GetRowCountNotExpanded(P: PUTF8Char; FieldCount: integer; var RowCount: integer): PUTF8Char; /// go to the end of a field name in a JSON '"FieldName":Value' pair // - returns nil if P was not formatted as expected ................................................................................ (** return the UTF-8 encoded JSON objects for the values contained in the current published fields of a TSQLRecord child - only simple fields (i.e. not TSQLRawBlob/TSQLRecordMany) are retrieved: BLOB fields are ignored (use direct access via dedicated methods instead) - if Expand is true, JSON data is an object, for direct use with any Ajax or .NET client: ! {"col1":val11,"col2":"val12"} - if Expand is false, JSON data is serialized (as used in TSQLTableJSON) ! { "fieldCount":1,"values":["col1","col2",val11,"val12",val21,..] } - if withID is true, then the first ID field value is included *) procedure GetJSONValues(JSON: TStream; Expand: boolean; withID: boolean; Occasion: TSQLOccasion); overload; /// same as above, but returning result into a RawUTF8 // - if UsingStream is not set, it will use a temporary THeapMemoryStream instance function GetJSONValues(Expand: boolean; withID: boolean; Occasion: TSQLOccasion; UsingStream: TCustomMemoryStream=nil): RawUTF8; overload; ................................................................................ inc(P); until false; end; end; function UnJSONFirstField(var P: PUTF8Char): RawUTF8; // expand=true: [ {"col1":val11} ] -> val11 // expand=false: { "fieldCount":1,"values":["col1",val11] } -> vall11 begin result := ''; if P=nil then exit; if Expect(P,'{"fieldCount":') then begin // not expanded format if GetJSONIntegerVar(P)<>1 then exit; // wrong field count while P^<>'[' do if P^=#0 then exit else inc(P); // go to ["col1" inc(P); // go to "col1" end else begin // expanded format ................................................................................ end; GetJSONField(P,P); // ignore field name result := GetJSONField(P,P); // get field value end; function IsNotAjaxJSON(P: PUTF8Char): Boolean; begin result := Expect(P,'{"fieldCount":'); end; function IsNotExpanded(var P: PUTF8Char; var FieldCount: integer): boolean; begin if not IsNotAjaxJSON(P) then begin result := false; exit; end; inc(P,14); FieldCount := GetJSONIntegerVar(P); result := (FieldCount<>0) and Expect(P,',"values":['); end; function GetRowCountNotExpanded(P: PUTF8Char; FieldCount: integer; var RowCount: integer): PUTF8Char; begin RowCount := 0; result := P; // no data at all of unexpected end repeat ................................................................................ result := false; // error on parsing if (self=nil) or (Buffer=nil) then exit; // go to start of object P := GotoNextNotSpace(Buffer); if IsNotExpanded(P,fFieldCount) then begin // A. Not Expanded format (* {"fieldCount":9,"values":["ID","Int","Test","Unicode","Ansi","ValFloat","ValWord", "ValDate","Next",0,0,"abcde+�ef+�+�","abcde+�ef+�+�","abcde+�ef+�+�", 3.14159265300000E+0000,1203,"2009-03-10T21:19:36",0,..]} *) // 1. get RowCount and DataLen DataLen := GetRowCountNotExpanded(P,FieldCount,fRowCount)-P; // also check P^ format if DataLen=0 then begin fRowCount := 0; exit; ................................................................................ Freemem(tmp); end; end; end; procedure TSQLRecord.FillFrom(P: PUTF8Char); (* two possible formats = first not expanded, 2nd is expanded (most usefull) {"fieldCount":9,"values":["ID","Int","Test","Unicode","Ansi","ValFloat","ValWord", "ValDate","Next",0,0,"abcde+�ef+�+�","abcde+�ef+�+�","abcde+�ef+�+�", 3.14159265300000E+0000,1203,"2009-03-10T21:19:36",0]} {"ID":0,"Int":0,"Test":"abcde+�ef+�+�","Unicode":"abcde+�ef+�+�","Ansi": "abcde+�ef+�+�","ValFloat": 3.14159265300000E+0000,"ValWord":1203, "ValDate":"2009-03-10T21:19:36","Next":0} *) var F: array[0..MAX_SQLFIELDS-1] of PUTF8Char; // store field/property names i, n: integer; ................................................................................ Value: PUTF8Char; begin // go to start of object if P=nil then exit; while P^<>'{' do if P^=#0 then exit else inc(P); if Expect(P,'{"fieldCount":') then begin // not expanded format n := GetJSONIntegerVar(P)-1; if (cardinal(n)>high(F)) or not Expect(P,',"values":[') then exit; for i := 0 to n do F[i] := GetJSONField(P,P); // get field names for i := 0 to n do begin Prop := F[i]; // share shortstring on stack with code below FillValue(Prop,GetJSONField(P,P)); // set properties from values end; ................................................................................ procedure TSQLModel.SetTableProps(aTable: TSQLRecordClass; aIndex: integer; Last, VirtualsRemain: boolean); var f, R: integer; Props: TSQLRecordProperties; PT: PTypeInfo; begin Props := aTable.RecordProps; if (not VirtualsRemain) and (Props.Kind in IS_CUSTOM_VIRTUAL) then Props.Kind := rSQLite3; // reset to internal table at model creation if Props.Model=nil then begin Props.Model := self; Props.ModelTableIndex := aIndex; end; TableProps[aIndex] := Props; fTablesName[aIndex] := Props.SQLTableName; ................................................................................ W.Add(','); end; result := fValue.Count; end else result := FindWhereEqual(WhereField,WhereValue,GetJSONValuesEvent,W); if (result=0) and W.Expand then begin // we want the field names at least, even with no data Expand := false; // {"fieldCount":2,"values":["col1","col2"]} W.Expand := false; W.CancelAll; fStoredClassProps.SetJSONWriterColumnNames(W); end; W.CancelLastComma; // cancel last ',' // end the JSON object W.Add(']'); |
Changes to SynCommons.pas.
308 309 310 311 312 313 314 315 316 317 318 319 320 321 .... 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 .... 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 .... 5667 5668 5669 5670 5671 5672 5673 5674 5675 5676 5677 5678 5679 5680 5681 ..... 20194 20195 20196 20197 20198 20199 20200 20201 20202 20203 20204 20205 20206 20207 20208 20209 20210 20211 20212 20213 20214 20215 20216 20217 20218 20219 20220 20221 20222 20223 20224 20225 20226 20227 20228 20229 20230 20231 |
TObjectListPropertyHashed class, which allows hashing of a sub-property of an object (including some changes made to TDynArray/TDynArrayHshed) - new TTextWriter.AddDateTime() overloaded method able to quote the output - both TTextWriter.AddDateTime() overloaded methods will store '' when value is 0, or a pure ISO-8601 date or time if the value is defined as such, just as expected by http://www.sqlite.org/lang_datefunc.html - it will also reduce average generated JSON/text content size - new SetInt64() procedure for direct assignment of the result - TSynTableStatement class now accepts '_' in table and column identifiers - fixed implementation issue in function FindNextUTF8WordBegin() - fixed false negative issue in TSynSoundEx.UTF8 and TSynSoundEx.Ansi - added an optional parameter to StrToCurr64() function, able to return a true Int64 value if no decimal is supplied within the input text buffer - enhanced TSynAnsiFixedWidth.UnicodeBufferToAnsi average process speed ................................................................................ /// used to store output format for TSQLRecord.GetJSONValues() fWithID: boolean; /// used to store field for TSQLRecord.GetJSONValues() fFields: TSQLFieldBits; fFieldMax: integer; /// if not Expanded format, contains the Stream position of the first // usefull Row of data; i.e. ',val11' position in: // & { "FieldCount":1,"Values":["col1","col2",val11,"val12",val21,..] } fStartDataPosition: integer; public /// used internally to store column names and count for AddColumns ColNames: TRawUTF8DynArray; /// the data will be written to the specified Stream // - if no Stream is supplied, a temporary memory stream will be created // (it's faster to supply one, e.g. any TSQLRest.TempMemoryStream) ................................................................................ /// Read-Only access to the field bits set for each column to be stored property Fields: TSQLFieldBits read fFields write fFields; /// Read-Only access to the higher field index to be stored // - i.e. the highest bit set in Fields property FieldMax: integer read fFieldMax write fFieldMax; /// if not Expanded format, contains the Stream position of the first // usefull Row of data; i.e. ',val11' position in: // & { "FieldCount":1,"Values":["col1","col2",val11,"val12",val21,..] } property StartDataPosition: integer read fStartDataPosition; end; /// implement a cache of some key/value pairs, e.g. to improve reading speed // - used e.g. by TSQLDataBase for caching the SELECT statements results in an // internal JSON format (which is faster than a query to the SQLite3 engine) // - internally make use of an efficient hashing algorithm for fast response ................................................................................ const Fields: TSQLFieldBits): TJSONWriter; (** return the UTF-8 encoded JSON objects for the values contained in the specified RecordBuffer encoded in our SBF compact binary format, according to the Expand/WithID/Fields parameters of W - if W.Expand is true, JSON data is an object, for direct use with any Ajax or .NET client: ! {"col1":val11,"col2":"val12"} - if W.Expand is false, JSON data is serialized (as used in TSQLTableJSON) ! { "FieldCount":1,"Values":["col1","col2",val11,"val12",val21,..] } - only fields with a bit set in W.Fields will be appended - if W.WithID is true, then the first ID field value is included *) procedure GetJSONValues(aID: integer; RecordBuffer: PUTF8Char; W: TJSONWriter); /// can be used to retrieve all values matching a preparated TSynTableStatement // - this method matchs the TSynBigTableIterateEvent callback definition // - Sender will be the TSynBigTable instance, and Opaque will point to a // TSynTableStatement instance (with all fields initialized, including Writer) ................................................................................ procedure TJSONWriter.AddColumns; var i: integer; begin if fExpand then begin for i := 0 to High(ColNames) do ColNames[i] := '"'+ColNames[i]+'":'; end else begin AddShort('{"FieldCount":'); Add(length(ColNames)); AddShort(',"Values":["'); // first row is FieldNames for i := 0 to High(ColNames) do begin AddString(ColNames[i]); AddNoJSONEscape(PAnsiChar('","'),3); end; CancelLastChar; // cancel last '"' fStartDataPosition := fStream.Position+(B-fTempBuf); // B := buf-1 at startup -> need ',val11' position in // 'Values":["col1","col2",val11,' i.e. current pos without the ',' end; end; procedure TJSONWriter.TrimFirstRow; var P, PBegin, PEnd: PUTF8Char; begin if (self=nil) or not fStream.InheritsFrom(TMemoryStream) or fExpand or (fStartDataPosition=0) then exit; // go to begin of first row Flush; // we need the data to be in fStream memory // PBegin^=val11 in { "FieldCount":1,"Values":["col1","col2",val11,"val12",val21,..] } PBegin := TMemoryStream(fStream).Memory; PEnd := PBegin+fStream.Position; PEnd^ := #0; // mark end of current values inc(PBegin,fStartDataPosition+1); // +1 to include ',' of ',val11' // jump to end of first row P := GotoNextJSONField(PBegin,length(ColNames)); if P=nil then exit; // unexpected end |
> > | | | | | | | |
308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 .... 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 .... 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 .... 5669 5670 5671 5672 5673 5674 5675 5676 5677 5678 5679 5680 5681 5682 5683 ..... 20196 20197 20198 20199 20200 20201 20202 20203 20204 20205 20206 20207 20208 20209 20210 20211 20212 20213 20214 20215 20216 20217 20218 20219 20220 20221 20222 20223 20224 20225 20226 20227 20228 20229 20230 20231 20232 20233 |
TObjectListPropertyHashed class, which allows hashing of a sub-property of an object (including some changes made to TDynArray/TDynArrayHshed) - new TTextWriter.AddDateTime() overloaded method able to quote the output - both TTextWriter.AddDateTime() overloaded methods will store '' when value is 0, or a pure ISO-8601 date or time if the value is defined as such, just as expected by http://www.sqlite.org/lang_datefunc.html - it will also reduce average generated JSON/text content size - changed the non expanded JSON format to use lowercase first column names: {"fieldCount":1,"values":["col1"... instead of {"FieldCount":1,"Values":[.. - new SetInt64() procedure for direct assignment of the result - TSynTableStatement class now accepts '_' in table and column identifiers - fixed implementation issue in function FindNextUTF8WordBegin() - fixed false negative issue in TSynSoundEx.UTF8 and TSynSoundEx.Ansi - added an optional parameter to StrToCurr64() function, able to return a true Int64 value if no decimal is supplied within the input text buffer - enhanced TSynAnsiFixedWidth.UnicodeBufferToAnsi average process speed ................................................................................ /// used to store output format for TSQLRecord.GetJSONValues() fWithID: boolean; /// used to store field for TSQLRecord.GetJSONValues() fFields: TSQLFieldBits; fFieldMax: integer; /// if not Expanded format, contains the Stream position of the first // usefull Row of data; i.e. ',val11' position in: // & { "fieldCount":1,"values":["col1","col2",val11,"val12",val21,..] } fStartDataPosition: integer; public /// used internally to store column names and count for AddColumns ColNames: TRawUTF8DynArray; /// the data will be written to the specified Stream // - if no Stream is supplied, a temporary memory stream will be created // (it's faster to supply one, e.g. any TSQLRest.TempMemoryStream) ................................................................................ /// Read-Only access to the field bits set for each column to be stored property Fields: TSQLFieldBits read fFields write fFields; /// Read-Only access to the higher field index to be stored // - i.e. the highest bit set in Fields property FieldMax: integer read fFieldMax write fFieldMax; /// if not Expanded format, contains the Stream position of the first // usefull Row of data; i.e. ',val11' position in: // & { "fieldCount":1,"values":["col1","col2",val11,"val12",val21,..] } property StartDataPosition: integer read fStartDataPosition; end; /// implement a cache of some key/value pairs, e.g. to improve reading speed // - used e.g. by TSQLDataBase for caching the SELECT statements results in an // internal JSON format (which is faster than a query to the SQLite3 engine) // - internally make use of an efficient hashing algorithm for fast response ................................................................................ const Fields: TSQLFieldBits): TJSONWriter; (** return the UTF-8 encoded JSON objects for the values contained in the specified RecordBuffer encoded in our SBF compact binary format, according to the Expand/WithID/Fields parameters of W - if W.Expand is true, JSON data is an object, for direct use with any Ajax or .NET client: ! {"col1":val11,"col2":"val12"} - if W.Expand is false, JSON data is serialized (as used in TSQLTableJSON) ! { "fieldCount":1,"values":["col1","col2",val11,"val12",val21,..] } - only fields with a bit set in W.Fields will be appended - if W.WithID is true, then the first ID field value is included *) procedure GetJSONValues(aID: integer; RecordBuffer: PUTF8Char; W: TJSONWriter); /// can be used to retrieve all values matching a preparated TSynTableStatement // - this method matchs the TSynBigTableIterateEvent callback definition // - Sender will be the TSynBigTable instance, and Opaque will point to a // TSynTableStatement instance (with all fields initialized, including Writer) ................................................................................ procedure TJSONWriter.AddColumns; var i: integer; begin if fExpand then begin for i := 0 to High(ColNames) do ColNames[i] := '"'+ColNames[i]+'":'; end else begin AddShort('{"fieldCount":'); Add(length(ColNames)); AddShort(',"values":["'); // first row is FieldNames for i := 0 to High(ColNames) do begin AddString(ColNames[i]); AddNoJSONEscape(PAnsiChar('","'),3); end; CancelLastChar; // cancel last '"' fStartDataPosition := fStream.Position+(B-fTempBuf); // B := buf-1 at startup -> need ',val11' position in // "values":["col1","col2",val11,' i.e. current pos without the ',' end; end; procedure TJSONWriter.TrimFirstRow; var P, PBegin, PEnd: PUTF8Char; begin if (self=nil) or not fStream.InheritsFrom(TMemoryStream) or fExpand or (fStartDataPosition=0) then exit; // go to begin of first row Flush; // we need the data to be in fStream memory // PBegin^=val11 in { "fieldCount":1,"values":["col1","col2",val11,"val12",val21,..] } PBegin := TMemoryStream(fStream).Memory; PEnd := PBegin+fStream.Position; PEnd^ := #0; // mark end of current values inc(PBegin,fStartDataPosition+1); // +1 to include ',' of ',val11' // jump to end of first row P := GotoNextJSONField(PBegin,length(ColNames)); if P=nil then exit; // unexpected end |