从其它平台迁移而来


在从数据库中查询数据时,有时需要事先取得字段内容的大小,再根据情况进行处理。

对于ADO之类返回TField类型的,可以使用DataSize属性,但是!!!这里有很深的坑!!!

首先看如下代码:

1
2
3
4
if ADOQuery.FieldByName('Test').DataSize > 3 then
  {处理1}
else
  {处理2};

按预想,当Test字段里的数据超过3B时,应该执行处理1的代码,但事实上无论该内容长短,都是执行处理2的代码,WHY?

扒一下Delphi的源码就明白了。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
function TField.GetDataSize: Integer;
begin
  Result := 0;
end;

function TStringField.GetDataSize: Integer;
begin
  Result := Size + 1;
end;

function TWideStringField.GetDataSize: Integer;
begin
  Result := (Size + 1) * SizeOf(WideChar);
end;

function TIntegerField.GetDataSize: Integer;
begin
  Result := SizeOf(Integer);
end;

function TLongWordField.GetDataSize: Integer;
begin
  Result := SizeOf(LongWord);
end;

function TSmallintField.GetDataSize: Integer;
begin
  Result := SizeOf(SmallInt);
end;

function TShortintField.GetDataSize: Integer;
begin
  Result := SizeOf(ShortInt);
end;

function TByteField.GetDataSize: Integer;
begin
  Result := SizeOf(Byte);
end;

function TLargeintField.GetDataSize: Integer;
begin
  Result := SizeOf(Largeint);
end;

function TWordField.GetDataSize: Integer;
begin
  Result := SizeOf(Word);
end;

function TFloatField.GetDataSize: Integer;
begin
  Result := SizeOf(Double);
end;

function TSingleField.GetDataSize: Integer;
begin
  Result := SizeOf(Single);
end;

function TExtendedField.GetDataSize: Integer;
begin
  Result := SizeOf(Extended);
end;

function TBooleanField.GetDataSize: Integer;
begin
  Result := SizeOf(WordBool);
end;

function TDateTimeField.GetDataSize: Integer;
begin
  Result := SizeOf(TDateTime);
end;

function TSQLTimeStampField.GetDataSize: Integer;
begin
  Result := SizeOf(TSQLTimeStamp);
end;

function TSQLTimeStampOffsetField.GetDataSize: Integer;
begin
  Result := SizeOf(TSQLTimeStampOffset);
end;

function TDateField.GetDataSize: Integer;
begin
  Result := SizeOf(Integer);
end;

function TTimeField.GetDataSize: Integer;
begin
  Result := SizeOf(Integer);
end;

function TBytesField.GetDataSize: Integer;
begin
  Result := Size;
end;

function TVarBytesField.GetDataSize: Integer;
begin
  Result := Size + SizeOf(Word) {Length Prefix};
end;

function TBCDField.GetDataSize: Integer;
begin
  // SizeOf(TBcd) is used here instead of SizeOf(Currency) because some
  // datasets store the currency data in TBcd format in the record buffer.
  // For these classes (TBDEDataset & TClientDataset) a call to
  // TField.GetData(Buffer, True) will return a TBcd.
  Result := SizeOf(TBcd);
end;

function TFMTBCDField.GetDataSize: Integer;
begin
  Result := SizeOf(TBcd);
end;

function TBlobField.GetDataSize: Integer;
begin
  // Blob data is not stored in the record buffer and can not be read
  // with a call to TField.GetData. Use GetBlobSize instead.
  Result := 0;
end;

function TReferenceField.GetDataSize: Integer;
begin
  Result := FSize + 2;
end;

也就是说,不能直接取DataSize,而是需要转换为实际的类型后再取DataSize,而且TBlobField是特例,需要使用TBlobField.BlobSize。那么,刚才的例子应该这样写(假设字段类型是Blob):

1
2
3
4
if TBlobField(ADOQuery.FieldByName('Test')).BlobSize > 3 then
  {处理1}
else
  {处理2};