Skip to content

Commit

Permalink
optimized TSqlRequest.Execute about resultset column name
Browse files Browse the repository at this point in the history
  • Loading branch information
Arnaud Bouchez committed Oct 1, 2021
1 parent 62ae423 commit 587a679
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 14 deletions.
60 changes: 55 additions & 5 deletions src/db/mormot.db.core.pas
Expand Up @@ -803,6 +803,11 @@ TJsonWriter = class(TTextWriter)
// - if aKnownRowsCount is not null, a "rowCount":... item will be added
// to the generated JSON stream (for faster unserialization of huge content)
procedure AddColumns(aKnownRowsCount: integer = 0);
/// write or init field names for appropriate JSON Expand later use
// - accept a name directly supplied by the DB provider
// - if Expand is true, will set ColNames[] with the expected format
// - on non-expanded format, will directly write aColName to W
procedure AddColumn(aColName: PUtf8Char; aColIndex, aColCount: PtrInt);
/// allow to change on the fly an expanded format column layout
// - by definition, a non expanded format will raise a ESynDBException
// - caller should then set ColNames[] and run AddColumns()
Expand Down Expand Up @@ -2213,10 +2218,10 @@ procedure TJsonWriter.AddColumns(aKnownRowsCount: integer);
if fExpand then
begin
if twoForceJsonExtended in CustomOptions then
for i := 0 to High(ColNames) do
for i := 0 to length(ColNames) - 1 do
ColNames[i] := ColNames[i] + ':'
else
for i := 0 to High(ColNames) do
for i := 0 to length(ColNames) - 1 do
ColNames[i] := '"' + ColNames[i] + '":';
end
else
Expand All @@ -2230,18 +2235,63 @@ procedure TJsonWriter.AddColumns(aKnownRowsCount: integer);
end;
AddShort(',"values":["');
// first row is FieldNames
for i := 0 to High(ColNames) do
for i := 0 to length(ColNames) - 1 do
begin
AddString(ColNames[i]);
AddNoJsonEscape(PAnsiChar('","'), 3);
AddShorter('","');
end;
CancelLastChar('"');
fStartDataPosition := fStream.Position {%H-}+ (B - fTempBuf);
fStartDataPosition := fStream.Position + PtrInt(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.AddColumn(aColName: PUtf8Char; aColIndex, aColCount: PtrInt);
var
len: PtrInt;
P: PUtf8Char;
begin
len := StrLen(aColName);
if fExpand then
begin
if aColIndex = 0 then // non-expanded mode doesn't use ColNames[]
SetLength(ColNames, aColCount);
FastSetString(ColNames[aColIndex], nil,
len + 3 - ord(twoForceJsonExtended in CustomOptions) * 2);
P := pointer(ColNames[aColIndex]);
if twoForceJsonExtended in CustomOptions then
MoveFast(aColName^, P^, len) // extended JSON unquoted field names
else
begin
P[0] := '"';
inc(P);
MoveFast(aColName^, P^, len); // regular JSON quoted field name
P[len] := '"';
inc(P);
end;
P[len] := ':';
end
else
begin
if aColIndex = 0 then
begin
AddShort('{"fieldCount":');
Add(aColCount);
AddShort(',"values":["');
// first row is FieldNames in non-expanded format
end;
AddNoJsonEscape(aColName, len);
if aColIndex = aColCount - 1 then
begin
// last AddColumn() call would finalize the non-expanded header
Add('"' , ',');
fStartDataPosition := fStream.Position + PtrInt(B - fTempBuf);
end else
AddShorter('","');
end;
end;

procedure TJsonWriter.ChangeExpandedFields(aWithID: boolean;
const aFields: TFieldIndexDynArray);
begin
Expand Down
14 changes: 5 additions & 9 deletions src/db/mormot.db.raw.sqlite3.pas
Expand Up @@ -7816,15 +7816,13 @@ function TSqlRequest.Execute(aDB: TSqlite3DB; const aSql: RawUtf8;
W.CancelAllVoid;
exit;
end;
// get col names and types
SetLength(W.ColNames, FieldCount);
// directly assign column names from SQlite3 API into W
for i := 0 to FieldCount - 1 do
W.ColNames[i] := sqlite3.column_name(Request, i);
W.AddColumns; // write or init field names for appropriate Json Expand
W.AddColumn(sqlite3.column_name(Request, i), i, FieldCount);
if Expand then
W.Add('[');
// write rows data
repeat
while true do
case Step of
SQLITE_ROW:
begin
Expand All @@ -7839,16 +7837,14 @@ function TSqlRequest.Execute(aDB: TSqlite3DB; const aSql: RawUtf8;
SQLITE_DONE:
break;
end;
until false;
if (result = 0) and
W.Expand then
begin
// we want the field names at least, even with no data: allow RowCount=0
W.Expand := false; // {"FieldCount":2,"Values":["col1","col2"]}
W.Expand := false; // {"FieldCount":2,"Values":["col1","col2"]} format
W.CancelAll;
for i := 0 to FieldCount - 1 do
W.ColNames[i] := sqlite3.column_name(Request, i);
W.AddColumns;
W.AddColumn(sqlite3.column_name(Request, i), i, FieldCount);
end;
W.EndJsonObject(0, result);
finally
Expand Down

0 comments on commit 587a679

Please sign in to comment.