Browse Source

fcl-db: odbc: add support for ftFmtBCD parameters. Bind them as string to support BCD values with precision > 10^38 (max.supported by SQL_NUMERIC_STRUCT)

git-svn-id: trunk@29764 -
lacak 10 years ago
parent
commit
0182f49b7b
1 changed files with 84 additions and 3 deletions
  1. 84 3
      packages/fcl-db/src/sqldb/odbc/odbcconn.pas

+ 84 - 3
packages/fcl-db/src/sqldb/odbc/odbcconn.pas

@@ -60,6 +60,7 @@ type
       TDBMSInfo = record
         GetLastInsertIDSQL: string; // SQL statement for get last insert value for autoincrement column
       end;
+
     var
       FDriver: string;
       FEnvironment:TODBCEnvironment;
@@ -312,6 +313,74 @@ begin
   end;
 end;
 
+(*
+function BCDToNumericStruct(const bcd: TBCD): SQL_NUMERIC_STRUCT;
+var i, j, p: integer;
+    nibble: Byte;
+    a, m, carry: DWord;
+    BigInt: array[0..3] of QWord;
+    qw: QWord;
+    pdw: PDWord;
+begin
+  Result.precision := BCDPrecision(bcd);
+  if Result.precision = 0 then Result.precision := 1; // if bcd is NULL
+  Result.scale := BCDScale(bcd);
+  if IsBCDNegative(bcd) then
+    Result.sign := 0
+  else
+    Result.sign := 1;
+  // BigInt := 0
+  FillByte(BigInt, sizeof(BigInt), 0);
+  // process BCD nibbles (high nibble is at 0)
+  p := Result.precision;
+  i := 0;
+  while p > 0 do
+  begin
+    nibble := bcd.Fraction[i];
+    if p = 1 then
+      begin
+      a := nibble shr 4;
+      m := 10;
+      end
+    else
+      begin
+      a := (nibble shr 4)*10 + nibble and $0F;
+      m := 100;
+      end;
+
+    // BigInt := BigInt * m + a
+    // big multiplication
+    j := 0; carry := 0;
+    repeat
+      qw := BigInt[j] * m + carry;
+      BigInt[j] := qw and $FFFFFFFF;
+      carry := qw shr 32;
+      inc(j);
+    until j>high(BigInt);
+
+    // big addition
+    j := 0; carry := 0;
+    repeat
+      qw := BigInt[j] + a + carry;
+      BigInt[j] := qw and $FFFFFFFF;
+      carry := qw shr 32;
+      inc(j);
+    until (carry = 0) or (j>high(BigInt));
+
+    dec(p,2);
+    inc(i);
+  end;
+
+  // SQL_NUMERIC_STRUCT.val size must be 16 bytes (128bit integer)
+  pdw := @Result.val;
+  for j:=0 to high(BigInt) do
+    begin
+    pdw^ := NtoLE(BigInt[j]);
+    inc(pdw);
+    end;
+end;
+*)
+
 procedure TODBCConnection.SetParameters(ODBCCursor: TODBCCursor; AParams: TParams);
 var
   ParamIndex: integer;
@@ -319,7 +388,7 @@ var
   I, Size: integer;
   IntVal: clong;
   LargeVal: clonglong;
-  StrVal: string;
+  StrVal: ansistring;
   WideStrVal: widestring;
   FloatVal: cdouble;
   DateVal: SQL_DATE_STRUCT;
@@ -446,6 +515,18 @@ begin
           ColumnSize:=NumericVal.precision;
           DecimalDigits:=NumericVal.scale;
         end;
+      ftFmtBCD:
+        begin
+          // bind FmtBCD parameter as string to support higher precision than 10^38 (supported by SQL_NUMERIC_STRUCT)
+          StrVal:=GetAsSQLText(AParams[ParamIndex]);
+          StrLenOrInd:=Length(StrVal);
+          PVal:=@StrVal[1];
+          Size:=Length(StrVal);
+          CType:=SQL_C_CHAR;
+          SqlType:=SQL_CHAR;
+          ColumnSize:=Size;
+          BufferLength:=Size;
+        end;
       ftDate:
         begin
           DateVal:=DateTimeToDateStruct(AParams[ParamIndex].AsDate);
@@ -1053,7 +1134,7 @@ begin
   if Res<>SQL_NO_DATA then
     ODBCCheckResult(Res,SQL_HANDLE_STMT, ODBCCursor.FSTMTHandle, 'Could not fetch new row from result set.');
 
-  // result is true iff a new row was available
+  // result is true if a new row was available
   Result:=Res<>SQL_NO_DATA;
 end;
 
@@ -1382,7 +1463,7 @@ begin
                 IndexDef.Options:=IndexDef.Options+[ixDescending];
               end;
             end else if (OrdinalPos=1) or not Assigned(IndexDef) then begin
-              // create new IndexDef iff OrdinalPos=1 or not Assigned(IndexDef) (the latter should not occur though)
+              // create new IndexDef if OrdinalPos=1 or not Assigned(IndexDef) (the latter should not occur though)
               IndexDef:=IndexDefs.AddIndexDef;
               IndexDef.Name:=PChar(@IndexName[1]); // treat ansistring as zero terminated string
               IndexDef.Fields:=PChar(@ColName[1]);