mORMot and Open Source friends
Check-in [4e42b0c81b]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:{4321} consistent TSQLRestServerDB.InternalBatchStop with a single Add()
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 4e42b0c81b3572cf5fd419fe7e08d2c50f5bd7a4
User & Date: ab 2018-02-20 22:51:55
Context
2018-02-20
23:05
{4322} pointless refactoring to use FindPropName() if possible check-in: 52b2947db3 user: ab tags: trunk
22:51
{4321} consistent TSQLRestServerDB.InternalBatchStop with a single Add() check-in: 4e42b0c81b user: ab tags: trunk
22:45
{4320} fixed boRollbackOnError for mPOST check-in: f927a214c3 user: ab tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to SQLite3/mORMot.pas.

28058
28059
28060
28061
28062
28063
28064
28065
28066
28067
28068
28069
28070
28071
28072
28073
28074
28075
28076
28077
28078
28079
28080
  {$WARNINGS ON}
{$endif}

function TJSONObjectDecoder.EncodeAsSQL(Update: boolean): RawUTF8;
var F: integer;
    W: TTextWriter;
    temp: TTextWriterStackBuffer;
procedure AddValue;
begin
  if InlinedParams then
    W.AddShort(':(');
  W.AddString(FieldValues[F]);
  if InlinedParams then
    W.AddShort('):,') else
    W.Add(',');
end;
begin
  result := '';
  if FieldCount=0 then
    exit;
  W := TTextWriter.CreateOwnedStream(temp);
  try
    if Update then begin






|
|
|
|
|
|
|
|
|







28058
28059
28060
28061
28062
28063
28064
28065
28066
28067
28068
28069
28070
28071
28072
28073
28074
28075
28076
28077
28078
28079
28080
  {$WARNINGS ON}
{$endif}

function TJSONObjectDecoder.EncodeAsSQL(Update: boolean): RawUTF8;
var F: integer;
    W: TTextWriter;
    temp: TTextWriterStackBuffer;
  procedure AddValue;
  begin
    if InlinedParams then
      W.AddShort(':(');
    W.AddString(FieldValues[F]);
    if InlinedParams then
      W.AddShort('):,') else
      W.Add(',');
  end;
begin
  result := '';
  if FieldCount=0 then
    exit;
  W := TTextWriter.CreateOwnedStream(temp);
  try
    if Update then begin

Changes to SQLite3/mORMotSQLite3.pas.

1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
....
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932


1933
1934
1935
1936
1937
1938
1939
1940
....
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
....
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
....
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
function TSQLRestServerDB.InternalBatchStart(
  Method: TSQLURIMethod; BatchOptions: TSQLRestBatchOptions): boolean;
begin
  result := false; // means BATCH mode not supported
  if method=mPOST then begin // POST=ADD=INSERT -> MainEngineAdd() to fBatchValues[]
    if (fBatchMethod<>mNone) or (fBatchValuesCount<>0) or (fBatchIDCount<>0) then
      raise EORMException.CreateUTF8('%.InternalBatchStop should have been called',[self]);
    fBatchMethod := method;
    fBatchOptions := BatchOptions;
    fBatchTableIndex := -1;
    fBatchIDMax := 0; // MainEngineAdd() will search for max(id)
    result := true; // means BATCH mode is supported
  end;
end;
................................................................................
    Props: TSQLRecordProperties;
    Decode: TJSONObjectDecoder;
    tmp: TSynTempBuffer;
begin
  if (fBatchValuesCount=0) or (fBatchTableIndex<0) then
    exit; // nothing to add
  if fBatchMethod<>mPOST then
    raise EORMException.CreateUTF8('%.InternalBatchStop: BatchMethod=%',
      [self,ToText(fBatchMethod)^]);
  try
    if fBatchValuesCount<>fBatchIDCount then
      raise EORMException.CreateUTF8('%.InternalBatchStop(*Count?)',[self]);
    UpdateEventNeeded := InternalUpdateEventNeeded(fBatchTableIndex);
    Props := fModel.Tables[fBatchTableIndex].RecordProps;
    if fBatchValuesCount=1 then begin // handle single record insert
      Decode.Decode(fBatchValues[0],nil,pInlined,fBatchID[0]);
      if Props.RecordVersionField<>nil then
        InternalRecordVersionHandle(
          soInsert,fBatchTableIndex,Decode,Props.RecordVersionField);
      SQL := 'INSERT INTO '+Props.SQLTableName+Decode.EncodeAsSQL(False)+';';


      if InternalExecute(SQL,true) and UpdateEventNeeded then
        InternalUpdateEvent(seAdd,fBatchTableIndex,fBatchID[0],fBatchValues[0],nil);
      exit;
    end;
    DecodeSaved := true;
    valuesCount := 0;
    rowCount := 0;
    valuesFirstRow := 0;
................................................................................
        try
          if UpdateEventNeeded then begin
            tmp.Init(fBatchValues[ndx]);
            P := tmp.buf;
          end else
            P := pointer(fBatchValues[ndx]);
          if P=nil then
            raise EORMException.CreateUTF8(
              '%.InternalBatchStop: fBatchValues[%]=""',[self,ndx]);
          while P^ in [#1..' ','{','['] do inc(P);
          Decode.Decode(P,nil,pNonQuoted,fBatchID[ndx]);
          if Props.RecordVersionField<>nil then
            InternalRecordVersionHandle(
              soInsert,fBatchTableIndex,Decode,Props.RecordVersionField);
          inc(ndx);
................................................................................
              ftBlob:
                fStatement^.BindBlob(f+1,Values[f]);
              end;
            inc(prop);
            if prop=fieldCount then
              prop := 0;
          end;
          repeat until fStatement^.Step<>SQLITE_ROW;
          if UpdateEventNeeded then
            for r := valuesFirstRow to valuesFirstRow+rowCount-1 do
              InternalUpdateEvent(seAdd,fBatchTableIndex,fBatchID[r],fBatchValues[r],nil);
          inc(valuesFirstRow,rowCount);
          GetAndPrepareStatementRelease;
        except
          on E: Exception do begin
................................................................................
      end;
      FillcharFast(ValuesNull[0],(ValuesCount shr 3)+1,0);
      ValuesCount := 0;
      rowCount := 0;
      Fields := nil; // force new SQL statement and Values[]
    until DecodeSaved and (ndx=fBatchValuesCount);
    if valuesFirstRow<>fBatchValuesCount then
      raise EORMException.CreateUTF8('%.InternalBatchStop(valuesFirstRow)',[self]);
  finally
    fBatchMethod := mNone;
    fBatchValuesCount := 0;
    fBatchValues := nil;
    fBatchIDCount := 0;
    fBatchID := nil;
  end;






|







 







|



|








>
>
|







 







|







 







|







 







|







1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
....
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
....
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
....
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
....
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
function TSQLRestServerDB.InternalBatchStart(
  Method: TSQLURIMethod; BatchOptions: TSQLRestBatchOptions): boolean;
begin
  result := false; // means BATCH mode not supported
  if method=mPOST then begin // POST=ADD=INSERT -> MainEngineAdd() to fBatchValues[]
    if (fBatchMethod<>mNone) or (fBatchValuesCount<>0) or (fBatchIDCount<>0) then
      raise EORMBatchException.CreateUTF8('%.InternalBatchStop should have been called',[self]);
    fBatchMethod := method;
    fBatchOptions := BatchOptions;
    fBatchTableIndex := -1;
    fBatchIDMax := 0; // MainEngineAdd() will search for max(id)
    result := true; // means BATCH mode is supported
  end;
end;
................................................................................
    Props: TSQLRecordProperties;
    Decode: TJSONObjectDecoder;
    tmp: TSynTempBuffer;
begin
  if (fBatchValuesCount=0) or (fBatchTableIndex<0) then
    exit; // nothing to add
  if fBatchMethod<>mPOST then
    raise EORMBatchException.CreateUTF8('%.InternalBatchStop: BatchMethod=%',
      [self,ToText(fBatchMethod)^]);
  try
    if fBatchValuesCount<>fBatchIDCount then
      raise EORMBatchException.CreateUTF8('%.InternalBatchStop(*Count?)',[self]);
    UpdateEventNeeded := InternalUpdateEventNeeded(fBatchTableIndex);
    Props := fModel.Tables[fBatchTableIndex].RecordProps;
    if fBatchValuesCount=1 then begin // handle single record insert
      Decode.Decode(fBatchValues[0],nil,pInlined,fBatchID[0]);
      if Props.RecordVersionField<>nil then
        InternalRecordVersionHandle(
          soInsert,fBatchTableIndex,Decode,Props.RecordVersionField);
      SQL := 'INSERT INTO '+Props.SQLTableName+Decode.EncodeAsSQL(False)+';';
      if not InternalExecute(SQL,true) then // just like ESQLite3Exception below
        raise EORMBatchException.CreateUTF8('%.InternalBatchStop failed on %', [self, SQL]);
      if UpdateEventNeeded then
        InternalUpdateEvent(seAdd,fBatchTableIndex,fBatchID[0],fBatchValues[0],nil);
      exit;
    end;
    DecodeSaved := true;
    valuesCount := 0;
    rowCount := 0;
    valuesFirstRow := 0;
................................................................................
        try
          if UpdateEventNeeded then begin
            tmp.Init(fBatchValues[ndx]);
            P := tmp.buf;
          end else
            P := pointer(fBatchValues[ndx]);
          if P=nil then
            raise EORMBatchException.CreateUTF8(
              '%.InternalBatchStop: fBatchValues[%]=""',[self,ndx]);
          while P^ in [#1..' ','{','['] do inc(P);
          Decode.Decode(P,nil,pNonQuoted,fBatchID[ndx]);
          if Props.RecordVersionField<>nil then
            InternalRecordVersionHandle(
              soInsert,fBatchTableIndex,Decode,Props.RecordVersionField);
          inc(ndx);
................................................................................
              ftBlob:
                fStatement^.BindBlob(f+1,Values[f]);
              end;
            inc(prop);
            if prop=fieldCount then
              prop := 0;
          end;
          repeat until fStatement^.Step<>SQLITE_ROW; // ESQLite3Exception on error
          if UpdateEventNeeded then
            for r := valuesFirstRow to valuesFirstRow+rowCount-1 do
              InternalUpdateEvent(seAdd,fBatchTableIndex,fBatchID[r],fBatchValues[r],nil);
          inc(valuesFirstRow,rowCount);
          GetAndPrepareStatementRelease;
        except
          on E: Exception do begin
................................................................................
      end;
      FillcharFast(ValuesNull[0],(ValuesCount shr 3)+1,0);
      ValuesCount := 0;
      rowCount := 0;
      Fields := nil; // force new SQL statement and Values[]
    until DecodeSaved and (ndx=fBatchValuesCount);
    if valuesFirstRow<>fBatchValuesCount then
      raise EORMBatchException.CreateUTF8('%.InternalBatchStop(valuesFirstRow)',[self]);
  finally
    fBatchMethod := mNone;
    fBatchValuesCount := 0;
    fBatchValues := nil;
    fBatchIDCount := 0;
    fBatchID := nil;
  end;

Changes to SynCommons.pas.

1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
    // - Dest^ buffer must be reserved with at least SourceChars bytes
    // - no trailing #0 is appended to the buffer
    function UTF8BufferToAnsi(Dest: PAnsiChar; Source: PUTF8Char;
      SourceChars: Cardinal): PAnsiChar; override;
  end;

  /// implements a stack-based storage of some (UTF-8 or binary) text
  // - could be used e.g. to make a temporary copy when JSON would be
  // parsed in-place
  // - call one of the Init() overloaded methods, then Done to release its memory
  // - will avoid temporary memory allocation via the heap for up to 4KB of text
  {$ifdef UNICODE}
  TSynTempBuffer = record
  {$else}
  TSynTempBuffer = object
  {$endif}






|
<







1496
1497
1498
1499
1500
1501
1502
1503

1504
1505
1506
1507
1508
1509
1510
    // - Dest^ buffer must be reserved with at least SourceChars bytes
    // - no trailing #0 is appended to the buffer
    function UTF8BufferToAnsi(Dest: PAnsiChar; Source: PUTF8Char;
      SourceChars: Cardinal): PAnsiChar; override;
  end;

  /// implements a stack-based storage of some (UTF-8 or binary) text
  // - could be used e.g. to make a temporary copy when JSON is parsed in-place

  // - call one of the Init() overloaded methods, then Done to release its memory
  // - will avoid temporary memory allocation via the heap for up to 4KB of text
  {$ifdef UNICODE}
  TSynTempBuffer = record
  {$else}
  TSynTempBuffer = object
  {$endif}

Changes to SynopseCommit.inc.

1
'1.18.4320'
|
1
'1.18.4321'