mORMot and Open Source friends
Check-in [8cca20d7e0]
Not logged in

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

Overview
Comment:{554} handle per-row column type in SynDB remote access (SQLite3 only) e.g. select coalesce(column,0) from ..
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 8cca20d7e05ec73311359ca892ec8a4a1fc949e7
User & Date: ab 2014-11-21 19:15:45
Context
2014-11-22
10:41
{555} added new project publishing Cross-Platform wrappers for sample 28 check-in: b0fd38d077 user: ab tags: trunk
2014-11-21
19:15
{554} handle per-row column type in SynDB remote access (SQLite3 only) e.g. select coalesce(column,0) from .. check-in: 8cca20d7e0 user: ab tags: trunk
18:19
{553} fixed Delphi XE7 specific issue our read/only TDataSet check-in: ac81632ed2 user: ab tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to SynDB.pas.

2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457


2458
2459
2460
2461
2462
2463
2464
....
6134
6135
6136
6137
6138
6139
6140

6141
6142
6143
6144





6145
6146
6147
6148
6149
6150
6151
6152
6153
6154
6155
6156
6157
6158
6159
6160
6161
6162
6163
6164

6165

6166
6167
6168
6169
6170
6171
6172
6173
6174
6175
6176
6177
6178

6179
6180
6181

6182

6183
6184
6185
6186
6187
6188
6189
6190
6191
6192
6193
6194
6195
6196
6197
6198
6199
....
6221
6222
6223
6224
6225
6226
6227

6228
6229
6230
6231
6232
6233
6234
....
7212
7213
7214
7215
7216
7217
7218
7219
7220
7221
7222
7223
7224
7225
7226
7227
7228
7229
7230
7231



7232
7233

7234
7235
7236
7237
7238
7239
7240
7241
7242
7243
7244
7245
7246
7247
7248
7249
7250
7251
7252
7253
7254
7255
7256
7257
7258
7259
7260
7261
7262
7263
7264
7265
7266
7267
7268





7269
7270
7271

7272
7273
7274
7275
7276
7277
7278
7279
7280
7281
7282
7283
7284
7285
7286
7287
7288
7289
7290
....
7291
7292
7293
7294
7295
7296
7297
7298
7299
7300
7301
7302
7303
7304
7305
7306
7307
7308
....
7313
7314
7315
7316
7317
7318
7319
7320
7321
7322
7323
7324
7325
7326
7327
7328
7329
7330
7331
7332
....
7348
7349
7350
7351
7352
7353
7354
7355
7356
7357
7358
7359
7360
7361
7362
7363
7364
7365
7366
7367
7368
7369
7370
7371
7372
7373
7374
  // - will handle an internal binary buffer when the statement returned rows
  // data, as generated by TSQLDBStatement.FetchAllToBinary()
  TSQLDBProxyStatementAbstract = class(TSQLDBStatementWithParamsAndColumns)
  protected
    fDataRowCount: integer;
    fDataRowReaderOrigin, fDataRowReader: PByte;
    fDataRowNullSize: cardinal;
    fDataCurrentRowIndex: integer;
    fDataCurrentRowNull: TSQLDBProxyStatementColumns;
    fDataCurrentRowNullLen: cardinal;
    fDataCurrentRowValues: array of pointer;
    fDataCurrentRowValuesStart: pointer;
    fDataCurrentRowValuesSize: Cardinal;


    function IntColumnType(Col: integer; out Data: PByte): TSQLDBFieldType;
      {$ifdef HASINLINE}inline;{$endif}
    procedure IntHeaderProcess(Data: PByte; DataLen: integer);
    procedure IntFillDataCurrent(var Reader: PByte);
  public
    /// the Column type of the current Row
    function ColumnType(Col: integer; FieldSize: PInteger=nil): TSQLDBFieldType; override;
................................................................................

procedure TSQLDBStatement.ColumnsToBinary(W: TFileBufferWriter;
  const Null: TSQLDBProxyStatementColumns; const ColTypes: TSQLDBFieldTypeDynArray);
var F: integer;
    VDouble: double;
    VCurrency: currency absolute VDouble;
    VDateTime: TDateTime absolute VDouble;

begin
  for F := 0 to length(ColTypes)-1 do
    if not (F in Null) then
    case ColTypes[F] of





    ftInt64:
      W.WriteVarInt64(ColumnInt(F));
    ftDouble: begin
      VDouble := ColumnDouble(F);
      W.Write(@VDouble,sizeof(VDouble));
    end;
    ftCurrency: begin
      VCurrency := ColumnCurrency(F);
      W.Write(@VCurrency,sizeof(VCurrency));
    end;
    ftDate: begin
      VDateTime := ColumnDateTime(F);
      W.Write(@VDateTime,sizeof(VDateTime));
    end;
    ftUTF8:
      W.Write(ColumnUTF8(F));
    ftBlob:
      W.Write(ColumnBlob(F));
    else raise ESQLDBException.CreateUTF8(
      '%.ColumnsToBinary: invalid ColTypes[%]=%',[self,F,ord(ColTypes[F])]);

    end;

end;

const
  FETCHALLTOBINARY_MAGIC = 1;

function TSQLDBStatement.FetchAllToBinary(Dest: TStream; MaxRowCount: cardinal;
  DataRowPosition: PCardinalDynArray): cardinal;
var F, FMax, FieldSize, NullRowSize: integer;
    StartPos: cardinal;
    Null: TSQLDBProxyStatementColumns;
    W: TFileBufferWriter;
    ColTypes: TSQLDBFieldTypeDynArray;
begin

  result := 0;
  W := TFileBufferWriter.Create(Dest);
  try

    FMax := ColumnCount;

    if FMax>0 then
      // write column description
      W.WriteVarUInt32(FETCHALLTOBINARY_MAGIC);
      W.WriteVarUInt32(FMax);
      SetLength(ColTypes,FMax);
      dec(FMax);
      for F := 0 to FMax do begin
        W.Write(ColumnName(F));
        ColTypes[F] := ColumnType(F,@FieldSize);
        W.Write(@ColTypes[F],sizeof(ColTypes[0]));
        W.WriteVarUInt32(FieldSize);
      end;
      // initialize null handling
      NullRowSize := (FMax shr 3)+1;
      if NullRowSize>sizeof(Null) then
        raise ESQLDBException.CreateUTF8('%.FetchAllToBinary: too many columns',[self]);
      // save all data rows
................................................................................
          W.Write(@Null,NullRowSize);
        // then write data values
        ColumnsToBinary(W,Null,ColTypes);
        inc(result);
        if (MaxRowCount>0) and (result>=MaxRowCount) then
          break;
      until not Step;

    W.Write(@result,SizeOf(result)); // fixed size at the end for row count
    W.Flush;
  finally
    W.Free;
  end;
end;

................................................................................
  fProxy.Process(cStartTransaction,self,self);
end;


{ TSQLDBProxyStatementAbstract }

procedure TSQLDBProxyStatementAbstract.IntHeaderProcess(Data: PByte; DataLen: integer);
var Magic,F: integer;
begin
  fDataCurrentRowValuesStart := nil;
  fDataCurrentRowValuesSize := 0;
  fDataCurrentRowIndex := -1;
  repeat
    if DataLen<=5 then
      break;
    fDataRowCount := PInteger(PtrInt(Data)+DataLen-sizeof(Integer))^;
    Magic := FromVarUInt32(Data);
    if Magic<>FETCHALLTOBINARY_MAGIC then
      break;
    for F := 1 to FromVarUInt32(Data) do



    with PSQLDBColumnProperty(fColumn.AddAndMakeUniqueName(FromVarString(Data)))^ do begin
      ColumnType := TSQLDBFieldType(Data^);

      inc(Data);
      ColumnValueDBSize := FromVarUInt32(Data);
    end;
    if fColumnCount=0 then
      exit; // no data returned
    if (fColumnCount>sizeof(TSQLDBProxyStatementColumns)shl 3) or
       (cardinal(fDataRowCount)>=cardinal(DataLen) div cardinal(fColumnCount)) then
      break;
    fDataRowReaderOrigin := Data;
    fDataRowReader := Data;
    fDataRowNullSize := ((fColumnCount-1) shr 3)+1;
    SetLength(fDataCurrentRowValues,fColumnCount);
    exit;
  until false;
  fDataRowCount := 0;
  fColumnCount := 0;
  raise ESQLDBException.CreateUTF8('Invalid %.IntHeaderProcess',[self]);
end;

procedure TSQLDBProxyStatementAbstract.IntFillDataCurrent(var Reader: PByte);
var F, Len: Integer;
begin
  if fDataCurrentRowNullLen>0 then
    FillChar(fDataCurrentRowNull,fDataCurrentRowNullLen,0);
  fDataCurrentRowNullLen := FromVarUInt32(Reader);
  if fDataCurrentRowNullLen>fDataRowNullSize then
    raise ESQLDBException.CreateUTF8('Invalid %.IntFillDataCurrent',[self]);
  if fDataCurrentRowNullLen>0 then begin
    Move(Reader^,fDataCurrentRowNull,fDataCurrentRowNullLen);
    inc(Reader,fDataCurrentRowNullLen);
  end;
  fDataCurrentRowValuesStart := Reader;
  for F := 0 to fColumnCount-1 do
    if F in fDataCurrentRowNull then
      fDataCurrentRowValues[F] := nil else begin





      fDataCurrentRowValues[F] := Reader;
      with fColumns[F] do
      case ColumnType of

      ftInt64:
        Reader := GotoNextVarInt(Reader);
      ftDouble, ftCurrency, ftDate:
        inc(Reader,SizeOf(Int64));
      ftUTF8, ftBlob: begin
        Len := FromVarUInt32(Reader);
        if Len>ColumnDataSize then
          ColumnDataSize := Len;
        inc(Reader,Len); // jump string/blob content
      end;
      else raise ESQLDBException.CreateUTF8('%.IntStep: Invalid ColumnType(%)=%',
        [self,ColumnName,ord(ColumnType)]);
      end;
    end;
  fDataCurrentRowValuesSize := PtrUInt(Reader)-PtrUInt(fDataCurrentRowValuesStart);
end;

procedure TSQLDBProxyStatementAbstract.ColumnsToJSON(WR: TJSONWriter);
var col, DataLen: integer;
................................................................................
    Data: PByte;
begin
  if WR.Expand then
    WR.Add('{');
  for col := 0 to fColumnCount-1 do begin
    if WR.Expand then
      WR.AddFieldName(fColumns[col].ColumnName); // add '"ColumnName":'
    Data := fDataCurrentRowValues[col];
    if Data=nil then
      WR.AddShort('null') else
    case fColumns[col].ColumnType of
      ftInt64:
        WR.Add(FromVarInt64Value(Data));
      ftDouble:
        WR.Add(PDouble(Data)^);
      ftCurrency:
        WR.AddCurr64(PInt64(Data)^);
      ftDate: begin
................................................................................
      ftUTF8: begin
        WR.Add('"');
        DataLen := FromVarUInt32(Data);
        WR.AddJSONEscape(Data,DataLen);
        WR.Add('"');
      end;
      ftBlob:
        if fForceBlobAsNull then
          WR.AddShort('null') else begin
          // WrBase64(..,withMagic=true)
          DataLen := FromVarUInt32(Data);
          WR.WrBase64(PAnsiChar(Data),DataLen,true);
        end;
    end;
    WR.Add(',');
  end;
  WR.CancelLastComma; // cancel last ','
  if WR.Expand then
    WR.Add('}');
end;
................................................................................
begin
  if (fDataRowCount>0) and (cardinal(Col)<cardinal(fColumnCount)) then
    if Col in fDataCurrentRowNull then
      result := ftNull else
      with fColumns[Col] do begin
        if FieldSize<>nil then
          FieldSize^ := ColumnDataSize; // true max size as computed at loading 
        result := ColumnType;
      end else
    raise ESQLDBException.CreateUTF8('Invalid %.ColumnType()',[self]);
end;

function TSQLDBProxyStatementAbstract.IntColumnType(Col: integer; out Data: PByte): TSQLDBFieldType;
begin
  if (cardinal(Col)>=cardinal(fColumnCount)) or (fDataCurrentRowValues=nil) then
    result := ftUnknown else begin
    Data := fDataCurrentRowValues[Col];
    if Data=nil then
      result := ftNull else
      result := fColumns[Col].ColumnType;
  end;
end;

function TSQLDBProxyStatementAbstract.ColumnCurrency(Col: integer): currency;
var Data: PByte;
begin
  case IntColumnType(Col,Data) of






|

|



>
>







 







>


|
|
>
>
>
>
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>

>













>



>

>
|

<
<





|







 







>







 







|











|
>
>
>


>











<








|
|













>
>
>
>
>

<
<
>






|
|



|







 







|


|







 







|
|
|
|
|
|







 







|











|







2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
....
6136
6137
6138
6139
6140
6141
6142
6143
6144
6145
6146
6147
6148
6149
6150
6151
6152
6153
6154
6155
6156
6157
6158
6159
6160
6161
6162
6163
6164
6165
6166
6167
6168
6169
6170
6171

6172
6173
6174
6175
6176
6177
6178
6179
6180
6181
6182
6183
6184
6185
6186
6187
6188
6189
6190
6191
6192
6193
6194
6195
6196


6197
6198
6199
6200
6201
6202
6203
6204
6205
6206
6207
6208
6209
....
6231
6232
6233
6234
6235
6236
6237
6238
6239
6240
6241
6242
6243
6244
6245
....
7223
7224
7225
7226
7227
7228
7229
7230
7231
7232
7233
7234
7235
7236
7237
7238
7239
7240
7241
7242
7243
7244
7245
7246
7247
7248
7249
7250
7251
7252
7253
7254
7255
7256
7257
7258
7259

7260
7261
7262
7263
7264
7265
7266
7267
7268
7269
7270
7271
7272
7273
7274
7275
7276
7277
7278
7279
7280
7281
7282
7283
7284
7285
7286
7287
7288


7289
7290
7291
7292
7293
7294
7295
7296
7297
7298
7299
7300
7301
7302
7303
7304
7305
7306
7307
7308
....
7309
7310
7311
7312
7313
7314
7315
7316
7317
7318
7319
7320
7321
7322
7323
7324
7325
7326
....
7331
7332
7333
7334
7335
7336
7337
7338
7339
7340
7341
7342
7343
7344
7345
7346
7347
7348
7349
7350
....
7366
7367
7368
7369
7370
7371
7372
7373
7374
7375
7376
7377
7378
7379
7380
7381
7382
7383
7384
7385
7386
7387
7388
7389
7390
7391
7392
  // - will handle an internal binary buffer when the statement returned rows
  // data, as generated by TSQLDBStatement.FetchAllToBinary()
  TSQLDBProxyStatementAbstract = class(TSQLDBStatementWithParamsAndColumns)
  protected
    fDataRowCount: integer;
    fDataRowReaderOrigin, fDataRowReader: PByte;
    fDataRowNullSize: cardinal;
    fDataCurrentRowNullLen: cardinal;
    fDataCurrentRowNull: TSQLDBProxyStatementColumns;
    fDataCurrentRowIndex: integer;
    fDataCurrentRowValues: array of pointer;
    fDataCurrentRowValuesStart: pointer;
    fDataCurrentRowValuesSize: Cardinal;
    // per-row column type (SQLite3 only) e.g. select coalesce(column,0) from ..
    fDataCurrentRowColTypes: array of TSQLDBFieldType;
    function IntColumnType(Col: integer; out Data: PByte): TSQLDBFieldType;
      {$ifdef HASINLINE}inline;{$endif}
    procedure IntHeaderProcess(Data: PByte; DataLen: integer);
    procedure IntFillDataCurrent(var Reader: PByte);
  public
    /// the Column type of the current Row
    function ColumnType(Col: integer; FieldSize: PInteger=nil): TSQLDBFieldType; override;
................................................................................

procedure TSQLDBStatement.ColumnsToBinary(W: TFileBufferWriter;
  const Null: TSQLDBProxyStatementColumns; const ColTypes: TSQLDBFieldTypeDynArray);
var F: integer;
    VDouble: double;
    VCurrency: currency absolute VDouble;
    VDateTime: TDateTime absolute VDouble;
    colType: TSQLDBFieldType;
begin
  for F := 0 to length(ColTypes)-1 do
    if not (F in Null) then begin
      colType := ColTypes[F];
      if colType<ftInt64 then begin
        colType := ColumnType(F); // per-row column type (SQLite3 only)
        W.Write1(ord(colType));
      end;
      case colType of
      ftInt64:
        W.WriteVarInt64(ColumnInt(F));
      ftDouble: begin
        VDouble := ColumnDouble(F);
        W.Write(@VDouble,sizeof(VDouble));
      end;
      ftCurrency: begin
        VCurrency := ColumnCurrency(F);
        W.Write(@VCurrency,sizeof(VCurrency));
      end;
      ftDate: begin
        VDateTime := ColumnDateTime(F);
        W.Write(@VDateTime,sizeof(VDateTime));
      end;
      ftUTF8:
        W.Write(ColumnUTF8(F));
      ftBlob:
        W.Write(ColumnBlob(F));
      else raise ESQLDBException.CreateUTF8('%.ColumnsToBinary: Invalid ColumnType(%)=%',

        [self,ColumnName(F),ord(colType)]);
    end;
  end;
end;

const
  FETCHALLTOBINARY_MAGIC = 1;

function TSQLDBStatement.FetchAllToBinary(Dest: TStream; MaxRowCount: cardinal;
  DataRowPosition: PCardinalDynArray): cardinal;
var F, FMax, FieldSize, NullRowSize: integer;
    StartPos: cardinal;
    Null: TSQLDBProxyStatementColumns;
    W: TFileBufferWriter;
    ColTypes: TSQLDBFieldTypeDynArray;
begin
  FillChar(Null,sizeof(Null),0);
  result := 0;
  W := TFileBufferWriter.Create(Dest);
  try
    W.WriteVarUInt32(FETCHALLTOBINARY_MAGIC);
    FMax := ColumnCount;
    W.WriteVarUInt32(FMax);
    if FMax>0 then begin
      // write column description


      SetLength(ColTypes,FMax);
      dec(FMax);
      for F := 0 to FMax do begin
        W.Write(ColumnName(F));
        ColTypes[F] := ColumnType(F,@FieldSize);
        W.Write1(ord(ColTypes[F]));
        W.WriteVarUInt32(FieldSize);
      end;
      // initialize null handling
      NullRowSize := (FMax shr 3)+1;
      if NullRowSize>sizeof(Null) then
        raise ESQLDBException.CreateUTF8('%.FetchAllToBinary: too many columns',[self]);
      // save all data rows
................................................................................
          W.Write(@Null,NullRowSize);
        // then write data values
        ColumnsToBinary(W,Null,ColTypes);
        inc(result);
        if (MaxRowCount>0) and (result>=MaxRowCount) then
          break;
      until not Step;
    end;
    W.Write(@result,SizeOf(result)); // fixed size at the end for row count
    W.Flush;
  finally
    W.Free;
  end;
end;

................................................................................
  fProxy.Process(cStartTransaction,self,self);
end;


{ TSQLDBProxyStatementAbstract }

procedure TSQLDBProxyStatementAbstract.IntHeaderProcess(Data: PByte; DataLen: integer);
var Magic,F,colCount: integer;
begin
  fDataCurrentRowValuesStart := nil;
  fDataCurrentRowValuesSize := 0;
  fDataCurrentRowIndex := -1;
  repeat
    if DataLen<=5 then
      break;
    fDataRowCount := PInteger(PtrInt(Data)+DataLen-sizeof(Integer))^;
    Magic := FromVarUInt32(Data);
    if Magic<>FETCHALLTOBINARY_MAGIC then
      break;
    colCount := FromVarUInt32(Data);
    SetLength(fDataCurrentRowColTypes,colCount);
    SetLength(fDataCurrentRowValues,colCount);
    for F := 0 to colCount-1 do
    with PSQLDBColumnProperty(fColumn.AddAndMakeUniqueName(FromVarString(Data)))^ do begin
      ColumnType := TSQLDBFieldType(Data^);
      fDataCurrentRowColTypes[F] := ColumnType; 
      inc(Data);
      ColumnValueDBSize := FromVarUInt32(Data);
    end;
    if fColumnCount=0 then
      exit; // no data returned
    if (fColumnCount>sizeof(TSQLDBProxyStatementColumns)shl 3) or
       (cardinal(fDataRowCount)>=cardinal(DataLen) div cardinal(fColumnCount)) then
      break;
    fDataRowReaderOrigin := Data;
    fDataRowReader := Data;
    fDataRowNullSize := ((fColumnCount-1) shr 3)+1;

    exit;
  until false;
  fDataRowCount := 0;
  fColumnCount := 0;
  raise ESQLDBException.CreateUTF8('Invalid %.IntHeaderProcess',[self]);
end;

procedure TSQLDBProxyStatementAbstract.IntFillDataCurrent(var Reader: PByte);
var F,Len: Integer;
begin // format match TSQLDBStatement.FetchAllToBinary()
  if fDataCurrentRowNullLen>0 then
    FillChar(fDataCurrentRowNull,fDataCurrentRowNullLen,0);
  fDataCurrentRowNullLen := FromVarUInt32(Reader);
  if fDataCurrentRowNullLen>fDataRowNullSize then
    raise ESQLDBException.CreateUTF8('Invalid %.IntFillDataCurrent',[self]);
  if fDataCurrentRowNullLen>0 then begin
    Move(Reader^,fDataCurrentRowNull,fDataCurrentRowNullLen);
    inc(Reader,fDataCurrentRowNullLen);
  end;
  fDataCurrentRowValuesStart := Reader;
  for F := 0 to fColumnCount-1 do
    if F in fDataCurrentRowNull then
      fDataCurrentRowValues[F] := nil else begin
      fDataCurrentRowColTypes[F] := fColumns[F].ColumnType;
      if fDataCurrentRowColTypes[F]<ftInt64 then begin
        fDataCurrentRowColTypes[F] := TSQLDBFieldType(Reader^);
        inc(Reader);
      end;
      fDataCurrentRowValues[F] := Reader;


      case fDataCurrentRowColTypes[F] of
      ftInt64:
        Reader := GotoNextVarInt(Reader);
      ftDouble, ftCurrency, ftDate:
        inc(Reader,SizeOf(Int64));
      ftUTF8, ftBlob: begin
        Len := FromVarUInt32(Reader);
        if Len>fColumns[F].ColumnDataSize then
          fColumns[F].ColumnDataSize := Len;
        inc(Reader,Len); // jump string/blob content
      end;
      else raise ESQLDBException.CreateUTF8('%.IntStep: Invalid ColumnType(%)=%',
        [self,fColumns[F].ColumnName,ord(fDataCurrentRowColTypes[F])]);
      end;
    end;
  fDataCurrentRowValuesSize := PtrUInt(Reader)-PtrUInt(fDataCurrentRowValuesStart);
end;

procedure TSQLDBProxyStatementAbstract.ColumnsToJSON(WR: TJSONWriter);
var col, DataLen: integer;
................................................................................
    Data: PByte;
begin
  if WR.Expand then
    WR.Add('{');
  for col := 0 to fColumnCount-1 do begin
    if WR.Expand then
      WR.AddFieldName(fColumns[col].ColumnName); // add '"ColumnName":'
    Data := fDataCurrentRowValues[col]; 
    if Data=nil then
      WR.AddShort('null') else
    case fDataCurrentRowColTypes[col] of
      ftInt64:
        WR.Add(FromVarInt64Value(Data));
      ftDouble:
        WR.Add(PDouble(Data)^);
      ftCurrency:
        WR.AddCurr64(PInt64(Data)^);
      ftDate: begin
................................................................................
      ftUTF8: begin
        WR.Add('"');
        DataLen := FromVarUInt32(Data);
        WR.AddJSONEscape(Data,DataLen);
        WR.Add('"');
      end;
      ftBlob:
      if fForceBlobAsNull then
        WR.AddShort('null') else begin
        // WrBase64(..,withMagic=true)
        DataLen := FromVarUInt32(Data);
        WR.WrBase64(PAnsiChar(Data),DataLen,true);
      end;
    end;
    WR.Add(',');
  end;
  WR.CancelLastComma; // cancel last ','
  if WR.Expand then
    WR.Add('}');
end;
................................................................................
begin
  if (fDataRowCount>0) and (cardinal(Col)<cardinal(fColumnCount)) then
    if Col in fDataCurrentRowNull then
      result := ftNull else
      with fColumns[Col] do begin
        if FieldSize<>nil then
          FieldSize^ := ColumnDataSize; // true max size as computed at loading 
        result := fDataCurrentRowColTypes[Col]; // per-row column type (SQLite3)
      end else
    raise ESQLDBException.CreateUTF8('Invalid %.ColumnType()',[self]);
end;

function TSQLDBProxyStatementAbstract.IntColumnType(Col: integer; out Data: PByte): TSQLDBFieldType;
begin
  if (cardinal(Col)>=cardinal(fColumnCount)) or (fDataCurrentRowValues=nil) then
    result := ftUnknown else begin
    Data := fDataCurrentRowValues[Col];
    if Data=nil then
      result := ftNull else
      result := fDataCurrentRowColTypes[Col]; // per-row column type (SQLite3)
  end;
end;

function TSQLDBProxyStatementAbstract.ColumnCurrency(Col: integer): currency;
var Data: PByte;
begin
  case IntColumnType(Col,Data) of

Changes to SynopseCommit.inc.

1
'1.18.553'
|
1
'1.18.554'