Browse Source

* Length of data in binary string. First part of Mantis #20453

git-svn-id: trunk@20052 -
marco 13 years ago
parent
commit
bf67fed0cf

+ 15 - 10
packages/fcl-db/src/base/fields.inc

@@ -429,7 +429,7 @@ end;
 function TField.GetAsBytes: TBytes;
 begin
   SetLength(Result, DataSize);
-  if not GetData(@Result[0], False) then
+  if assigned(result) and not GetData(@Result[0], False) then
     Result := nil;
 end;
 
@@ -2181,14 +2181,22 @@ begin
   // Just check for really invalid stuff; actual size is
   // dependent on the record...
   If AValue<1 then
-    DatabaseErrorfmt(SInvalidFieldSize,[Avalue]);
+    DatabaseErrorFmt(SInvalidFieldSize,[AValue]);
 end;
 
 function TBinaryField.GetAsBytes: TBytes;
+var B: TBytes;
 begin
-  SetLength(Result, DataSize);
-  if not GetData(Pointer(Result), True) then
-    SetLength(Result, 0);
+  SetLength(B, DataSize);
+  if not assigned(B) or not GetData(Pointer(B), True) then
+    SetLength(Result, 0)
+  else if DataType = ftVarBytes then
+  begin
+    SetLength(Result, PWord(B)^);
+    Move(B[sizeof(Word)], Result[0], Length(Result));
+  end
+  else // ftBytes
+    Result := B;
 end;
 
 
@@ -2199,10 +2207,7 @@ begin
   if length(B) = 0 then
     Result := ''
   else
-  begin
-    SetLength(Result, length(B) div SizeOf(Char));
-    Move(B[0], Result[1], length(Result) * SizeOf(Char));
-  end;
+    SetString(Result, @B[0], length(B) div SizeOf(Char));
 end;
 
 
@@ -2246,8 +2251,8 @@ begin
     end;
 
     if DataType = ftVarBytes then begin
-      Move(AValue[0], P[2], Len);
       PWord(P)^ := Len;
+      Move(AValue[0], P[sizeof(Word)], Len);
     end
     else begin // ftBytes
       Move(AValue[0], P^, Len);

+ 22 - 10
packages/fcl-db/src/sqldb/mysql/mysqlconn.inc

@@ -55,7 +55,7 @@ Type
     FNeedData : Boolean;
     FStatement : String;
     Row : MYSQL_ROW;
-    Lengths : pculong;                { Lengths of the columns of the current row }
+    Lengths : pculong;                  { Lengths of the columns of the current row }
     RowsAffected : QWord;
     LastInsertID : QWord;
     ParamBinding : TParamBinding;
@@ -870,7 +870,7 @@ var
 begin
   Result := False;
   CreateBlob := False;
-  if Source = Nil then
+  if Source = Nil then // If the pointer is NULL, the field is NULL
     exit;
   SetString(Src, Source, Len);
   case AField^.ftype of
@@ -966,14 +966,26 @@ begin
           end;
       Writeln;
 }
-      // String-fields which can contain more then dsMaxStringSize characters
-      // are mapped to ftBlob fields, while their mysql-datatype is FIELD_TYPE_BLOB
-      if FieldDef.DataType in [ftBlob,ftMemo] then
-        CreateBlob := True
-      else if Src<> '' then
-        Move(Source^, Dest^, FieldDef.Size)
-      else
-        Dest^ := #0;
+      if Len > FieldDef.Size then
+        Len := FieldDef.Size;
+      case FieldDef.DataType of
+        // String-fields which can contain more then dsMaxStringSize characters
+        // are mapped to ftBlob fields, while their mysql-datatype is FIELD_TYPE_BLOB
+        ftBlob, ftMemo:
+          CreateBlob := True;
+        ftVarBytes:
+          begin
+          PWord(Dest)^ := Len;
+          Move(Source^, (Dest+sizeof(Word))^, Len);
+          end;
+        ftBytes:
+          Move(Source^, Dest^, Len);
+        else // ftString, ftFixedChar
+          begin
+          Move(Source^, Dest^, Len);
+          (Dest+Len)^ := #0;
+          end;
+      end;
       end;
     FIELD_TYPE_BLOB:
       CreateBlob := True;

+ 7 - 1
packages/fcl-db/src/sqldb/sqlite/sqlite3conn.pp

@@ -641,13 +641,19 @@ begin
       if int1 > 0 then
         move(sqlite3_column_text16(st,fnum)^, buffer^, int1); //Strings returned by sqlite3_column_text() and sqlite3_column_text16(), even empty strings, are always zero terminated.
       end;
+    ftVarBytes,
     ftBytes:
       begin
       int1 := sqlite3_column_bytes(st,fnum);
       if int1 > FieldDef.Size then
         int1 := FieldDef.Size;
+      if FieldDef.DataType = ftVarBytes then
+      begin
+        PWord(buffer)^ := int1;
+        inc(buffer, sizeof(Word));
+      end;
       if int1 > 0 then
-         move(sqlite3_column_blob(st,fnum)^, buffer^, int1);
+        move(sqlite3_column_blob(st,fnum)^, buffer^, int1);
       end;
     ftWideMemo,
     ftMemo,

+ 14 - 1
packages/fcl-db/tests/testfieldtypes.pas

@@ -94,6 +94,7 @@ type
     procedure TestFloatParamQuery;
     procedure TestBCDParamQuery;
     procedure TestBytesParamQuery;
+    procedure TestVarBytesParamQuery;
     procedure TestAggregates;
 
     procedure TestStringLargerThen8192;
@@ -150,7 +151,12 @@ const
   );
 
   testBytesValuesCount = 5;
-  testBytesValues : Array[0..testBytesValuesCount-1] of shortstring = (#1#0#1#0#1, #0#0#1#0#1, #0''''#13#0#1, '\'#0'"\'#13, #13#13#0#10#10);
+  testVarBytesValuesCount = 8;
+  testBytesValues : Array[0..testVarBytesValuesCount-1] of shortstring = (
+    #1#0#1#0#1, #0#0#1#0#1, #0''''#13#0#1, '\'#0'"\'#13, #13#13#0#10#10,
+    '', #0, #0#1#2#3#4#5#6#7#8#9
+  );
+
 
 procedure TTestFieldTypes.TestpfInUpdateFlag;
 var ds   : TCustomBufDataset;
@@ -801,6 +807,11 @@ begin
   TestXXParamQuery(ftBytes, FieldtypeDefinitions[ftBytes], testBytesValuesCount, true);
 end;
 
+procedure TTestFieldTypes.TestVarBytesParamQuery;
+begin
+  TestXXParamQuery(ftVarBytes, FieldtypeDefinitions[ftVarBytes], testVarBytesValuesCount);
+end;
+
 procedure TTestFieldTypes.TestStringParamQuery;
 
 begin
@@ -862,6 +873,7 @@ begin
                      Params.ParamByName('field1').Value := StringToByteArray(testBytesValues[i])
                    else
                      Params.ParamByName('field1').AsBlob := testBytesValues[i];
+        ftVarBytes:Params.ParamByName('field1').AsString := testBytesValues[i];
       else
         AssertTrue('no test for paramtype available',False);
       end;
@@ -886,6 +898,7 @@ begin
         ftDate   : AssertEquals(testDateValues[i],DateTimeToStr(FieldByName('FIELD1').AsDateTime, DBConnector.FormatSettings));
         ftDateTime : AssertEquals(testValues[ADataType,i], DateTimeToStr(FieldByName('FIELD1').AsDateTime, DBConnector.FormatSettings));
         ftFMTBcd : AssertEquals(testFmtBCDValues[i], BCDToStr(FieldByName('FIELD1').AsBCD, DBConnector.FormatSettings));
+        ftVarBytes,
         ftBytes  : AssertEquals(testBytesValues[i], shortstring(FieldByName('FIELD1').AsString));
       else
         AssertTrue('no test for paramtype available',False);