Skip to content

Commit

Permalink
introducing TSqlDBPostgresConnectionProperties.ArrayParamsAsBinary
Browse files Browse the repository at this point in the history
- but binary binding seems not really faster than text binding
  • Loading branch information
Arnaud Bouchez committed May 12, 2023
1 parent 2c42ec0 commit fa3cd43
Show file tree
Hide file tree
Showing 4 changed files with 177 additions and 51 deletions.
21 changes: 10 additions & 11 deletions ex/techempower-bench/raw.pas
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ TRawAsyncServer = class(TSynPersistent)
WORLD_COUNT = 10000;
WORLD_READ_SQL = 'select id,randomNumber from World where id=?';
WORLD_UPDATE_SQLN = 'update World as t set randomNumber = v.r from ' +
'(SELECT unnest(?::bigint[]), unnest(?::bigint[]) order by 1) as v(id, r)' +
'(SELECT unnest(?::integer[]), unnest(?::integer[]) order by 1) as v(id, r)' +
' where t.id = v.id';
FORTUNES_SQL = 'select id,message from Fortune';

Expand Down Expand Up @@ -189,6 +189,7 @@ constructor TRawAsyncServer.Create(
{$else}
fDbPool := TSqlDBPostgresConnectionProperties.Create(
'tfb-database:5432', 'hello_world', 'benchmarkdbuser', 'benchmarkdbpass');
// fDbPool.ArrayParamsAsBinary := true; // seems not really faster
{$endif USE_SQLITE3}
// customize JSON serialization for TFB expectations
TOrmWorld.OrmProps.Fields.JsonRenameProperties([
Expand Down Expand Up @@ -593,7 +594,7 @@ function TRawAsyncServer.rawupdates(ctxt: THttpServerRequest): cardinal;
var
cnt, i: PtrInt;
res: TWorlds;
ids, nums: TInt64DynArray;
params: TInt64DynArray;
conn: TSqlDBConnection;
stmt: ISqlDBStatement;
begin
Expand All @@ -608,16 +609,14 @@ function TRawAsyncServer.rawupdates(ctxt: THttpServerRequest): cardinal;
if cnt > 20 then
begin
// fill parameters arrays for update with nested select (PostgreSQL only)
setLength(ids{%H-}, cnt);
setLength(nums{%H-}, cnt);
for i := 0 to cnt - 1 do
begin
ids[i] := res[i].id;
nums[i] := res[i].randomNumber;
end;
stmt := conn.NewStatementPrepared(WORLD_UPDATE_SQLN, false, true);
stmt.BindArray(1, ids);
stmt.BindArray(2, nums);
SetLength(params{%H-}, cnt);
for i := 0 to cnt - 1 do
params[i] := res[i].id;
stmt.BindArray(1, params);
for i := 0 to cnt - 1 do
params[i] := res[i].randomNumber;
stmt.BindArray(2, params);
end
else
begin
Expand Down
127 changes: 104 additions & 23 deletions src/db/mormot.db.raw.postgres.pas
Original file line number Diff line number Diff line change
Expand Up @@ -37,68 +37,66 @@ interface
// see pg_type.h
BOOLOID = 16;
BYTEAOID = 17;
CHAROID = 18;
NAMEOID = 19;
INT8OID = 20;
INT2OID = 21;
INT2VECTOROID = 22;
INT4OID = 23;
REGPROCOID = 24;
TEXTOID = 25;
OIDOID = 26;
FLOAT4OID = 700;
FLOAT8OID = 701;
ABSTIMEOID = 702;
CASHOID = 790;
DATEOID = 1082;
TIMEOID = 1083;
TIMESTAMPOID = 1114;
TIMESTAMPTZOID = 1184;
TIMETZOID = 1266;
NUMERICOID = 1700;

CHAROID = 18;
NAMEOID = 19;
INT2VECTOROID = 22;
TIDOID = 27;
XIDOID = 28;
CIDOID = 29;
OIDVECTOROID = 30;
PGDDLCOMMANDOID = 32;
JSONOID = 114;
XMLOID = 142;
PGNODETREEOID = 194;
PGDDLCOMMANDOID = 32;
POINTOID= 600;
LSEGOID = 601;
PATHOID = 602;
BOXOID = 603;
POLYGONOID = 604;
LINEOID = 628;
CIDROID = 650;
FLOAT4OID = 700;
FLOAT8OID = 701;
ABSTIMEOID = 702;
RELTIMEOID = 703;
TINTERVALOID = 704;
UNKNOWNOID = 705;
CIRCLEOID = 718;
CASHOID = 790;
MACADDROID = 829;
INETOID = 869;
CIDROID = 650;
INT2ARRAYOID = 1005;
INT4ARRAYOID = 1007;
TEXTARRAYOID = 1009;
INT8ARRAYOID = 1016;
TEXTARRAYOID= 1009;
OIDARRAYOID = 1028;
FLOAT4ARRAYOID = 1021;
FLOAT8ARRAYOID = 1022;
OIDARRAYOID = 1028;
ACLITEMOID = 1033;
CSTRINGARRAYOID = 1263;
BPCHAROID = 1042;
VARCHAROID = 1043;
DATEOID = 1082;
TIMEOID = 1083;
TIMESTAMPOID = 1114;
TIMESTAMPTZOID = 1184;
INTERVALOID = 1186;
CSTRINGARRAYOID = 1263;
TIMETZOID = 1266;
BITOID = 1560;
VARBITOID = 1562;
REFCURSOROID= 1790;
NUMERICOID = 1700;
REFCURSOROID = 1790;
REGPROCEDUREOID = 2202;
REGOPEROID = 2203;
REGOPERATOROID = 2204;
REGCLASSOID = 2205;
REGTYPEOID = 2206;
REGROLEOID = 4096;
REGNAMESPACEOID = 4089;
REGTYPEARRAYOID = 2211;
UUIDOID = 2950;
LSNOID = 3220;
Expand All @@ -108,7 +106,9 @@ interface
REGCONFIGOID = 3734;
REGDICTIONARYOID = 3769;
JSONBOID = 3802;
INT4RANGEOID = 3904;
INT4RANGEOID = 3904;
REGNAMESPACEOID = 4089;
REGROLEOID = 4096;

const
PGRES_EMPTY_QUERY = 0;
Expand Down Expand Up @@ -139,6 +139,11 @@ interface
PGFMT_TEXT = 0;
PGFMT_BIN = 1;

/// compute the PostgreSQL raw binary to encode an array of (integer) parameters
function ToArrayOid(Values: PByte; ArrayOid, ValueCount, ValueSize: integer;
var Bin: RawByteString): boolean;



{ ************ PostgreSQL Client Library Loading }

Expand Down Expand Up @@ -240,6 +245,82 @@ procedure PostgresLibraryInitialize;

implementation


{ ************ Native PostgreSQL Client Library Constants }

// see https://stackoverflow.com/a/66499392/458259

function ToArrayOid(Values: PByte; ArrayOid, ValueCount, ValueSize: integer;
var Bin: RawByteString): boolean;
var
len: PtrInt;
v: Int64;
p: PCardinal;
begin
result := false;
if (ValueCount <= 0) or
not (ValueSize in [4, 8]) then
exit;
case ArrayOid of
INT4ARRAYOID:
begin
ArrayOid := INT4OID;
len := (5 * 4) + ValueCount * (4 + 4);
end;
INT8ARRAYOID:
begin
ArrayOid := INT8OID;
len := (5 * 4) + ValueCount * (4 + 8);
end;
else
exit; // unsupported
end;
FastSetRawByteString(Bin, nil, len);
p := pointer(Bin);
p^ := $01000000; // dimensions
inc(p);
p^ := $00000000; // has null
inc(p);
p^ := bswap32(ArrayOid); // items type
inc(p);
p^ := bswap32(ValueCount); // items count
inc(p);
p^ := $01000000; // offset
inc(p);
if ArrayOid = INT4OID then
repeat
p^ := $04000000; // item length
inc(p);
p^ := bswap32(PCardinal(Values)^); // item value (maybe truncated)
inc(p);
inc(Values, ValueSize);
dec(ValueCount)
until ValueCount = 0
else if ValueSize = 4 then
repeat
p^ := $08000000; // item length
inc(p);
v := PInteger(Values)^; // expand sign to 64-bit
PInt64(p)^ := bswap64(v); // item value
inc(PInt64(p));
inc(PInteger(Values));
dec(ValueCount)
until ValueCount = 0
else // ValueSize = 8
repeat
p^ := $08000000;
inc(p);
PInt64(p)^ := bswap64(PInt64(Values)^);
inc(PInt64(p));
inc(PInt64(Values));
dec(ValueCount)
until ValueCount = 0;
//if PAnsiChar(p) - pointer(Bin) <> length(Bin) then
// raise ESqlDBPostgres.Create('ToIntArrayOid');
result := true;
end;


{ ************ PostgreSQL Client Library Loading }

const
Expand Down
Loading

0 comments on commit fa3cd43

Please sign in to comment.