TZArray),{$IFDEF ZEOS90UP}SizeOf(Pointer), SizeOf(Pointer){$ELSE}SizeOf(Pointer){$ENDIF}
  );

const ZDataIncompatibilityMatrix: array[TZSQLType] of set of TZSQLType = (
  {stUnknown}   [Low(TZSQLType)..High(TZSQLType)],
  {stBoolean}   [stDate, stTime, stTimestamp, stGUID, stBytes, stBinaryStream, stArray],
  {stByte}      [stDate, stTime, stTimestamp, stGUID, stBytes, stBinaryStream, stArray],
  {stshort}     [stDate, stTime, stTimestamp, stGUID, stBytes, stBinaryStream, stArray],
  {stWord}      [stDate, stTime, stTimestamp, stGUID, stBytes, stBinaryStream, stArray],
  {stSmall}     [stDate, stTime, stTimestamp, stGUID, stBytes, stBinaryStream, stArray],
  {stLongWord}  [stDate, stTime, stTimestamp, stGUID, stBytes, stBinaryStream, stArray],
  {stInteger}   [stDate, stTime, stTimestamp, stGUID, stBytes, stBinaryStream, stArray],
  {stULong}     [stDate, stTime, stTimestamp, stGUID, stBytes, stBinaryStream, stArray],
  {stLong}      [stDate, stTime, stTimestamp, stGUID, stBytes, stBinaryStream, stArray],
  {stFloat}     [stGUID, stBytes, stBinaryStream, stArray],
  {stDouble}    [stGUID, stBytes, stBinaryStream, stArray],
  {stCurrency}  [stDate, stTime, stTimestamp, stGUID, stBytes, stBinaryStream, stArray],
  {stBigDecimal}[stDate, stTime, stTimestamp, stGUID, stBytes, stBinaryStream, stArray],
  {stDate}      [stBoolean..stLong, stCurrency, stBigDecimal, stBytes, stBinaryStream, stArray],
  {stTime}      [stBoolean..stLong, stCurrency, stBigDecimal, stBytes, stBinaryStream, stArray],
  {stTimestamp} [stBoolean..stLong, stCurrency, stBigDecimal, stBytes, stBinaryStream, stArray],
  {stGUID}      [stBoolean..stTimestamp],
  {stString}    [],
  {stUnicodeString} [],
  {stBytes}     [stBoolean..stTimestamp, stUnicodeString, stUnicodeStream],
  {stAsciiStream} [stBoolean..stTimestamp],
  {stUnicodeStream} [stBoolean..stTimestamp],
  {stBinaryStream}  [stBoolean..stTimestamp, stUnicodeString, stUnicodeStream],
  {$IFDEF ZEOS90UP}
  SizeOf(Pointer), SizeOf(Pointer), SizeOf(Variant),
  {$ENDIF ZEOS90UP}
  {stArray}     [Low(TZSQLType)..High(TZSQLType)],
  {$IFDEF ZEOS90UP}SizeOf(Pointer), SizeOf(Pointer){$ELSE}[Low(TZSQLType)..High(TZSQLType)]{$ENDIF}
  );

function GetDefaultCharacterFieldType(Self: TZParam): TZControlsCodePage;
begin
  with Self do
    if ((fConnection <> nil) or TrySetConnection)
    then Result := TZAbstractConnection(fConnection).ControlsCodePage
    else Result :=
    {$IFDEF UNICODE}
      cCP_UTF16
    {$ELSE}
      {$IFDEF FPC}
        {$IFDEF LCL}
          cCP_UTF8
        {$ELSE LCL}
          cGET_ACP
        {$ENDIF LCL}
      {$ELSE FPC}
        cGET_ACP
      {$ENDIF FPC}
    {$ENDIF UNICODE};
end;

{ TZParam }

procedure TZParam.Assign(Source: TPersistent);
var
  StreamPersist: IStreamPersist;
  procedure LoadFromStreamPersist(const StreamPersist: IStreamPersist);
  var
    MS: TMemoryStream;
  begin
    MS := TMemoryStream.Create;
    try
      StreamPersist.SaveToStream(MS);
      LoadBinaryFromStream(MS);
    finally
      MS.Free;
    end;
  end;
  procedure LoadFromStrings(Source: TSTrings);
  begin
    AsMemo := Source.Text;
  end;
begin
  if Source = nil then Exit;
  if Source is TZParam then
    AssignParam(TZParam(Source))
  else if Source is TParam then
    AssignParam(TParam(Source))
  else if Source is TField then
    AssignField(TField(Source))
  else if Source is TStrings then
    LoadFromStrings(TStrings(Source))
  else if Supports(Source, IStreamPersist, StreamPersist) then
    LoadFromStreamPersist(StreamPersist)
  else
    inherited Assign(Source);
end;

procedure TZParam.AssignField(Field: TField);
  procedure MoveUnicodeStrings;
  begin
    {$IFDEF WITH_WIDEMEMO}
    if Field.DataType = ftWideMemo then
      {$IFDEF WITH_VIRTUAL_TFIELD_ASUNICODESTRING}
      SetAsWideMemo(Field.AsUnicodeString)
      {$ELSE}
      SetAsWideMemo(Field.AsWideString)
      {$ENDIF}
    else
    {$ENDIF}
      {$IFDEF WITH_VIRTUAL_TFIELD_ASUNICODESTRING}
      SetAsUnicodeString(Field.AsUnicodeString);
      {$ELSE}
        {$IFNDEF WITH_WIDEMEMO}
      SetAsUnicodeString(TWideStringField(Field).Value);
        {$ELSE}
      SetAsUnicodeString(Field.AsWideString);
        {$ENDIF}
      {$ENDIF}
  end;
  procedure MoveTBytes;
  begin
    if Field.DataType in [ftBytes, ftVarBytes] then
      {$IFDEF TFIELD_HAS_ASBYTES}
      SetAsBytes(Field.AsBytes)
      {$ELSE}
      SetAsBytes(VarToBytes(Field.Value))
      {$ENDIF}
    else
      {$IFDEF TBLOBDATA_IS_TBYTES}
      SetAsBlob(TBlobField(Field).AsBytes);
      {$ELSE}
      SetAsBlob(TBlobField(Field).Value);
      {$ENDIF}
  end;
  procedure MoveRawStrings;
  var CP: Word;
  begin
    if Field is TZRawCLobField then begin
      CP := TZRawCLobField(Field).CodePage;
      if CP = zCP_UTF16
      then SetAsWideMemo(TZRawCLobField(Field).AsUnicodeString)
      else SetAsRawMemo(TZRawCLobField(Field).AsRawByteString, CP);
    end else if Field is TZRawStringField then begin
      CP := TZRawStringField(Field).CodePage;
      if CP = zCP_UTF16
      then SetAsUnicodeString(TZRawStringField(Field).AsUnicodeString)
      else SetAsRawByteString(TZRawStringField(Field).AsRawByteString, TZRawStringField(Field).CodePage);
    end else if Field is TMemoField then
      SetAsMemo(Field.AsString)
    else {$IFDEF UNICODE}SetAsUnicodeString{$ELSE}SetAsString{$ENDIF}(Field.AsString);
  end;
begin
  if Field <> nil then
    case Field.DataType of
      //ftUnknown: ;
      ftString:     MoveRawStrings;
      ftSmallint:   {$IFNDEF WITH_FTSHORTINT}
                    if Field is TZShortIntField
                    then SetAsShortInt(TZShortIntField(Field).Value)
                    else {$ENDIF}SetAsSmallInt(SmallInt(Field.AsInteger));
      ftInteger:    SetAsInteger(Field.AsInteger);
      ftWord:       {$IFNDEF WITH_FTBYTE}
                    if Field is TZByteField
                    then SetAsByte(Field.AsInteger)
                    else {$ENDIF}SetAsWord(Word(Field.AsInteger));
      ftBoolean:    SetAsBoolean(Field.AsBoolean);