unit ABSBase;

interface

uses SysUtils, Classes,

// AbsoluteDatabase units
{$I ABSVer.inc}

     {$IFDEF DEBUG_LOG}
     ABSDebug,
     {$ENDIF}
     ABSMemory,
     ABSCompression,
     ABSSecurity,
     ABSTypes,
     ABSConverts,
     ABSTypesRoutines,
     ABSVariant,
     ABSLexer,
     ABSExcept,
     ABSConst;

type
 // Events
 TABSFilterRecord = Pointer;


type

  TABSBaseSession = class;
  TABSCursor = class;
  TABSIndexDef = class;
  TABSFieldDef = class;

  TABSFieldDefs = class;
  TABSIndexDefs = class;

  TABSCursorPos = record
   FirstPosition: Boolean;
   LastPosition:  Boolean;
   RecordID:      TABSRecordID;
  end;
  PABSCursorPos = ^TABSCursorPos;

////////////////////////////////////////////////////////////////////////////////
//
// TABSMetaObjectDef
//
////////////////////////////////////////////////////////////////////////////////


  TABSMetaObjectDef = class (TObject)
   private
    FName:       TABSObjectName;
    FObjectID:   TABSObjectID;
    FSchemaName: string;
    FSchemaID:   TABSObjectID;
   public
    constructor Create;
    procedure Assign(Source: TABSMetaObjectDef); virtual;
    procedure LoadFromStream(Stream: TStream); virtual;
    procedure SaveToStream(Stream: TStream); virtual;
   public
    property Name: TABSObjectName read FName write FName;
    property ObjectID: TABSObjectID read FObjectID write FObjectID;
    property SchemaName: string read FSchemaName write FSchemaName;
    property SchemaID: TABSObjectID read FSchemaID write FSchemaID;
  end; // TABSMetaObjectDef



////////////////////////////////////////////////////////////////////////////////
//
// TABSFieldDef
//
////////////////////////////////////////////////////////////////////////////////


  TABSFieldDef = class (TABSMetaObjectDef)
   private
    FBaseFieldType:             TABSBaseFieldType;
    FAdvancedFieldType:         TABSAdvancedFieldType;
    FFieldSize:                 Integer;
    FDiskDataSize:              Integer; // size of binary data in disk page or table file
    FMemoryDataSize:            Integer; // size of binary data in record buffer
    FDiskOffset:                Integer; // offset to binary data in disk page or table file
    FMemoryOffset:              Integer; // offset to binary data in record buffer
    FFieldNoReference:          Integer; // index of this field in TableData.FieldManager.FieldDefs

    // Default Value
    FDefaultValue:              TABSVariant;
    FDefaultValueExpr:          TObject;

    // Blob data
    FBLOBCompressionAlgorithm:  TABSCompressionAlgorithm;
    FBLOBCompressionMode:       TABSCompressionMode;
    FBLOBBlockSize:             Integer;

    // Autoinc settings
    FAutoincIncrement:    Int64;
    FAutoincInitialValue: Int64;
    FAutoincMinValue:     Int64;
    FAutoincMaxValue:     Int64;
    FAutoincCycled:       ByteBool;

   private
    procedure RecalcInternalSizes;
    procedure CreateDefaultValueExprIfNeeded;
   public
    constructor Create;
    destructor Destroy; override;
    procedure Assign(Source: TABSMetaObjectDef); override;
    procedure SetFieldDefDataType(
                                  AdvancedFieldType: TABSAdvancedFieldType;
                                  FieldSize:        Integer = 0
                                 ); overload;
    procedure SetFieldDefDataType(
                                  BaseFieldType: TABSBaseFieldType;
                                  FieldSize:        Integer = 0
                                 ); overload;

    procedure LoadFromStream(Stream: TStream); override;
    procedure SaveToStream(Stream: TStream); override;

   public
    property BaseFieldType: TABSBaseFieldType read FBaseFieldType write FBaseFieldType;
    property AdvancedFieldType: TABSAdvancedFieldType read FAdvancedFieldType write FAdvancedFieldType;
    property FieldSize: Integer read FFieldSize write FFieldSize;
    property DiskOffset: Integer read FDiskOffset write FDiskOffset;
    property MemoryOffset: Integer read FMemoryOffset write FMemoryOffset;
    property DiskDataSize: Integer read FDiskDataSize write FDiskDataSize;
    property MemoryDataSize: Integer read FMemoryDataSize write FMemoryDataSize;
    property FieldNoReference: Integer read FFieldNoReference write FFieldNoReference;

    //property DefaultValueType: TABSDefaultValueType read FDefaultValueType write FDefaultValueType;
    property DefaultValue: TABSVariant read FDefaultValue write FDefaultValue;
    property DefaultValueExpr: TObject read FDefaultValueExpr;

    property AutoincIncrement: Int64    read FAutoincIncrement  write   FAutoincIncrement;
    property AutoincInitialValue: Int64 read FAutoincInitialValue write FAutoincInitialValue;
    property AutoincMinValue:  Int64    read FAutoincMinValue   write   FAutoincMinValue;
    property AutoincMaxValue:  Int64    read FAutoincMaxValue   write   FAutoincMaxValue;
    property AutoincCycled:    ByteBool read FAutoincCycled     write   FAutoincCycled;

    property BLOBCompressionAlgorithm: TABSCompressionAlgorithm read FBLOBCompressionAlgorithm write FBLOBCompressionAlgorithm;
    property BLOBCompressionMode: TABSCompressionMode read FBLOBCompressionMode write FBLOBCompressionMode;
    property BLOBBlockSize: Integer read FBLOBBlockSize write FBLOBBlockSize;
  end; // TABSFieldDef


////////////////////////////////////////////////////////////////////////////////
//
// TABSIndexDef
//
////////////////////////////////////////////////////////////////////////////////


  TABSIndexType = (itBTree,itAnotherOne);

  TABSIndexColumn = class (TObject)
   private
    FFieldName:        string;
    FDescending:       ByteBool;
    FCaseInsensitive:  ByteBool;
    FMaxIndexedSize:   Integer;
   public
    procedure LoadFromStream(Stream: TStream);
    procedure SaveToStream(Stream: TStream);
   public
    property FieldName: string read FFieldName write FFieldName;
    property Descending: ByteBool read FDescending write FDescending;
    property CaseInsensitive: ByteBool read FCaseInsensitive write FCaseInsensitive;
    property MaxIndexedSize: Integer read FMaxIndexedSize write FMaxIndexedSize;
  end;


////////////////////////////////////////////////////////////////////////////////
//
// TABSIndexDef
//
////////////////////////////////////////////////////////////////////////////////

  TABSIndexDef = class (TABSMetaObjectDef)
   private
    FIndexType:           TABSIndexType; // BTree or other
    FIndexColumns:        array of TABSIndexColumn;
    FUnique:              ByteBool;
    FPrimary:             ByteBool;
    FRootPageNo:          TABSPageNo;
    FTemporary:           ByteBool;
    FSessionID:           TABSSessionID; // for temp index
    FTableState:          Integer;       // for temp index
    FNeedRebuild:         ByteBool;      // for temp index

    function GetIndexColumn(Index: Integer): TABSIndexColumn;
    function GetColumnCount: Integer;
    procedure SetColumnCount(Value: Integer);
   public
    constructor Create;
    destructor Destroy; override;
    procedure Assign(Source: TABSMetaObjectDef); override;
    procedure AssignByNames(FieldNames, AscDescList, CaseSensitivityList: TStringList);
    procedure LoadFromStream(Stream: TStream); override;
    procedure SaveToStream(Stream: TStream); override;
   public
    property IndexType: TABSIndexType read FIndexType write FIndexType;
    property Columns[Index: Integer]: TABSIndexColumn read GetIndexColumn;
    property ColumnCount: Integer read GetColumnCount write SetColumnCount;
    property Unique: ByteBool read FUnique write FUnique;
    property Primary: ByteBool read FPrimary write FPrimary;
    property RootPageNo: TABSPageNo read FRootPageNo write FRootPageNo;
    property Temporary: ByteBool read FTemporary write FTemporary;
    property SessionID: TABSSessionID read FSessionID write FSessionID;
    property TableState: Integer read FTableState write FTableState;
    property NeedRebuild: ByteBool read FNeedRebuild write FNeedRebuild;
  end; // TABSIndexDef


////////////////////////////////////////////////////////////////////////////////
//
// TABSConstraintDef
//
////////////////////////////////////////////////////////////////////////////////


  TABSConstraintDef = class (TABSMetaObjectDef)
   private
    FConstraintType:  TABSConstraintType;
   public
    procedure Assign(Source: TABSMetaObjectDef); override;
   public
    property ConstraintType: TABSConstraintType read FConstraintType write FConstraintType;
  end;


  TABSConstraintDefNotNull = class (TABSConstraintDef)
   private
    FTableSchemaName:          TABSObjectName;  // Shema
    FTableSchemaObjectID:      TABSObjectID;
    FTableName:                TABSObjectName;  // Table
    FTableObjectID:            TABSObjectID;
    FColumnName:               TABSObjectName;  // Column
    FColumnObjectID:           TABSObjectID;
   public
    constructor Create;
    procedure Assign(Source: TABSMetaObjectDef); override;
    procedure SetNames(
                        ColumnName: string;
                        TableName: string = '';
                        SchemaName: string = ''
                       );
    procedure LoadFromStream(Stream: TStream); override;
    procedure SaveToStream(Stream: TStream); override;
   public
    property TableSchemaName: TABSObjectName read FTableSchemaName write FTableSchemaName;
    property TableSchemaObjectID: TABSObjectID read FTableSchemaObjectID write FTableSchemaObjectID;
    property TableName: TABSObjectName read FTableName write FTableName;
    property TableObjectID: TABSObjectID read FTableObjectID write FTableObjectID;
    property ColumnName: TABSObjectName read FColumnName write FColumnName;
    property ColumnObjectID: TABSObjectID read FColumnObjectID write FColumnObjectID;
  end;// TABSConstraintDef


  TABSConstraintDefCheck = class (TABSConstraintDef)
   private
    FTableSchemaName:     TABSObjectName;  // Shema
    FTableSchemaObjectID: TABSObjectID;
    FTableName:           TABSObjectName;  // Table
    FTableObjectID:       TABSObjectID;
    FColumnName:          TABSObjectName;  // Column
    FColumnObjectID:      TABSObjectID;
    FMinValue:            TABSVariant;
    FMaxValue:            TABSVariant;
   public
    constructor Create;
    destructor Destroy; override;
    procedure Assign(Source: TABSMetaObjectDef); override;
    procedure SetNames(
                        ColumnName: string;
                        TableName: string = '';
                        SchemaName: string = ''
                       );
    procedure LoadFromStream(Stream: TStream); override;
    procedure SaveToStream(Stream: TStream); override;
   public
    property MinValue: TABSVariant read FMinValue;
    property MaxValue: TABSVariant read FMaxValue;
    property TableSchemaName: TABSObjectName read FTableSchemaName write FTableSchemaName;
    property TableSchemaObjectID: TABSObjectID read FTableSchemaObjectID write FTableSchemaObjectID;
    property TableName: TABSObjectName read FTableName write FTableName;
    property TableObjectID: TABSObjectID read FTableObjectID write FTableObjectID;
    property ColumnName: TABSObjectName read FColumnName write FColumnName;
    property ColumnObjectID: TABSObjectID read FColumnObjectID write FColumnObjectID;
  end;//TABSConstraintDefCheck


  TABSConstraintColumn = record
    ColumnName:          TABSObjectName;  // Column
    ColumnObjectID:      TABSObjectID;
  end;


  TABSConstraintDefUnique = class (TABSConstraintDef)
   private
    FTableSchemaName:          TABSObjectName;  // Shema
    FTableSchemaObjectID:      TABSObjectID;
    FTableName:                TABSObjectName;  // Table
    FTableObjectID:            TABSObjectID;
    FIndexName:                TABSObjectName;  // Index ID
    FIndexObjectID:            TABSObjectID;
   public
    Columns: array of TABSConstraintColumn; // Columns
   public
    constructor Create;
    destructor Destroy; override;
    procedure Assign(Source: TABSMetaObjectDef); override;
    procedure LoadFromStream(Stream: TStream); override;
    procedure SaveToStream(Stream: TStream); override;
   public
    property TableSchemaName: TABSObjectName read FTableSchemaName write FTableSchemaName;
    property TableSchemaObjectID: TABSObjectID read FTableSchemaObjectID write FTableSchemaObjectID;
    property TableName: TABSObjectName read FTableName write FTableName;
    property TableObjectID: TABSObjectID read FTableObjectID write FTableObjectID;
    property IndexName: TABSObjectName read FIndexName write FIndexName;
    property IndexObjectID: TABSObjectID read FIndexObjectID write FIndexObjectID;
  end;//TABSConstraintDefUnique


  TABSConstraintDefPrimary = class (TABSConstraintDefUnique)
   public
    constructor Create;
  end;//TABSConstraintDefPrimary


////////////////////////////////////////////////////////////////////////////////
//
// Meta Objects Defs
//
////////////////////////////////////////////////////////////////////////////////

 TABSMetaObjectDefs = class(TObject)
  protected
   FDefsList:   TABSSortedStringPtrArray;
   FLoadedItemCount:  Integer;
  private
   function GetCount: Integer; virtual;
   function GetDef(Index: Integer): TABSMetaObjectDef;
   procedure SetDef(Index: Integer; Value: TABSMetaObjectDef);

   procedure Add(MetaObjectDef: TABSMetaObjectDef); virtual;
   function InternalAddCreated: TABSMetaObjectDef; virtual;
  public
   procedure LoadFromStream(Stream: TStream); virtual;
   procedure SaveToStream(Stream: TStream); virtual;

   constructor Create;
   destructor Destroy; override;
   procedure Assign(Source: TABSMetaObjectDefs); virtual;

   procedure Delete(Index: Integer); virtual;
   procedure Insert(Index: Integer; MetaObjectDef: TABSMetaObjectDef); virtual;
   procedure Move(CurIndex, NewIndex: Integer); virtual;
   procedure Clear; virtual;

   function GetDefNumberByName(Name: string): Integer;
   function GetDefByName(Name: string): TABSMetaObjectDef;
   function GetDefNumberByObjectId(id: TABSObjectID): Integer;
   function GetDefByObjectId(id: TABSObjectID): TABSMetaObjectDef;
  public
   property Count: Integer read GetCount;
   property Items[Index: Integer]: TABSMetaObjectDef read GetDef write SetDef; default;
 end;


////////////////////////////////////////////////////////////////////////////////
//
// TABSIndexDefs
//
////////////////////////////////////////////////////////////////////////////////


 TABSIndexDefs = class(TABSMetaObjectDefs)
  private
   function GetIndexDef(Index: Integer): TABSIndexDef; virtual;
   procedure SetIndexDef(Index: Integer; Value: TABSIndexDef); virtual;
   function InternalAddCreated: TABSMetaObjectDef; override;
  public
   // AscDesc and CaseSensitivity lists should contain constants ABS_ASC, ABS_DESC, ABS_NO_CASE, ABS_CASE
   function IsIndexExists(FieldNames, AscDescList, CaseSensitivityList: TStringList;
                                     SessionID: TABSSessionID;
                                     FieldDefs: TABSFieldDefs): Boolean;
   function FindIndex(FieldNames, AscDescList, CaseSensitivityList: TStringList;
                       SessionID: TABSSessionID; FieldDefs: TABSFieldDefs): TABSObjectID;
   function AddCreated: TABSIndexDef;
   function GetIndexDefByName(Name: string): TABSIndexDef;
   procedure LoadFromStream(Stream: TStream); override;
   procedure SaveToStream(Stream: TStream); override;
  public
   property Items[Index: Integer]: TABSIndexDef read GetIndexDef write SetIndexDef; default;
 end;


////////////////////////////////////////////////////////////////////////////////
//
// TABSFieldDefs
//
////////////////////////////////////////////////////////////////////////////////


 TABSFieldDefs = class(TABSMetaObjectDefs)
  private
   function GetDef(Index: Integer): TABSFieldDef;
   procedure SetDef(Index: Integer; Value: TABSFieldDef);
   function InternalAddCreated: TABSMetaObjectDef; override;
  public
   function AddCreated: TABSFieldDef;
   function GetFieldDefByName(Name: string): TABSFieldDef;

   procedure RecalcFieldOffsets; virtual;
   function GetMemoryRecordBufferSize: Integer;
   function GetDiskRecordBufferSize: Integer;

   procedure LoadFromStream(Stream: TStream); override;
   procedure SaveToStream(Stream: TStream); override;
  public
   property Items[Index: Integer]: TABSFieldDef read GetDef write SetDef; default;
 end;//TABSFieldDefs


////////////////////////////////////////////////////////////////////////////////
//
// TABSConstraintDefs
//
////////////////////////////////////////////////////////////////////////////////

 TABSConstraintDefs =  class(TABSMetaObjectDefs)
  private
   function GetDef(Index: Integer): TABSConstraintDef;
   procedure SetDef(Index: Integer; Value: TABSConstraintDef);
  public
   procedure Assign(Source: TABSMetaObjectDefs); override;
   // Create TABSConstraintDefNotNull and add it into list
   function AddNotNull: TABSConstraintDefNotNull;
   // Create TABSConstraintDefCheck and add it into list
   function AddCheck: TABSConstraintDefCheck;
   function AddPK: TABSConstraintDefPrimary;
   function AddUnique: TABSConstraintDefUnique;

   procedure LoadFromStream(Stream: TStream); override;
   procedure SaveToStream(Stream: TStream); override;
  public
   property Items[Index: Integer]: TABSConstraintDef read GetDef write SetDef; default;
 end;//TABSConstraintDefs



 TABSRestructureInfo = record
    FRestructureBLOBCompression:   TABSCompression;
    //FRestructurePassword:          TABSPassword;
    FRestructureFieldDefs:         TABSFieldDefs;
    FRestructureIndexDefs:         TABSIndexDefs;
    FRestructureConstraintDefs:    TABSConstraintDefs;
 end;


////////////////////////////////////////////////////////////////////////////////
//
// TABSCursor
//
////////////////////////////////////////////////////////////////////////////////


  TABSCursor = class (TObject)
   public
    FSettingProjection:             Boolean;
    FTableName:                     string;
    FIndexName:                     string;
    FIndexID:                       TABSObjectID;
    FReadOnly:                      Boolean;
    FExclusive:                     Boolean;
    FInMemory:                      Boolean;
    FTemporary:                     Boolean;
    FSession:                       TABSBaseSession;
    FIsOpen:                        Boolean;
    FPhysicalOrder:                 Boolean;
    FCurrentRecordPositionInIndex:  TABSIndexPosition;
    // current record buffer
    FCurrentRecordBuffer:           TABSRecordBuffer;
    // distinct
    FDistinctRecordBuffer:          TABSRecordBuffer;
    // buffer with original record, stored on InternalEdit by TABSDataset
    FEditRecordBuffer:              TABSRecordBuffer;
    FPassword:                      TABSPassword;
    FConstraintDefs:                TABSConstraintDefs;
    FBLOBCompression:               TABSCompression;
    FFieldDefs:                     TABSFieldDefs;
    FVisibleFieldDefs:              TABSFieldDefs; // visible fields (projection)
    FIndexDefs:                     TABSIndexDefs;
    FBLOBStreams:                   TList;
    FRecordBitmap:                  Pointer;
    FIndexPositionCache:            TABSIndexPositionCache;
    FTableLockedByCursor:           Boolean;
    FBatchUpdate:                   Boolean;
    FDisableTempFiles:              Boolean;
    FIsRepairing:                   Boolean;
   private
    // BLOBS will be stored as 6 bytes reference:
    // DiskEngine: 4 bytes PAGEID, 2 bytes ObjectID
    // TemporaryEngine: 4 bytes pointer to BLOBDescriptor record, 2 bytes not used
    // MemoryEngine: 4 bytes pointer to BLOBCompressedStream, 2 bytes not used

    // Record Buffer sizes and offsets:
    //              + FieldValuesOffset
    //                                   + BookmarOffset
    //                                              + CalculatedFieldsOffset
    // +------------+--------------------+----------+-----------------+
    // | Null Flags | Field Values,      | Bookmark | Calculated and  |
    // |            | References To BLOB | Bookmark | Lookup Fields   |
    // +------------+--------------------+----------+-----------------+
    //                                              + RecordSize
    //                                                                + RecordBufferSize

    // Key buffer:
    //                                                   + KeyBufferSize
    //                                   + KeyOffset
    // +------------+--------------------+---------------+
    // | Null Flags | Field Values,      | TABSKeyBuffer |
    // |            | References To BLOB |               |
    // +------------+--------------------+---------------+

    FErrorCode:                     TABSErrorCode;
    FErrorMessage:                  string;
    FIsDesignMode:                  Boolean;
    FRecordBufferSize:              Integer;
    FRecordSize:                    Integer;
    FKeyBufferSize:                 Integer;
    FKeyOffset:                     Integer;
    FKeyFieldCount:                 Integer;
    FFieldValuesOffset:             Integer;
    FCalculatedFieldsOffset:        Integer;
    FBookmarkOffset:                Integer;
    FFilterExpression:              Pointer;
    FSQLFilterExpression:           Pointer;
    FKeyBuffer:                     TABSRecordBuffer;
    FRangeStartBuffer:              TABSRecordBuffer;
    FRangeEndBuffer:                TABSRecordBuffer;
    FRangeStartExclusive:           Boolean;
    FRangeEndExclusive:             Boolean;
    FRangeStartKeyFieldCount:       Integer;
    FRangeEndKeyFieldCount:         Integer;
    FDistinctFieldCount:            Integer;
   protected
    procedure SetIndexName(Value: string);
   public
    property RecordBufferSize: Integer read FRecordBufferSize write FRecordBufferSize;
    property RecordSize: Integer read FRecordSize write FRecordSize;
    property FieldValuesOffset: Integer read FFieldValuesOffset write FFieldValuesOffset;
    property CalculatedFieldsOffset: Integer read FCalculatedFieldsOffset write FCalculatedFieldsOffset;
    property BookmarkOffset: Integer read FBookmarkOffset write FBookmarkOffset;
    property KeyOffset: Integer read FKeyOffset write FKeyOffset;
    property KeyBufferSize: Integer read FKeyBufferSize write FKeyBufferSize;

   public
    // table operations
    procedure CreateTable(
                          FieldDefs: TABSFieldDefs;
                          IndexDefs: TABSIndexDefs;
                          ConstraintDefs: TABSConstraintDefs
                         ); virtual; abstract;
    procedure DeleteTable; virtual; abstract;
    procedure EmptyTable; virtual; abstract;
    procedure RenameTable(NewTableName: string); virtual; abstract;

    procedure InternalInitFieldDefs; virtual; abstract;
    procedure OpenTableByFieldDefs(
                          FieldDefs: TABSFieldDefs;
                          IndexDefs: TABSIndexDefs;
                          ConstraintDefs: TABSConstraintDefs
                       ); virtual; abstract;
    procedure CloseTable; virtual; abstract;
    procedure LockTableData; virtual; abstract;
    procedure UnlockTableData; virtual; abstract;
    function LockTable(LockType: TABSLockType; TryCount, Delay: Integer; AllowXIRWAfterSIRW: Boolean = True): Boolean; virtual; abstract;
    function UnlockTable(LockType: TABSLockType; IgnoreIfNoLock: Boolean=False): Boolean; virtual; abstract;

    // Rename Field by Field Index in FieldDefs
    procedure RenameField(FieldName, NewFieldName: string); virtual;

    // index operations
    function GetIndexDefs: TABSIndexDefs; virtual;
    procedure AddIndex(IndexDef: TABSIndexDef); virtual; abstract;
    procedure DeleteIndex(Name: string); virtual; abstract;
    procedure DeleteAllIndexes; virtual; abstract;
    // return index name
    function FindOrCreateIndex(FieldNamesList,
                AscDescList, CaseSensitivityList: TStringList; var IsCreated: Boolean): string; virtual; abstract;
    function IndexExists(FieldNamesList, AscDescList, CaseSensitivityList: TStringList): Boolean; virtual; abstract;

    // check field value and if not null move data from RecordBuffer to Buffer
    function GetFieldData(
                          FieldNo:      Integer; // field no
                          Buffer:       Pointer; // buffer
                          RecordBuffer: TABSRecordBuffer // record buffer
                         ): Boolean;
    // set field data from Buffer to RecordBuffer
    procedure SetFieldData(
                            FieldNo:       Integer;
                            Buffer:        Pointer;
                            RecordBuffer:  TABSRecordBuffer // record buffer
                          );
    // clear garbage after the end of strings in record buffer
    procedure ClearStringFieldsGarbage(RecordBuffer:  TABSRecordBuffer);

    procedure GetFieldValue(Value: TABSVariant; FieldNo: Integer; DirectAccess: Boolean);
    procedure SetFieldValue(
                            Value:        TABSVariant;
                            FieldNo:      Integer;
                            DirectAccess: Boolean;
                            RecordBuffer: TABSRecordBuffer = nil
                           );
    procedure CopyFieldValue(SrcFieldNo: Integer;
                             DirectAccess: Boolean;
                             DestFieldNo: Integer;
                             DestCursor: TABSCursor); virtual; abstract;

    // allocate record buffer and set null flags
    function AllocateRecordBuffer: TABSRecordBuffer;
    // initialize record buffer
    procedure InternalInitRecord(RecordBuffer: TABSRecordBuffer; InsertMode: Boolean); virtual; abstract;
    // free record buffer
    procedure FreeRecordBuffer(var Buffer: TABSRecordBuffer); virtual;
    // allocate record buffer and set null flags
    function AllocateKeyRecordBuffer: TABSRecordBuffer;
    // initialize record buffer
    procedure InternalInitKeyBuffer(RecordBuffer: TABSRecordBuffer);


    //---------------------------------------------------------------------------
    // navigation & bookmark methods
    //---------------------------------------------------------------------------

    function GetRecordCount: TABSRecordNo; virtual; abstract;
    // get record
    function GetRecordBuffer(
              GetRecordMode:  TABSGetRecordMode
              ): TABSGetRecordResult; virtual; abstract;
    // go to record
    procedure SetRecNo(Value: Int64); virtual; abstract;
    // return current record number
    function GetRecNo: Int64; virtual; abstract;
    // -1,0,1 - compare records order with or without active index
    function CompareRecordsOrder(RecordID1, RecordID2: TABSRecordID): integer; virtual; abstract;
    // go to first record
    procedure InternalFirst; virtual; abstract;
    // go to last record
    procedure InternalLast; virtual; abstract;
    function SavePosition: Pointer;
    procedure RestorePosition(Pos: Pointer);
    procedure FreePosition(Pos: Pointer);


    //---------------------------------------------------------------------------
    // insert, edit, post, delete methods
    //---------------------------------------------------------------------------

    // insert record
    procedure InternalInsert; virtual; abstract;
    // edit record
    procedure InternalEdit; virtual; abstract;
    // cancels updates
    procedure InternalCancel(ToInsert: Boolean); virtual; abstract;
    // update record
    procedure InternalPost(ToInsert: Boolean); virtual; abstract;
    // delete record
    procedure InternalDelete; virtual; abstract;
    // check if record is locked by another user
    function IsRecordLocked: Boolean; virtual; abstract;


    //---------------------------------------------------------------------------
    // search & filter methods
    //---------------------------------------------------------------------------

    // disable record bitmap
    procedure DisableRecordBitmap;
    // set distinct
    procedure ApplyDistinct(FieldNamesList, AscDescList, CaseSensitivityList: TStringList); virtual; abstract;
    // apply projection
    procedure ApplyProjection(FieldNamesList, AliasList: TStringList);
    procedure ActivateFilters(
                              FilterText:      string;
                              CaseInsensitive: Boolean;
                              PartialKey:      Boolean
                            ); virtual; abstract;
    procedure DeactivateFilters; virtual; abstract;
    function Locate(
                    const KeyFields: string;
                    const KeyValues: Variant;
                    CaseInsensitive: Boolean;
                    PartialKey:      Boolean
              ): Boolean; virtual; abstract;
    function FindKey(SearchCondition: TABSSearchCondition): Boolean; virtual; abstract;
    // used by SQL: "where field > all (select ...)"
    function IsAnyRecordMatchCondition(const FieldName: string;
          const Operator: TABSDataOperator; const Value: TABSVariant): Boolean; virtual; abstract;
    function IsIndexApplied: Boolean;
    function IsDistinctApplied: Boolean;
    function IsFilterApplied: Boolean;
    function IsRangeApplied: Boolean;
    function IsViewRestricted: Boolean;
    procedure ResetRange;
    procedure ApplyRange(
                          StartBuffer, EndBuffer: TABSRecordBuffer;
                          StartKeyFieldCount:     Integer;
                          EndKeyFieldCount:       Integer;
                          StartExclusive:         Boolean;
                          EndExclusive:           Boolean
                        );
    // set SQL Filter
    procedure SetSQLFilter(FilterExpr: TObject; ParentQueryAO: TObject; ParentCursor: TABSCursor);

    //---------------------------------------------------------------------------
    // BLOB methods
    //---------------------------------------------------------------------------

    function InternalCreateBlobStream(
              ToInsert: Boolean;
              ToEdit: Boolean;
              FieldNo:  Integer;
              OpenMode: TABSBLOBOpenMode;
              CanDoGetRecordBuffer: Boolean
              ):TABSStream; virtual; abstract;

    procedure InternalCloseBLOB(FieldNo: Integer); virtual; abstract;

    // clear blob streams
    procedure ClearBLOBStreams(WriteOnly: Boolean = False); virtual; abstract;

    function LastAutoincValue(FieldNo: Integer): Int64; virtual; abstract;

    // batch update methods
    procedure BeginBatchUpdate; virtual; abstract;
    procedure EndBatchUpdate; virtual; abstract;
    procedure CancelBatchUpdate; virtual; abstract;

    function CheckConstraints(ToInsert: Boolean): Boolean; virtual; abstract;

   public
    // for bookmarks
    CurrentRecordID:               TABSRecordID;
    CurrentIndexID:                TABSObjectID;
    // position for navigation
    FirstPosition:                 Boolean;
    LastPosition:                  Boolean;
    FilterRecord:                  TABSFilterRecord;
    Dataset:                       Pointer;

    property RecordBitmap: Pointer read FRecordBitmap write FRecordBitmap;
    property IndexPositionCache: TABSIndexPositionCache read FIndexPositionCache;
    property DistinctFieldCount: Integer read FDistinctFieldCount write FDistinctFieldCount;
    property FilterExpression: Pointer read FFilterExpression write FFilterExpression;
    property SQLFilterExpression: Pointer read FSQLFilterExpression write FSQLFilterExpression;
    property BLOBStreams: TList read FBLOBStreams;
    property ErrorCode: TABSErrorCode read FErrorCode write FErrorCode;
    property ErrorMessage: string read FErrorMessage write FErrorMessage;
    property IsDesignMode: Boolean read FIsDesignMode write FIsDesignMode;
    property TableName: string read FTableName write FTableName;
    property IndexName: string read FIndexName write SetIndexName;
    property IndexID: TABSObjectID read FIndexID write FIndexID;
    property ReadOnly: Boolean read FReadOnly write FReadOnly;
    property Exclusive: Boolean read FExclusive write FExclusive;
    property InMemory: Boolean read FInMemory write FInMemory;
    property Temporary: Boolean read FTemporary write FTemporary;
    property Session: TABSBaseSession read FSession write FSession;
    property IsOpen: Boolean read FIsOpen write FIsOpen;
    property IsRepairing: Boolean read FIsRepairing write FIsRepairing;
    property RecordCount: Int64 read GetRecordCount;
    property FieldDefs: TABSFieldDefs read FFieldDefs;
    property VisibleFieldDefs: TABSFieldDefs read FVisibleFieldDefs;
    property IndexDefs: TABSIndexDefs read GetIndexDefs;
    property ConstraintDefs: TABSConstraintDefs read FConstraintDefs;
    // set it before call CreateTable
    property BLOBCompression: TABSCompression read FBLOBCompression
             write FBLOBCompression;
    // set it before call OpenTable, CreateTable
    property Password: TABSPassword read FPassword
             write FPassword;
    property KeyFieldCount: Integer read FKeyFieldCount write FKeyFieldCount;
    property KeyBuffer: TABSRecordBuffer read FKeyBuffer write FKeyBuffer;
    property RangeStartBuffer: TABSRecordBuffer read FRangeStartBuffer
             write FRangeStartBuffer;
    property RangeEndBuffer:   TABSRecordBuffer read FRangeEndBuffer
             write FRangeEndBuffer;
    property RangeStartExclusive: Boolean read FRangeStartExclusive
             write FRangeStartExclusive;
    property RangeEndExclusive: Boolean read FRangeEndExclusive
             write FRangeEndExclusive;
    property RangeStartKeyFieldCount: Integer read FRangeStartKeyFieldCount
             write FRangeStartKeyFieldCount;
    property RangeEndKeyFieldCount: Integer read FRangeEndKeyFieldCount
             write FRangeEndKeyFieldCount;
    property CurrentRecordBuffer: TABSRecordBuffer read FCurrentRecordBuffer
              write FCurrentRecordBuffer;
    property DistinctRecordBuffer: TABSRecordBuffer read FDistinctRecordBuffer
              write FDistinctRecordBuffer;
    property EditRecordBuffer: TABSRecordBuffer read FEditRecordBuffer
              write FEditRecordBuffer;
    property PhysicalOrder: Boolean read FPhysicalOrder write FPhysicalOrder;
    property CurrentRecordPositionInIndex: TABSIndexPosition
              read FCurrentRecordPositionInIndex
              write FCurrentRecordPositionInIndex;
    property TableLockedByCursor: Boolean read FTableLockedByCursor write FTableLockedByCursor;
    property InBatchUpdate: Boolean read FBatchUpdate write FBatchUpdate;
  end; // TABSCursor


////////////////////////////////////////////////////////////////////////////////
//
// TABSBaseSession
//
////////////////////////////////////////////////////////////////////////////////

  // manager for TABSSession
  TABSSessionComponentManager = class(TObject)
  end;

  // Session object base class
  TABSSessionNamedObject = class(TObject)
   private
    FObjectID:    TABSObjectID;
    FName:        TABSObjectName;
   public
    constructor Create(Name: string); overload;
    constructor Create(ObjectID: TABSObjectID); overload;
   public
    property Name: TABSObjectName read FName write FName;
    property ObjectID: TABSObjectID read FObjectID write FObjectID;
  end;

  // Sequence last value stored in user session
  TABSSessionNamedObjectSequenceValue = class(TABSSessionNamedObject)
   public
    FValue: TABSSequenceValue;
   public
    constructor Create(ObjectID: TABSObjectID; Value: TABSSequenceValue);
   public
    property Value: TABSSequenceValue read FValue write FValue;
  end;

  // for database component
  TABSBaseSession = class (TObject)
   private
    FDatabaseName:      string; // name of database
    FDatabaseFileName:  string; // database file name
    FSessionID:         TABSSessionID;
    FInTransaction:     Boolean;
    FReadOnly:          Boolean;
    FExclusive:         Boolean;
    FInMemory:          Boolean;
    FLogin:             string;
    //FPassword:          string;
    FSessionHandle:     TABSSessionComponentManager;
    FSessionNamedObjectList: TABSSortedStringPtrArray;
    FMaxSessionCount:   Integer;
    FRepairNeeded:      Boolean;
    FMultiUser:         Boolean;
    // 5.12 readonly bugfix
    FSessionName: string;
   protected
    // db connected?
    function GetConnected: Boolean;  virtual;  abstract;
    // connect / disconnect
    procedure SetConnected(Value: boolean); virtual; abstract;
    function GetSuppressDBHeaderErrors: Boolean; virtual; abstract;
    procedure SetSuppressDBHeaderErrors(Value: boolean); virtual; abstract;
   public
    // constructor
    constructor Create;
    // destructor
    destructor Destroy; override;

    // create database
    procedure CreateDatabase; virtual; abstract;
    // delete database
    procedure DeleteDatabase; virtual; abstract;
    // rename database
    procedure RenameDatabase(NewDatabaseFileName:string); virtual; abstract;

    procedure GetTablesList(List: TStrings); virtual; abstract;
    function TableExists(TableName: string): Boolean; virtual; abstract;

    procedure SetObject(Value: TABSSessionNamedObject); virtual;
    function GetObjectByName(ObjectName: string): TABSSessionNamedObject; virtual;
    function GetObjectByID(id: TABSObjectID): TABSSessionNamedObject; virtual;
    procedure DeleteObject(id: TABSObjectID); virtual;

    procedure StartTransaction; virtual; abstract;
    procedure Commit(DoFlushBuffers: Boolean=True); virtual; abstract;
    procedure Rollback; virtual; abstract;
    procedure FlushBuffers; virtual; abstract;

    property Connected: boolean read GetConnected write SetConnected default false;
    property DatabaseFileName: string read FDatabaseFileName write FDatabaseFileName;
    property DatabaseName: string read FDatabaseName write FDatabaseName;
    property SessionID: TABSSessionID read FSessionID write FSessionID;
    property InTransaction: Boolean read FInTransaction write FInTransaction;
    property ReadOnly: Boolean read FReadOnly write FReadOnly;
    property Exclusive: Boolean read FExclusive write FExclusive;
    property InMemory: Boolean read FInMemory write FInMemory;
    property Login: string read FLogin write FLogin;
    //property Password: string read FPassword write FPassword;
    property SessionComponentManager: TABSSessionComponentManager
             read FSessionHandle write FSessionHandle;
    property MaxSessionCount: Integer read FMaxSessionCount write FMaxSessionCount;
    property RepairNeeded: Boolean read FRepairNeeded write FRepairNeeded;
    property SuppressDBHeaderErrors: Boolean read GetSuppressDBHeaderErrors write SetSuppressDBHeaderErrors;
    property MultiUser: Boolean read FMultiUser write FMultiUser;
    property SessionName: string read FSessionName write FSessionName;
  end; // TABSBaseSession




implementation

uses

// AbsoluteDatabase units
     ABSRelationalAlgebra,
     ABSExpressions,
     ABSBaseEngine;



////////////////////////////////////////////////////////////////////////////////
//
// TABSMetaObjectDef
//
////////////////////////////////////////////////////////////////////////////////


//------------------------------------------------------------------------------
// Create
//------------------------------------------------------------------------------
constructor TABSMetaObjectDef.Create;
begin
  FName       := '';
  FObjectID   := OBJECTID_IS_NULL;
  FSchemaName := '';
  FSchemaID   := OBJECTID_IS_NULL;
end;//Create


//------------------------------------------------------------------------------
// Assign
//------------------------------------------------------------------------------
procedure TABSMetaObjectDef.Assign(Source: TABSMetaObjectDef);
begin
  FName := Source.FName;
  FObjectID := Source.FObjectID;
  FSchemaName := Source.FSchemaName;
  FSchemaID := Source.FSchemaID;
end;//Assign


//------------------------------------------------------------------------------
// load from stream
//------------------------------------------------------------------------------
procedure TABSMetaObjectDef.LoadFromStream(Stream: TStream);
var
  Len: Byte;
begin
  LoadDataFromStream(Len,sizeof(Len),Stream,10166);
  SetLength(FName,Len);
  LoadDataFromStream(PAnsiChar(@FName[1])^,Len,Stream,10167);
  LoadDataFromStream(FObjectID,sizeof(ObjectID),Stream,10169);
end; // LoadFromStream


//------------------------------------------------------------------------------
// save to stream
//------------------------------------------------------------------------------
procedure TABSMetaObjectDef.SaveToStream(Stream: TStream);
var Len: Byte;
begin
  Len := Length(Name);
  SaveDataToStream(Len,Sizeof(Len),Stream,10164);
  SaveDataToStream(PAnsiChar(@FName[1])^,Len,Stream,10165);
  SaveDataToStream(FObjectID,sizeof(ObjectID),Stream,10168);
end; // SaveToStream


////////////////////////////////////////////////////////////////////////////////
//
// TABSFieldDef
//
////////////////////////////////////////////////////////////////////////////////



//------------------------------------------------------------------------------
// Constructor
//------------------------------------------------------------------------------
constructor TABSFieldDef.Create;
begin
  inherited Create;
  FBaseFieldType := bftUnknown;
  FAdvancedFieldType := aftUnknown;
  FFieldSize := 0;
  FDiskDataSize := 0;
  FMemoryDataSize := 0;
  FDiskOffset := 0;
  FMemoryOffset := 0;
  FFieldNoReference := 0;

  // Default Value
  //FDefaultValueType := dvtNull;
  FDefaultValue := TABSVariant.Create;
  FDefaultValueExpr := nil;

  // Blob data
  FBLOBCompressionAlgorithm := acaNone;
  FBLOBCompressionMode := 0;
  FBLOBBlockSize := DefaultBLOBBlockSize;

  // Autoinc settings
  FAutoincIncrement := 1;
  FAutoincInitialValue := 0;
  FAutoincMinValue  := 0;//Low(Int64);
  FAutoincMaxValue  := High(Int64);
  FAutoincCycled    := False;

end;//Create


//------------------------------------------------------------------------------
// Destroy
//------------------------------------------------------------------------------
destructor TABSFieldDef.Destroy;
begin
  FDefaultValue.Free;
  if (FDefaultValueExpr <> nil) then
    FDefaultValueExpr.Free;
  inherited;
end;//Destroy


//------------------------------------------------------------------------------
// SetFieldDefData ( set Advanced Field Type )
//------------------------------------------------------------------------------
procedure TABSFieldDef.SetFieldDefDataType(AdvancedFieldType: TABSAdvancedFieldType;
                                           FieldSize: Integer);
begin
  FAdvancedFieldType := AdvancedFieldType;
  FBaseFieldType := AdvancedFieldTypeToBaseFieldType(AdvancedFieldType);
  if FBaseFieldType = bftUnknown then
   raise EABSException.Create(30007,ErrorGUnsupportedDataType,
                                    [AftToStr(AdvancedFieldType)]);
  FFieldSize := FieldSize;
  RecalcInternalSizes;
end;//SetFieldDefData


//------------------------------------------------------------------------------
// SetFieldDefData ( set Advanced Field Type )
//------------------------------------------------------------------------------
procedure TABSFieldDef.SetFieldDefDataType(BaseFieldType: TABSBaseFieldType;
                                           FieldSize: Integer);
begin
  FBaseFieldType := BaseFieldType;
  FFieldSize := FieldSize;

  FAdvancedFieldType := BaseFieldTypeToAdvancedFieldType(BaseFieldType);
  if FAdvancedFieldType = aftUnknown then
   raise EABSException.Create(30008,ErrorGUnsupportedDataType,
                                    [BftToStr(BaseFieldType)]);
  RecalcInternalSizes;
end;//SetFieldDefData



//------------------------------------------------------------------------------
// RecalcInternalSizes
//------------------------------------------------------------------------------
procedure TABSFieldDef.RecalcInternalSizes;
begin
  // FMemoryDataSize ...
  FMemoryDataSize := GetDataSizeInMemory(FBaseFieldType, FFieldSize);

  // FDiskDataSize ...
  if IsBLOBFieldType(FBaseFieldType) then
   FDiskDataSize := SizeOf(TABSPageItemID)
  else
   FDiskDataSize := FMemoryDataSize;
end;//RecalcInternalSizes


//------------------------------------------------------------------------------
// CreateDefaultValueExprIfNeeded
//------------------------------------------------------------------------------
procedure TABSFieldDef.CreateDefaultValueExprIfNeeded;
begin
  if (FDefaultValueExpr <> nil) then
    begin
      FDefaultValueExpr.Free;
      FDefaultValueExpr := nil;
    end;
  if (IsNonConstantExpression(FDefaultValue)) then
    begin
      FDefaultValueExpr := TABSExpression.Create;
      TABSExpression(FDefaultValueExpr).ParseForDefaultValueExpression(string(FDefaultValue.AsWideString));
    end;
end;// CreateDefaultValueExprIfNeeded


//------------------------------------------------------------------------------
// Assign
//------------------------------------------------------------------------------
procedure TABSFieldDef.Assign(Source: TABSMetaObjectDef);
var s: TABSFieldDef;
begin
  s := Source as TABSFieldDef;
  inherited Assign(Source);
  FBaseFieldType := s.FBaseFieldType;
  FAdvancedFieldType := s.FAdvancedFieldType;
  FFieldSize := s.FFieldSize;
  FDiskDataSize := s.FDiskDataSize;
  FMemoryDataSize := s.FMemoryDataSize;
  FDiskOffset := s.FDiskOffset;
  FMemoryOffset := s.FMemoryOffset;

  // Default Value
  //FDefaultValueType := s.FDefaultValueType;
  FDefaultValue.Assign(s.FDefaultValue);
  CreateDefaultValueExprIfNeeded;

  // Blob data
  FBLOBCompressionAlgorithm := s.FBLOBCompressionAlgorithm;
  FBLOBCompressionMode      := s.FBLOBCompressionMode;
  FBLOBBlockSize            := s.FBLOBBlockSize;

  // Autoinc settings
  FAutoincIncrement := s.FAutoincIncrement;
  FAutoincInitialValue := s.FAutoincInitialValue;
  FAutoincMinValue  := s.FAutoincMinValue;
  FAutoincMaxValue  := s.FAutoincMaxValue;
  FAutoincCycled    := s.FAutoincCycled;

end;//Assign


//------------------------------------------------------------------------------
// load from stream
//------------------------------------------------------------------------------
procedure TABSFieldDef.LoadFromStream(Stream: TStream);
begin
  inherited LoadFromStream(Stream);

  LoadDataFromStream(FBaseFieldType,Sizeof(FBaseFieldType),Stream,10187);
  LoadDataFromStream(FAdvancedFieldType,Sizeof(FAdvancedFieldType),Stream,10188);
  LoadDataFromStream(FFieldSize,Sizeof(FFieldSize),Stream,10189);

  FDefaultValue.SetNull(FBaseFieldType);
  if (IsBlobFieldType(FBaseFieldType)) then
   begin
    // load blob params
    LoadDataFromStream(FBLOBCompressionAlgorithm,Sizeof(FBLOBCompressionAlgorithm),Stream,10192);
    LoadDataFromStream(FBLOBCompressionMode,Sizeof(FBLOBCompressionMode),Stream,10193);
    LoadDataFromStream(FBLOBBlockSize,Sizeof(FBLOBBlockSize),Stream,10194);
   end;

   LoadDataFromStream(FAutoincIncrement,Sizeof(FAutoincIncrement),Stream,30407);
   LoadDataFromStream(FAutoincInitialValue,Sizeof(FAutoincInitialValue),Stream,30408);
   LoadDataFromStream(FAutoincMinValue,Sizeof(FAutoincMinValue),Stream,30409);
   LoadDataFromStream(FAutoincMaxValue,Sizeof(FAutoincMaxValue),Stream,30410);
   LoadDataFromStream(FAutoincCycled,Sizeof(FAutoincCycled),Stream,30411);

   // load default value
   FDefaultValue.LoadFromStream(Stream);
   CreateDefaultValueExprIfNeeded;

   RecalcInternalSizes;
end; // LoadFromStream


//------------------------------------------------------------------------------
// save to stream
//------------------------------------------------------------------------------
procedure TABSFieldDef.SaveToStream(Stream: TStream);
begin
  inherited SaveToStream(Stream);

  SaveDataToStream(FBaseFieldType,Sizeof(FBaseFieldType),Stream,10170);
  SaveDataToStream(FAdvancedFieldType,Sizeof(FAdvancedFieldType),Stream,10171);
  SaveDataToStream(FFieldSize,Sizeof(FFieldSize),Stream,10172);

  if (IsBlobFieldType(FBaseFieldType)) then
   begin
    // save blob params
    SaveDataToStream(FBLOBCompressionAlgorithm,Sizeof(FBLOBCompressionAlgorithm),Stream,10175);
    SaveDataToStream(FBLOBCompressionMode,Sizeof(FBLOBCompressionMode),Stream,10176);
    SaveDataToStream(FBLOBBlockSize,Sizeof(FBLOBBlockSize),Stream,10177);
   end;

   SaveDataToStream(FAutoincIncrement,Sizeof(FAutoincIncrement),Stream,30412);
   SaveDataToStream(FAutoincInitialValue,Sizeof(FAutoincInitialValue),Stream,30413);
   SaveDataToStream(FAutoincMinValue,Sizeof(FAutoincMinValue),Stream,30414);
   SaveDataToStream(FAutoincMaxValue,Sizeof(FAutoincMaxValue),Stream,30415);
   SaveDataToStream(FAutoincCycled,Sizeof(FAutoincCycled),Stream,30416);

   // save default value
   FDefaultValue.SaveToStream(Stream);

end; // SaveToStream


////////////////////////////////////////////////////////////////////////////////
//
// TABSIndexColumn
//
////////////////////////////////////////////////////////////////////////////////


//------------------------------------------------------------------------------
// load from stream
//------------------------------------------------------------------------------
procedure TABSIndexColumn.LoadFromStream(Stream: TStream);
var Len: Byte;
  ans: AnsiString;
begin
  LoadDataFromStream(Len,Sizeof(Len),Stream,10358);
  SetLength(ans,Len);
  LoadDataFromStream(PAnsiChar(@ans[1])^,Len,Stream,10359);
  FFieldName := string(ans);
  LoadDataFromStream(FDescending,Sizeof(FDescending),Stream,10360);
  LoadDataFromStream(FCaseInsensitive,Sizeof(FCaseInsensitive),Stream,10361);
  LoadDataFromStream(FMaxIndexedSize,Sizeof(FMaxIndexedSize),Stream,20168);
end; // LoadFromStream


//------------------------------------------------------------------------------
// save to stream
//------------------------------------------------------------------------------
procedure TABSIndexColumn.SaveToStream(Stream: TStream);
var Len: Byte;
  ans: AnsiString;
begin
  ans := AnsiString(FFieldName);
  Len := Length(ans);
  SaveDataToStream(Len,Sizeof(Len),Stream,10354);
  SaveDataToStream(PAnsiChar(@ans[1])^,Len,Stream,10355);
  SaveDataToStream(FDescending,Sizeof(FDescending),Stream,10356);
  SaveDataToStream(FCaseInsensitive,Sizeof(FCaseInsensitive),Stream,10357);
  SaveDataToStream(FMaxIndexedSize,Sizeof(FMaxIndexedSize),Stream,20169);
end; // SaveToStream


////////////////////////////////////////////////////////////////////////////////
//
// TABSIndexDef
//
////////////////////////////////////////////////////////////////////////////////


//------------------------------------------------------------------------------
// get index column
//------------------------------------------------------------------------------
function TABSIndexDef.GetIndexColumn(Index: Integer): TABSIndexColumn;
begin
  Result := FIndexColumns[Index];
end;// GetIndexColumn


//------------------------------------------------------------------------------
// get column count
//------------------------------------------------------------------------------
function TABSIndexDef.GetColumnCount: Integer;
begin
  Result := Length(FIndexColumns);
end;// GetColumnCount


//------------------------------------------------------------------------------
// set column count
//------------------------------------------------------------------------------
procedure TABSIndexDef.SetColumnCount(Value: Integer);
var
  oldCount, i: Integer;
begin
  oldCount := Length(FIndexColumns);
  if (Value > oldCount) then
   begin
     SetLength(FIndexColumns, Value);
     for i := oldCount to Value-1 do
      FIndexColumns[i] := TABSIndexColumn.Create;
   end
  else
  if (Value < oldCount) then
   begin
     for i := Value to oldCount-1 do
      FIndexColumns[i].Free;
     SetLength(FIndexColumns, Value);
   end;
end;// SetColumnCount




//------------------------------------------------------------------------------
// create
//------------------------------------------------------------------------------
constructor TABSIndexDef.Create;
begin
  FUnique := False;
  FPrimary := False;
  FIndexType := itBTree;
  FIndexColumns := nil;
  FRootPageNo := INVALID_PAGE_NO;
  FSessionID := INVALID_SESSION_ID;
  FTableState := 0;
  FNeedRebuild := False;
end;// Create


//------------------------------------------------------------------------------
// destroy
//------------------------------------------------------------------------------
destructor TABSIndexDef.Destroy;
begin
  ColumnCount := 0;
  inherited Destroy;
end;// Destroy


//------------------------------------------------------------------------------
// assign another IndexDef
//------------------------------------------------------------------------------
procedure TABSIndexDef.Assign(Source: TABSMetaObjectDef);
var
  i: Integer;
begin
  inherited Assign(Source);
  IndexType := TABSIndexDef(Source).IndexType;
  Unique := TABSIndexDef(Source).Unique;
  Primary := TABSIndexDef(Source).Primary;
  FRootPageNo := TABSIndexDef(Source).RootPageNo;
  ColumnCount := TABSIndexDef(Source).ColumnCount;
  FTemporary := TABSIndexDef(Source).Temporary;
  FSessionID := TABSIndexDef(Source).SessionID;
  FTableState := TABSIndexDef(Source).TableState;
  FNeedRebuild := TABSIndexDef(Source).NeedRebuild;
  for i := 0 to ColumnCount-1 do
   begin
    Columns[i].FieldName := TABSIndexDef(Source).Columns[i].FieldName;
    Columns[i].Descending := TABSIndexDef(Source).Columns[i].Descending;
    Columns[i].CaseInsensitive := TABSIndexDef(Source).Columns[i].CaseInsensitive;
    Columns[i].MaxIndexedSize := TABSIndexDef(Source).Columns[i].MaxIndexedSize;
   end;
end;// Assign


//------------------------------------------------------------------------------
// assign by names
//------------------------------------------------------------------------------
procedure TABSIndexDef.AssignByNames(FieldNames, AscDescList, CaseSensitivityList: TStringList);
var i: integer;
begin
 if (FieldNames.Count <> AscDescList.Count) then
  raise EABSException.Create(10278,ErrorLDifferentListsLength,
    [FieldNames.Count,AscDescList.Count]);
 if (FieldNames.Count <> CaseSensitivityList.Count) then
  raise EABSException.Create(10279,ErrorLDifferentListsLength,
    [FieldNames.Count,CaseSensitivityList.Count]);
  ColumnCount := FieldNames.Count;
  for i := 0 to ColumnCount-1 do
   begin
    Columns[i].FieldName := FieldNames[i];
    Columns[i].Descending := (AscDescList[i] = ABS_DESC);
    Columns[i].CaseInsensitive := (CaseSensitivityList[i] = ABS_NO_CASE);
    Columns[i].MaxIndexedSize := DEFAULT_MAX_INDEXED_SIZE;
   end;
end;


//------------------------------------------------------------------------------
// load from stream
//------------------------------------------------------------------------------
procedure TABSIndexDef.LoadFromStream(Stream: TStream);
var i: Integer;
begin
  inherited LoadFromStream(Stream);

  LoadDataFromStream(FIndexType,Sizeof(FIndexType),Stream,10349);
  LoadDataFromStream(FUnique,Sizeof(FUnique),Stream,10350);
  LoadDataFromStream(FPrimary,Sizeof(FPrimary),Stream,10351);
  FTemporary := False;
  LoadDataFromStream(i,Sizeof(i),Stream,10352);
  ColumnCount := i;
  LoadDataFromStream(FRootPageNo,Sizeof(FRootPageNo),Stream,10353);
  for i := 0 to ColumnCount-1 do
    Columns[i].LoadFromStream(Stream);
end; // LoadFromStream


//------------------------------------------------------------------------------
// save to stream
//------------------------------------------------------------------------------
procedure TABSIndexDef.SaveToStream(Stream: TStream);
var i: Integer;
begin
  inherited SaveToStream(Stream);
  SaveDataToStream(FIndexType,Sizeof(FIndexType),Stream,10344);
  SaveDataToStream(FUnique,Sizeof(FUnique),Stream,10345);
  SaveDataToStream(FPrimary,Sizeof(FPrimary),Stream,10346);
  i := ColumnCount;
  SaveDataToStream(i,Sizeof(i),Stream,10347);
  SaveDataToStream(FRootPageNo,Sizeof(FRootPageNo),Stream,10348);
  for i := 0 to ColumnCount-1 do
    Columns[i].SaveToStream(Stream);
end; // SaveToStream




////////////////////////////////////////////////////////////////////////////////
//
// TABSConstraintDef
//
////////////////////////////////////////////////////////////////////////////////


//------------------------------------------------------------------------------
// Assign
//------------------------------------------------------------------------------
procedure TABSConstraintDef.Assign(Source: TABSMetaObjectDef);
begin
  inherited Assign(Source);
 FConstraintType := TABSConstraintDef(Source).FConstraintType;
end;//Assign



////////////////////////////////////////////////////////////////////////////////
//
// TABSConstraintDefNotNull
//
////////////////////////////////////////////////////////////////////////////////


//------------------------------------------------------------------------------
// Constructor
//------------------------------------------------------------------------------
constructor TABSConstraintDefNotNull.Create;
begin
  FConstraintType := ctNotNull;
end;//Create


//------------------------------------------------------------------------------
// Assign
//------------------------------------------------------------------------------
procedure TABSConstraintDefNotNull.Assign(Source: TABSMetaObjectDef);
begin
  inherited Assign(Source);
  FTableSchemaName := TABSConstraintDefNotNull(Source).FTableSchemaName;
  FTableSchemaObjectID := TABSConstraintDefNotNull(Source).FTableSchemaObjectID;
  FTableName := TABSConstraintDefNotNull(Source).FTableName;
  FTableObjectID := TABSConstraintDefNotNull(Source).FTableObjectID;
  FColumnName := TABSConstraintDefNotNull(Source).FColumnName;
  FColumnObjectID := TABSConstraintDefNotNull(Source).FColumnObjectID;
end;//Assign

//------------------------------------------------------------------------------
// SetNames
//------------------------------------------------------------------------------
procedure TABSConstraintDefNotNull.SetNames(ColumnName, TableName, SchemaName: string);
begin
  FColumnName := ShortString(ColumnName);
  FTableName := ShortString(TableName);
  FSchemaName := ShortString(SchemaName);
end;//SetNames



//------------------------------------------------------------------------------
// load from stream
//------------------------------------------------------------------------------
procedure TABSConstraintDefNotNull.LoadFromStream(Stream: TStream);
var Len: Byte;
begin
  inherited LoadFromStream(Stream);
  LoadDataFromStream(FTableSchemaObjectID,sizeof(FTableSchemaObjectID),Stream,10249);
  LoadDataFromStream(FTableObjectID,sizeof(FTableObjectID),Stream,10250);
  LoadDataFromStream(FColumnObjectID,sizeof(FColumnObjectID),Stream,10251);

  LoadDataFromStream(Len,sizeof(Len),Stream,10252);
  SetLength(FTableSchemaName,Len-1);
  LoadDataFromStream(PAnsiChar(@FTableSchemaName)^,Len,Stream,10253);

  LoadDataFromStream(Len,sizeof(Len),Stream,10254);
  SetLength(FTableName,Len-1);
  LoadDataFromStream(PAnsiChar(@FTableName)^,Len,Stream,10255);

  LoadDataFromStream(Len,sizeof(Len),Stream,10256);
  SetLength(FColumnName,Len-1);
  LoadDataFromStream(PAnsiChar(@FColumnName)^,Len,Stream,10257);
end; // LoadFromStream


//------------------------------------------------------------------------------
// save to stream
//------------------------------------------------------------------------------
procedure TABSConstraintDefNotNull.SaveToStream(Stream: TStream);
var Len: Byte;
begin
  inherited SaveToStream(Stream);

  SaveDataToStream(FTableSchemaObjectID,sizeof(FTableSchemaObjectID),Stream,10240);
  SaveDataToStream(FTableObjectID,sizeof(FTableObjectID),Stream,10241);
  SaveDataToStream(FColumnObjectID,sizeof(FColumnObjectID),Stream,10242);

  Len := Length(FTableSchemaName)+1;
  SaveDataToStream(Len,Sizeof(Len),Stream,10243);
  SaveDataToStream(PChar(@FTableSchemaName)^,Len,Stream,10244);

  Len := Length(FTableName)+1;
  SaveDataToStream(Len,Sizeof(Len),Stream,10245);
  SaveDataToStream(PChar(@FTableName)^,Len,Stream,10246);

  Len := Length(FColumnName)+1;
  SaveDataToStream(Len,Sizeof(Len),Stream,10247);
  SaveDataToStream(PChar(@FColumnName)^,Len,Stream,10248);
end; // SaveToStream


////////////////////////////////////////////////////////////////////////////////
//
// TABSConstraintDefCheck
//
////////////////////////////////////////////////////////////////////////////////


//------------------------------------------------------------------------------
// Constructor
//------------------------------------------------------------------------------
constructor TABSConstraintDefCheck.Create;
begin
  FConstraintType := ctCheck;
  FMinValue := TABSVariant.Create;
  FMaxValue := TABSVariant.Create;
end;//Create


//------------------------------------------------------------------------------
// Destructor
//------------------------------------------------------------------------------
destructor TABSConstraintDefCheck.Destroy;
begin
  FMinValue.Free;
  FMaxValue.Free;
  inherited;
end;//Destroy


//------------------------------------------------------------------------------
// Assign
//------------------------------------------------------------------------------
procedure TABSConstraintDefCheck.Assign(Source: TABSMetaObjectDef);
begin
  inherited Assign(Source);
  FTableSchemaName := TABSConstraintDefCheck(Source).FTableSchemaName;
  FTableSchemaObjectID := TABSConstraintDefCheck(Source).FTableSchemaObjectID;
  FTableName := TABSConstraintDefCheck(Source).FTableName;
  FTableObjectID := TABSConstraintDefCheck(Source).FTableObjectID;
  FColumnName := TABSConstraintDefCheck(Source).FColumnName;
  FColumnObjectID := TABSConstraintDefCheck(Source).FColumnObjectID;
  FMinValue.Assign(TABSConstraintDefCheck(Source).FMinValue);
  FMaxValue.Assign(TABSConstraintDefCheck(Source).FMaxValue);
end;//Assign


//------------------------------------------------------------------------------
// SetNames
//------------------------------------------------------------------------------
procedure TABSConstraintDefCheck.SetNames(ColumnName, TableName,
  SchemaName: string);
begin
  FColumnName := ShortString(ColumnName);
  FTableName := ShortString(TableName);
  FSchemaName := ShortString(SchemaName);
end;//SetNames


//------------------------------------------------------------------------------
// load from stream
//------------------------------------------------------------------------------
procedure TABSConstraintDefCheck.LoadFromStream(Stream: TStream);
var Len: Byte;
begin
  inherited LoadFromStream(Stream);
  LoadDataFromStream(FTableSchemaObjectID,sizeof(FTableSchemaObjectID),Stream,10230);
  LoadDataFromStream(FTableObjectID,sizeof(FTableObjectID),Stream,10231);
  LoadDataFromStream(FColumnObjectID,sizeof(FColumnObjectID),Stream,10232);

  LoadDataFromStream(Len,sizeof(Len),Stream,10233);
  SetLength(FTableSchemaName,Len-1);
  LoadDataFromStream(PAnsiChar(@FTableSchemaName)^,Len,Stream,10234);

  LoadDataFromStream(Len,sizeof(Len),Stream,10235);
  SetLength(FTableName,Len-1);
  LoadDataFromStream(PAnsiChar(@FTableName)^,Len,Stream,10236);

  LoadDataFromStream(Len,sizeof(Len),Stream,10237);
  SetLength(FColumnName,Len-1);
  LoadDataFromStream(PAnsiChar(@FColumnName)^,Len,Stream,10238);

  FMinValue.LoadFromStream(Stream);
  FMaxValue.LoadFromStream(Stream);
end; // LoadFromStream


//------------------------------------------------------------------------------
// save to stream
//------------------------------------------------------------------------------
procedure TABSConstraintDefCheck.SaveToStream(Stream: TStream);
var Len: Byte;
begin
  inherited SaveToStream(Stream);

  SaveDataToStream(FTableSchemaObjectID,sizeof(FTableSchemaObjectID),Stream,10227);
  SaveDataToStream(FTableObjectID,sizeof(FTableObjectID),Stream,10228);
  SaveDataToStream(FColumnObjectID,sizeof(FColumnObjectID),Stream,10229);

  Len := Length(FTableSchemaName)+1;
  SaveDataToStream(Len,Sizeof(Len),Stream,10221);
  SaveDataToStream(PAnsiChar(@FTableSchemaName)^,Len,Stream,10222);

  Len := Length(FTableName)+1;
  SaveDataToStream(Len,Sizeof(Len),Stream,10223);
  SaveDataToStream(PAnsiChar(@FTableName)^,Len,Stream,10224);

  Len := Length(FColumnName)+1;
  SaveDataToStream(Len,Sizeof(Len),Stream,10225);
  SaveDataToStream(PAnsiChar(@FColumnName)^,Len,Stream,10226);

   FMinValue.SaveToStream(Stream);
   FMaxValue.SaveToStream(Stream);
end; // SaveToStream


////////////////////////////////////////////////////////////////////////////////
//
// TABSConstraintDefUnique
//
////////////////////////////////////////////////////////////////////////////////


//------------------------------------------------------------------------------
// Constructor
//------------------------------------------------------------------------------
constructor TABSConstraintDefUnique.Create;
begin
  inherited;
  FConstraintType := ctUnique;
  SetLength(Columns,0);
end;//Create


//------------------------------------------------------------------------------
// Destructor
//------------------------------------------------------------------------------
destructor TABSConstraintDefUnique.Destroy;
begin
  inherited;
end;//Destroy


//------------------------------------------------------------------------------
// Assign
//------------------------------------------------------------------------------
procedure TABSConstraintDefUnique.Assign(Source: TABSMetaObjectDef);
var i,L: Integer;
begin
  inherited Assign(Source);
  L := Length(TABSConstraintDefUnique(Source).Columns);
  SetLength(Columns, L);
  for i:=0 to L-1 do
    Columns[i] := TABSConstraintDefUnique(Source).Columns[i];

  FTableSchemaName := TABSConstraintDefUnique(Source).FTableSchemaName;
  FTableSchemaObjectID := TABSConstraintDefUnique(Source).FTableSchemaObjectID;
  FTableName := TABSConstraintDefUnique(Source).FTableName;
  FTableObjectID := TABSConstraintDefUnique(Source).FTableObjectID;
  FIndexName := TABSConstraintDefUnique(Source).FIndexName;
  FIndexObjectID := TABSConstraintDefUnique(Source).FIndexObjectID;

end;//Assign


//------------------------------------------------------------------------------
// load from stream
//------------------------------------------------------------------------------
procedure TABSConstraintDefUnique.LoadFromStream(Stream: TStream);
var i,j, Len: Integer;
  ss: ShortString;
begin
  inherited LoadFromStream(Stream);

  LoadDataFromStream(FTableSchemaObjectID, sizeof(FTableSchemaObjectID), Stream, 30303);
  LoadDataFromStream(FTableObjectID,  sizeof(FTableObjectID),  Stream, 30304);
  LoadDataFromStream(FIndexObjectID,  sizeof(FIndexObjectID),  Stream, 30317);

  LoadDataFromStream(Len,sizeof(Len),Stream,30305);
  SetLength(ss ,Len-1);
  LoadDataFromStream(PAnsiChar(@ss)^,Len,Stream,30306);
  FTableSchemaName := string(ss);

  LoadDataFromStream(Len,sizeof(Len),Stream,30307);
  SetLength(ss,Len-1);
  LoadDataFromStream(PAnsiChar(@ss)^,Len,Stream,30308);
  FTableName := string(ss);

  LoadDataFromStream(Len,sizeof(Len),Stream,30321);
  SetLength(ss,Len-1);
  LoadDataFromStream(PAnsiChar(@ss)^,Len,Stream,30322);
  FIndexName := string(ss);

  LoadDataFromStream(j,sizeof(j),Stream,30309);
  SetLength(Columns,j);
  for i:=0 to j-1 do
    begin
      LoadDataFromStream(Columns[i].ColumnObjectID,sizeof(Columns[i].ColumnObjectID),Stream,30310);
      LoadDataFromStream(Len,sizeof(Len),Stream,30311);
      SetLength(ss, Len);
      LoadDataFromStream(PAnsiChar(@ss)^,Len,Stream,30312);
      Columns[i].ColumnName := string(ss);
    end;
end; // LoadFromStream


//------------------------------------------------------------------------------
// save to stream
//------------------------------------------------------------------------------
procedure TABSConstraintDefUnique.SaveToStream(Stream: TStream);
var i,j, Len: Integer;
begin
  inherited SaveToStream(Stream);

  SaveDataToStream(FTableSchemaObjectID, sizeof(FTableSchemaObjectID), Stream, 30313);
  SaveDataToStream(FTableObjectID,  sizeof(FTableObjectID),  Stream, 30314);
  SaveDataToStream(FIndexObjectID,  sizeof(FIndexObjectID),  Stream, 30318);

  Len := Length(FTableSchemaName)+1;
  SaveDataToStream(Len,Sizeof(Len),Stream,30315);
  SaveDataToStream(PAnsiChar(@FTableSchemaName)^,Len,Stream,30316);

  Len := Length(FTableName)+1;
  SaveDataToStream(Len,Sizeof(Len),Stream,30317);
  SaveDataToStream(PAnsiChar(@FTableName)^,Len,Stream,30318);

  Len := Length(FIndexName)+1;
  SaveDataToStream(Len,Sizeof(Len),Stream,30323);
  SaveDataToStream(PAnsiChar(@FIndexName)^,Len,Stream,30324);

  j := Length(Columns);
  SaveDataToStream(j,sizeof(j),Stream,30319);
  for i:=0 to j-1 do
    begin
      SaveDataToStream(Columns[i].ColumnObjectID,sizeof(Columns[i].ColumnObjectID),Stream,30320);
      Len := Length(Columns[i].ColumnName)+1;
      SaveDataToStream(Len,sizeof(Len),Stream,30321);
      SaveDataToStream(PAnsiChar(@Columns[i].ColumnName)^,Len,Stream,30322);
    end;
end;//SaveToStream


////////////////////////////////////////////////////////////////////////////////
//
// TABSMetaObjectDefs
//
////////////////////////////////////////////////////////////////////////////////


//------------------------------------------------------------------------------
// Constructor
//------------------------------------------------------------------------------
constructor TABSConstraintDefPrimary.Create;
begin
  inherited;
  FConstraintType := ctPK;
end;//Create



////////////////////////////////////////////////////////////////////////////////
//
// TABSMetaObjectDefs
//
////////////////////////////////////////////////////////////////////////////////


//------------------------------------------------------------------------------
// load from stream
//------------------------------------------------------------------------------
procedure TABSMetaObjectDefs.LoadFromStream(Stream: TStream);
begin
 Clear;
 LoadDataFromStream(FLoadedItemCount,sizeof(FLoadedItemCount),Stream,10159);
end; // LoadFromStream


//------------------------------------------------------------------------------
// save to stream
//------------------------------------------------------------------------------
procedure TABSMetaObjectDefs.SaveToStream(Stream: TStream);
var ItemCount:  Integer;
begin
 ItemCount := Self.Count;
 SaveDataToStream(ItemCount,sizeof(ItemCount),Stream,10158);
end; // SaveToStream


//------------------------------------------------------------------------------
// Constructor
//------------------------------------------------------------------------------
constructor TABSMetaObjectDefs.Create;
begin
  FDefsList := TABSSortedStringPtrArray.Create;
end;//Create


//------------------------------------------------------------------------------
// Destructor
//------------------------------------------------------------------------------
destructor TABSMetaObjectDefs.Destroy;
begin
  Clear;
  FDefsList.Free;
end;//Destroy


//------------------------------------------------------------------------------
// Assign
//------------------------------------------------------------------------------
procedure TABSMetaObjectDefs.Assign(Source: TABSMetaObjectDefs);
var i,k: Integer;
begin
  Clear;
  for i:=0 to Source.Count-1 do
   begin
    k := GetDefNumberByName(Source[i].Name);
    if (k >= 0) then
      raise EABSException.Create(10424,ErrorLDuplicateFieldName,
        [Source[i].Name]);
    InternalAddCreated.Assign(Source.Items[i]);
   end;
end;//Assign


//------------------------------------------------------------------------------
// GetCount
//------------------------------------------------------------------------------
function TABSMetaObjectDefs.GetCount: Integer;
begin
  Result := FDefsList.Count;
end;//GetCount



//------------------------------------------------------------------------------
// GetDef
//------------------------------------------------------------------------------
function TABSMetaObjectDefs.GetDef(Index: Integer): TABSMetaObjectDef;
begin
  Result := TABSMetaObjectDef(FDefsList[Index]);
end;//GetDef


//------------------------------------------------------------------------------
// SetDef
//------------------------------------------------------------------------------
procedure TABSMetaObjectDefs.SetDef(Index: Integer;
  Value: TABSMetaObjectDef);
begin
  TABSMetaObjectDef(FDefsList[Index]).Free;
  FDefsList[Index] := Value;
end;//SetDef


//------------------------------------------------------------------------------
// GetDefNumberByName
//    ( if name not found, then Result = -1 )
//------------------------------------------------------------------------------
function TABSMetaObjectDefs.GetDefNumberByName(Name: string): Integer;
var i: Integer;
begin
  Result := -1;
  for i:=0 to FDefsList.Count -1 do
    if (AnsiUpperCase(TABSMetaObjectDef(FDefsList[i]).Name) = AnsiUpperCase(Name)) then
      begin
        Result := i;
        break;
      end;
end;//GetDefNumberByName


//------------------------------------------------------------------------------
// GetDefByName
//------------------------------------------------------------------------------
function TABSMetaObjectDefs.GetDefByName(Name: string): TABSMetaObjectDef;
var i: Integer;
begin
  i := GetDefNumberByName(Name);
  if i = -1 then
    Result := nil
  else
    Result := TABSMetaObjectDef(Items[i]);
end;//GetDefByName


//------------------------------------------------------------------------------
// GetDefNumberByObjectId
//------------------------------------------------------------------------------
function TABSMetaObjectDefs.GetDefNumberByObjectId(id: TABSObjectID): Integer;
var i: Integer;
begin
  Result := -1;
  for i:=0 to FDefsList.Count -1 do
    if (TABSMetaObjectDef(FDefsList[i]).ObjectID = id) then
      begin
        Result := i;
        break;
      end;
end;//GetDefNumberByObjectId


//------------------------------------------------------------------------------
// GetDefByByObjectId
//------------------------------------------------------------------------------
function TABSMetaObjectDefs.GetDefByObjectId(id: TABSObjectID): TABSMetaObjectDef;
var i: Integer;
begin
  i := GetDefNumberByObjectId(id);
  if i <> -1 then
    Result := Items[i]
  else
    Result := nil;
end;//GetDefByByObjectId


//------------------------------------------------------------------------------
// Add
//------------------------------------------------------------------------------
procedure TABSMetaObjectDefs.Add(MetaObjectDef: TABSMetaObjectDef);
begin
  FDefsList.Add(MetaObjectDef);
end;//Add


//------------------------------------------------------------------------------
// internal add created
//------------------------------------------------------------------------------
function TABSMetaObjectDefs.InternalAddCreated: TABSMetaObjectDef;
begin
  raise EABSException.Create(30339, ErrorGMethodNotOverrided,
                                            ['InternalAddCreated', classname]);
end; // InternalAddCreated


//------------------------------------------------------------------------------
// Delete
//------------------------------------------------------------------------------
procedure TABSMetaObjectDefs.Delete(Index: Integer);
begin
 if FDefsList[Index] <> nil then
    TABSMetaObjectDef(FDefsList[Index]).Free;
 FDefsList.Delete(Index);
end;//Delete


//------------------------------------------------------------------------------
// Insert
//------------------------------------------------------------------------------
procedure TABSMetaObjectDefs.Insert(Index: Integer; MetaObjectDef: TABSMetaObjectDef);
begin
  FDefsList.Insert(Index, MetaObjectDef);
end;//Insert


//------------------------------------------------------------------------------
// Clear
//------------------------------------------------------------------------------
procedure TABSMetaObjectDefs.Clear;
begin
  while (Count > 0) do
    Delete(0);
  FDefsList.Clear;
end;//Clear



//------------------------------------------------------------------------------
// Move
//------------------------------------------------------------------------------
procedure TABSMetaObjectDefs.Move(CurIndex, NewIndex: Integer);
begin
  FDefsList.Move(CurIndex, NewIndex);
end;//Move




////////////////////////////////////////////////////////////////////////////////
//
// TABSIndexDefs
//
////////////////////////////////////////////////////////////////////////////////


//------------------------------------------------------------------------------
// get index def
//------------------------------------------------------------------------------
function TABSIndexDefs.GetIndexDef(Index: Integer): TABSIndexDef;
begin
  Result := TABSIndexDef(GetDef(Index));
end;// GetIndexDef


//------------------------------------------------------------------------------
// set index def
//------------------------------------------------------------------------------
procedure TABSIndexDefs.SetIndexDef(Index: Integer; Value: TABSIndexDef);
begin
  SetDef(Index, Value);
end;// SetIndexDef


//------------------------------------------------------------------------------
// InternalAddCreated
//------------------------------------------------------------------------------
function TABSIndexDefs.InternalAddCreated: TABSMetaObjectDef;
begin
  Result := TABSIndexDef.Create;
  Add(Result);
end;//InternalAddCreated


//------------------------------------------------------------------------------
// AscDesc and CaseSensitivity lists should contain constants ABS_ASC, ABS_DESC, ABS_NO_CASE, ABS_CASE
//------------------------------------------------------------------------------
function TABSIndexDefs.IsIndexExists(FieldNames, AscDescList,
                                     CaseSensitivityList: TStringList;
                                     SessionID: TABSSessionID;
                                     FieldDefs: TABSFieldDefs): Boolean;
begin
  Result := not
   (FindIndex(FieldNames,AscDescList,CaseSensitivityList,SessionID,FieldDefs) = INVALID_OBJECT_ID);
end; // IsIndexExists


//------------------------------------------------------------------------------
// find index
//------------------------------------------------------------------------------
function TABSIndexDefs.FindIndex(FieldNames, AscDescList, CaseSensitivityList: TStringList;
                       SessionID: TABSSessionID; FieldDefs: TABSFieldDefs): TABSObjectID;
var i,j,n:  Integer;
    bOK:    Boolean;
    bStringField: Boolean;
begin
 Result := INVALID_OBJECT_ID;
 if (FieldNames = nil) then
  raise EABSException.Create(10389,ErrorLNilPointer);
 if (AscDescList = nil) then
  raise EABSException.Create(10390,ErrorLNilPointer);
 if (CaseSensitivityList = nil) then
  raise EABSException.Create(10391,ErrorLNilPointer);
 if (FieldNames.Count <> AscDescList.Count) then
  raise EABSException.Create(10276,ErrorLDifferentListsLength,
    [FieldNames.Count,AscDescList.Count]);
 if (FieldNames.Count <> CaseSensitivityList.Count) then
  raise EABSException.Create(10277,ErrorLDifferentListsLength,
    [FieldNames.Count,CaseSensitivityList.Count]);
 n := 0;
 for i := 0 to Self.Count - 1 do
  begin
   if (Items[i].GetColumnCount < FieldNames.Count) then
    continue
   else
    n := FieldNames.Count-1;
   if ((Items[i].Temporary) and (Items[i].SessionID <> SessionID)) then
     continue;
   bOK := True;
   for j := 0 to n do
    if (UpperCase(FieldNames[j]) = UpperCase(Items[i].Columns[j].FieldName)) then
     begin
     bStringField :=
        IsStringFieldType(FieldDefs.GetFieldDefByName(FieldNames[j]).BaseFieldType) or
        IsWideStringFieldType(FieldDefs.GetFieldDefByName(FieldNames[j]).BaseFieldType);

     if (
          ((AscDescList[j] = ABS_ASC) and (Items[i].Columns[j].FDescending)) or
          ((AscDescList[j] = ABS_DESC) and (not Items[i].Columns[j].FDescending)) or
          (bStringField and
           ((CaseSensitivityList[j] = ABS_CASE) and (Items[i].Columns[j].FCaseInsensitive)) or
           ((CaseSensitivityList[j] = ABS_NO_CASE) and (not Items[i].Columns[j].FCaseInsensitive))
          )
         ) then
      begin
        bOK := False;
        break;
      end;
     end
    else
     begin
      bOK := False;
      break;
     end;
   if (bOK) then
    begin
     Result := Items[i].ObjectID;
     break;
    end;
  end;
end;


//------------------------------------------------------------------------------
// AddCreated
//------------------------------------------------------------------------------
function TABSIndexDefs.AddCreated: TABSIndexDef;
begin
  Result := TABSIndexDef(InternalAddCreated);
end;//AddCreated


//------------------------------------------------------------------------------
// GetIndexDefByIndexName
//------------------------------------------------------------------------------
function TABSIndexDefs.GetIndexDefByName(Name: string): TABSIndexDef;
var
  i: Integer;
begin
  i := GetDefNumberByName(Name);
  if i = -1 then
    Result := nil
  else
    Result := TABSIndexDef(Items[i]);
end;//GetIndexDefByIndexName


//------------------------------------------------------------------------------
// load from stream
//------------------------------------------------------------------------------
procedure TABSIndexDefs.LoadFromStream(Stream: TStream);
var IndexDef: TABSIndexDef;
    i:        Integer;
begin
 inherited LoadFromStream(Stream);
 for i := 0 to FLoadedItemCount-1 do
  begin
   IndexDef := TABSIndexDef.Create;
   IndexDef.LoadFromStream(Stream);
   Add(IndexDef);
  end;
end; // LoadFromStream


//------------------------------------------------------------------------------
// save to stream
//------------------------------------------------------------------------------
procedure TABSIndexDefs.SaveToStream(Stream: TStream);
var i:    Integer;
    qty:  Integer;
begin
 qty := 0;
 for i := 0 to Count-1 do
  if (not Items[i].FTemporary) then
   Inc(qty);
 SaveDataToStream(qty,sizeof(qty),Stream,10343);
 for i := 0 to Count-1 do
  if (not Items[i].FTemporary) then
   TABSIndexDef(Items[i]).SaveToStream(Stream);
end; // SaveToStream




////////////////////////////////////////////////////////////////////////////////
//
// TABSFieldDefs
//
////////////////////////////////////////////////////////////////////////////////



//------------------------------------------------------------------------------
// GetFieldDef
//------------------------------------------------------------------------------
function TABSFieldDefs.GetDef(Index: Integer): TABSFieldDef;
begin
  Result := TABSFieldDef(FDefsList[Index]);
end;//GetFieldDef


//------------------------------------------------------------------------------
// SetFieldDef
//------------------------------------------------------------------------------
procedure TABSFieldDefs.SetDef(Index: Integer; Value: TABSFieldDef);
begin
  TABSFieldDef(FDefsList[Index]).Free;
  FDefsList[Index] := Value;
end;//SetFieldDef


//------------------------------------------------------------------------------
// InternalAddCreated
//------------------------------------------------------------------------------
function TABSFieldDefs.InternalAddCreated: TABSMetaObjectDef;
begin
  Result := TABSFieldDef.Create;
  Add(Result);
end;//InternalAddCreated


//------------------------------------------------------------------------------
// AddCreated
//------------------------------------------------------------------------------
function TABSFieldDefs.AddCreated: TABSFieldDef;
begin
  Result := TABSFieldDef(InternalAddCreated);
end;//AddCreated


//------------------------------------------------------------------------------
// Recalc FieldOffsets in children fields
//------------------------------------------------------------------------------
procedure TABSFieldDefs.RecalcFieldOffsets;
var i: integer;
    CurMemOffset, CurDiskOffset: Integer;
    FieldDef: TABSFieldDef;
begin
  // Init Offsets
  CurMemOffset := Count div 8;
  if (Count mod 8 > 0) then Inc(CurMemOffset);
  CurDiskOffset := Count div 8;
  if (Count mod 8 > 0) then Inc(CurDiskOffset);
  // Fill offsets
  for i:=0 to FDefsList.Count-1 do
   begin
     FieldDef := FDefsList[i];
     FieldDef.FMemoryOffset := CurMemOffset;
     FieldDef.FDiskOffset := CurDiskOffset;
     CurMemOffset := CurMemOffset + FieldDef.FMemoryDataSize;
     CurDiskOffset := CurDiskOffset + FieldDef.FDiskDataSize;
   end;
end;//RecalcFieldOffsets


//------------------------------------------------------------------------------
// GetMemoryRecordBufferSize
//------------------------------------------------------------------------------
function TABSFieldDefs.GetMemoryRecordBufferSize: Integer;
var i: integer;
begin
  Result := 0;
  // 1 bit for each field ( NULL flags )
  Result := Result + Integer(Count) div 8;
  if (Count mod 8 > 0) then Inc(Result);
  for i:=0 to Count-1 do
    Result := Result + Items[i].FMemoryDataSize;
end;//GetMemoryRecordBufferSize


//------------------------------------------------------------------------------
// GetDiskRecordBufferSize
//------------------------------------------------------------------------------
function TABSFieldDefs.GetDiskRecordBufferSize: Integer;
var
  i: integer;
begin
  Result := 0;
  // 1 bit for each field ( NULL flags )
  Result := Result + Integer(Count) div 8;
  if (Count mod 8 > 0) then Inc(Result);
  for i:=0 to Count-1 do
    Result := Result + Items[i].FDiskDataSize;
end;// GetDiskRecordBufferSize


//------------------------------------------------------------------------------
// GetFieldDefByFieldName
//------------------------------------------------------------------------------
function TABSFieldDefs.GetFieldDefByName(Name: string): TABSFieldDef;
begin
  Result := TABSFieldDef(GetDefByName(Name));
end;//GetFieldDefByFieldName


//------------------------------------------------------------------------------
// load from stream
//------------------------------------------------------------------------------
procedure TABSFieldDefs.LoadFromStream(Stream: TStream);
var
    FieldDef: TABSFieldDef;
    i:        Integer;
begin
  inherited LoadFromStream(Stream);
  for i := 0 to FLoadedItemCount-1 do
   begin
     FieldDef := TABSFieldDef.Create;
     FieldDef.LoadFromStream(Stream);
     Add(FieldDef);
   end;
end; // LoadFromStream


//------------------------------------------------------------------------------
// save to stream
//------------------------------------------------------------------------------
procedure TABSFieldDefs.SaveToStream(Stream: TStream);
var i: Integer;
begin
  inherited SaveToStream(Stream);
 for i := 0 to Count-1 do
  TABSFieldDef(Items[i]).SaveToStream(Stream);
end; // SaveToStream



////////////////////////////////////////////////////////////////////////////////
//
// TABSConstraintDefs
//
////////////////////////////////////////////////////////////////////////////////


//------------------------------------------------------------------------------
// AddNotNull
//------------------------------------------------------------------------------
function TABSConstraintDefs.AddNotNull: TABSConstraintDefNotNull;
begin
  Result := TABSConstraintDefNotNull.Create;
  Add(Result);
end;//AddNotNull


//------------------------------------------------------------------------------
// AddCheck
//------------------------------------------------------------------------------
function TABSConstraintDefs.AddCheck: TABSConstraintDefCheck;
begin
  Result := TABSConstraintDefCheck.Create;
  Add(Result);
end;//AddCheck


//------------------------------------------------------------------------------
// Add PK
//------------------------------------------------------------------------------
function TABSConstraintDefs.AddPK: TABSConstraintDefPrimary;
begin
  Result := TABSConstraintDefPrimary.Create;
  Add(Result);
end;//AddPK


//------------------------------------------------------------------------------
// Add Unique
//------------------------------------------------------------------------------
function TABSConstraintDefs.AddUnique: TABSConstraintDefUnique;
begin
  Result := TABSConstraintDefUnique.Create;
  Add(Result);
end;//AddUnique


//------------------------------------------------------------------------------
// Assign
//------------------------------------------------------------------------------
procedure TABSConstraintDefs.Assign(Source: TABSMetaObjectDefs);
var i: Integer;
begin
  Clear;
  for i:=0 to Source.Count-1 do
   begin
    case TABSConstraintDef(Source.Items[i]).ConstraintType of
     ctNotNull:
       AddNotNull.Assign(TABSConstraintDefNotNull(Source.Items[i]));
     ctCheck:
       AddCheck.Assign(TABSConstraintDefCheck(Source.Items[i]));
     ctPK:
       AddPK.Assign(TABSConstraintDefPrimary(Source.Items[i]));
     ctUnique:
       AddUnique.Assign(TABSConstraintDefUnique(Source.Items[i]));
     else
       raise EABSException.Create(30035, ErrorGNotImplementedYet);
    end;
   end;
end;//Assign


//------------------------------------------------------------------------------
// GetDef
//------------------------------------------------------------------------------
function TABSConstraintDefs.GetDef(Index: Integer): TABSConstraintDef;
begin
  Result := TABSConstraintDef(FDefsList[Index]);
end;//GetDef


//------------------------------------------------------------------------------
// SetDef
//------------------------------------------------------------------------------
procedure TABSConstraintDefs.SetDef(Index: Integer; Value: TABSConstraintDef);
begin
  if FDefsList[Index] <> nil then
    TABSConstraintDef(FDefsList[Index]).Free;
  FDefsList[Index] := Value;
end;//SetDef


//------------------------------------------------------------------------------
// load from stream
//------------------------------------------------------------------------------
procedure TABSConstraintDefs.LoadFromStream(Stream: TStream);
var i:              Integer;
    ConstraintDef:  TABSConstraintDef;
    ConstraintType: TABSConstraintType;
begin
  inherited LoadFromStream(Stream);
  for i := 0 to FLoadedItemCount - 1 do
    begin
      LoadDataFromStream(ConstraintType,sizeof(ConstraintType),Stream,10220);
      case ConstraintType of
        ctNotNull:
         ConstraintDef := TABSConstraintDefNotNull.Create;
        ctCheck:
         ConstraintDef := TABSConstraintDefCheck.Create;
        ctPK:
         ConstraintDef := TABSConstraintDefPrimary.Create;
        ctUnique:
         ConstraintDef := TABSConstraintDefUnique.Create;
        else
          raise EABSException.Create(30316, ErrorGUnknownConstrainType,
                                     [Integer(ConstraintType)]);
      end;

      Add(ConstraintDef);
      ConstraintDef.LoadFromStream(Stream);
    end;
end; // LoadFromStream


//------------------------------------------------------------------------------
// save to stream
//------------------------------------------------------------------------------
procedure TABSConstraintDefs.SaveToStream(Stream: TStream);
var i: Integer;
begin
  inherited SaveToStream(Stream);
  for i := 0 to Count-1 do
   begin
    SaveDataToStream(Items[i].FConstraintType,sizeof(Items[i].ConstraintType),
      Stream,10219);
    Items[i].SaveToStream(Stream);
   end;
end; // SaveToStream



////////////////////////////////////////////////////////////////////////////////
//
// TABSCursor
//
////////////////////////////////////////////////////////////////////////////////


//------------------------------------------------------------------------------
// set index name
//------------------------------------------------------------------------------
procedure TABSCursor.SetIndexName(Value: string);
var
  ABSIndexDef: TABSIndexDef;
begin
  FIndexName := Value;
  ABSIndexDef := FIndexDefs.GetIndexDefByName(Value);
  if (ABSIndexDef <> nil) then
    FIndexID := ABSIndexDef.ObjectID
  else
    FIndexID := INVALID_OBJECT_ID;
end;// SetIndexName


//------------------------------------------------------------------------------
// Rename Field by Field Index in FieldDefs
//------------------------------------------------------------------------------
procedure TABSCursor.RenameField(FieldName, NewFieldName: string);
var
  fd: TABSFieldDef;
begin
  // Check Field Exists
  fd := FFieldDefs.GetFieldDefByName(FieldName);
  if (fd = nil) then
    raise EABSException.Create(30345, ErrorGFieldWithNameNotFound, [FieldName]);

  // Check For Duplicate FieldName
  if ( FFieldDefs.GetFieldDefByName(NewFieldName) <> nil ) then
   raise EABSException.Create(30346, ErrorGCannotRenameField,
                                     [FieldName, NewFieldName]);

  fd.Name := NewFieldName;
end;//RenameField


//------------------------------------------------------------------------------
// GetIndexDefs
//------------------------------------------------------------------------------
function TABSCursor.GetIndexDefs: TABSIndexDefs;
begin
  Result := FIndexDefs;
end;// GetIndexDefs


//------------------------------------------------------------------------------
// check field value and if not null move data from RecordBuffer to Buffer
//------------------------------------------------------------------------------
function TABSCursor.GetFieldData(
                          FieldNo:      Integer; // field no
                          Buffer:       Pointer; // buffer
                          RecordBuffer: TABSRecordBuffer // record buffer
                                      ): Boolean;
begin
 if (FieldNo >= VisibleFieldDefs.Count) then
   raise EABSException.Create(10005,ErrorLInvalidFieldNumber,[FieldNo,VisibleFieldDefs.Count]);
 Result := ABSBaseEngine.GetFieldData(VisibleFieldDefs[FieldNo].FieldNoReference,
                                      FieldDefs,Buffer,RecordBuffer);
end; // GetFieldData


//------------------------------------------------------------------------------
// set field data from Buffer to RecordBuffer
//------------------------------------------------------------------------------
procedure TABSCursor.SetFieldData(
                            FieldNo:      Integer;
                            Buffer:       Pointer;
                            RecordBuffer: TABSRecordBuffer // record buffer
                                      );
begin
 if (FieldNo >= VisibleFieldDefs.Count) then
   raise EABSException.Create(10006,ErrorLInvalidFieldNumber,[FieldNo,VisibleFieldDefs.Count]);
 ABSBaseEngine.SetFieldData(VisibleFieldDefs[FieldNo].FieldNoReference,
                                      FieldDefs,Buffer,RecordBuffer);
end; // SetFieldData


//------------------------------------------------------------------------------
// clear garbage after the end of strings in record buffer
//------------------------------------------------------------------------------
procedure TABSCursor.ClearStringFieldsGarbage(RecordBuffer: TABSRecordBuffer);
var
  FieldNo: Integer;
  Offset, Size: Integer;
begin
  for FieldNo:=0 to FieldDefs.Count-1 do
    if (not CheckNullFlag(FieldNo,RecordBuffer)) then
      begin
        case FieldDefs[FieldNo].BaseFieldType of
          bftChar, bftVarchar:
            begin
              Offset := FieldDefs.Items[FieldNo].MemoryOffset+StrLen(PAnsiChar(RecordBuffer+FieldDefs.Items[FieldNo].MemoryOffset));
              Size := FieldDefs.Items[FieldNo].MemoryDataSize-StrLen(PAnsiChar(RecordBuffer+FieldDefs.Items[FieldNo].MemoryOffset));
              FillChar(PAnsiChar(RecordBuffer+Offset)^,Size,#0);
            end;
          bftWideChar, bftWideVarchar:
            begin
              Offset := FieldDefs.Items[FieldNo].MemoryOffset+2*Length(WideString(PWideChar(RecordBuffer+FieldDefs.Items[FieldNo].MemoryOffset)));
              Size := FieldDefs.Items[FieldNo].MemoryDataSize-2*Length(WideString(PWideChar(RecordBuffer+FieldDefs.Items[FieldNo].MemoryOffset)));
              FillChar(PAnsiChar(RecordBuffer+Offset)^,Size,#0);
            end;
        end;
      end
    else
      if (FieldDefs[FieldNo].BaseFieldType in [bftChar, bftVarchar, bftWideChar, bftWideVarchar]) then
        FillChar(PAnsiChar(RecordBuffer + FieldDefs.Items[FieldNo].MemoryOffset)^,
                 FieldDefs.Items[FieldNo].MemoryDataSize,#0);
end;// ClearStringFieldsGarbage(RecordBuffer


//------------------------------------------------------------------------------
// get field value
//------------------------------------------------------------------------------
procedure TABSCursor.GetFieldValue(Value: TABSVariant; FieldNo: Integer; DirectAccess: Boolean);
var IsNull: Boolean;
    Offset: Integer;
    Buffer: PAnsiChar;
begin
 // access to field defs without projection?
 if (DirectAccess) then
  begin
   if (FieldNo >= FieldDefs.Count) then
     raise EABSException.Create(20191,ErrorLInvalidFieldNumber,
              [FieldNo,FieldDefs.Count]);
   IsNull := CheckNullFlag(FieldNo, CurrentRecordBuffer);
   if (IsNull) then
    Value.SetNull
   else
    begin
     Offset := FieldDefs[FieldNo].MemoryOffset;
     Buffer := PAnsiChar(CurrentRecordBuffer + Offset);
     Value.SetData(
                          Buffer,
                          FieldDefs[FieldNo].MemoryDataSize,
                          FieldDefs[FieldNo].FBaseFieldType
                         );
    end;
  end
 else
  begin
  // access to fields with projection
   if (FieldNo >= VisibleFieldDefs.Count) then
     raise EABSException.Create(10317,ErrorLInvalidFieldNumber,
              [FieldNo,VisibleFieldDefs.Count]);
   IsNull := CheckNullFlag(VisibleFieldDefs[FieldNo].FieldNoReference, CurrentRecordBuffer);
   if (IsNull) then
    Value.SetNull
   else
    begin
     Offset := VisibleFieldDefs[FieldNo].MemoryOffset;
     Buffer := PAnsiChar(CurrentRecordBuffer + Offset);
     Value.SetData(
                          Buffer,
                          VisibleFieldDefs[FieldNo].MemoryDataSize,
                          VisibleFieldDefs[FieldNo].FBaseFieldType
                         );
    end;
  end;
end; // GetFieldValue


//------------------------------------------------------------------------------
// get field value
//------------------------------------------------------------------------------
procedure TABSCursor.SetFieldValue(
                            Value:        TABSVariant;
                            FieldNo:      Integer;
                            DirectAccess: Boolean;
                            RecordBuffer: TABSRecordBuffer = nil
                                  );
var Buffer: PAnsiChar;
    Offset: Integer;
begin
 if (RecordBuffer = nil) then
   RecordBuffer := CurrentRecordBuffer;

 // access to field defs without projection?
 if (DirectAccess) then
  begin
   if (FieldNo >= FieldDefs.Count) then
     raise EABSException.Create(20192, ErrorLInvalidFieldNumber,
            [FieldNo,FieldDefs.Count]);
   if (Value.IsNull) then
    begin
     SetNullFlag(True,FieldNo,RecordBuffer);
    end
   else
    begin
     SetNullFlag(False,FieldNo,RecordBuffer);
     Offset := FieldDefs[FieldNo].MemoryOffset;
     Buffer := PAnsiChar(RecordBuffer + Offset);
     Value.Cast(FieldDefs[FieldNo].FBaseFieldType);
     Value.CopyDataToAddress(Buffer,FieldDefs[FieldNo].MemoryDataSize);
    end;
  end
 else
  begin
   // access to fields with projection
   if (FieldNo >= VisibleFieldDefs.Count) then
     raise EABSException.Create(20193,ErrorLInvalidFieldNumber,
            [FieldNo,VisibleFieldDefs.Count]);
   if (Value.IsNull) then
    begin
     SetNullFlag(True,VisibleFieldDefs[FieldNo].FieldNoReference,RecordBuffer);
    end
   else
    begin
     SetNullFlag(False,VisibleFieldDefs[FieldNo].FieldNoReference,RecordBuffer);
     Offset := VisibleFieldDefs[FieldNo].MemoryOffset;
     Buffer := PAnsiChar(RecordBuffer + Offset);
     Value.Cast(VisibleFieldDefs[FieldNo].FBaseFieldType);
     Value.CopyDataToAddress(Buffer,VisibleFieldDefs[FieldNo].MemoryDataSize);
    end;
  end;
end; // SetFieldValue


//------------------------------------------------------------------------------
// allocate record buffer and set null flags
//------------------------------------------------------------------------------
function TABSCursor.AllocateRecordBuffer: TABSRecordBuffer;
begin
// Result := MemoryManager.GetMem(RecordBufferSize);
 // init mem by #0 required to init BLOB fields in disk mode
 Result := MemoryManager.AllocMem(RecordBufferSize);
end; // AllocateRecordBuffer


//------------------------------------------------------------------------------
// free record buffer
//------------------------------------------------------------------------------
procedure TABSCursor.FreeRecordBuffer(var Buffer: TABSRecordBuffer);
begin
  MemoryManager.FreeAndNillMem(Buffer);
end; // FreeRecordBuffer


//------------------------------------------------------------------------------
// allocate record buffer and set null flags
//------------------------------------------------------------------------------
function TABSCursor.AllocateKeyRecordBuffer: TABSRecordBuffer;
begin
  Result := MemoryManager.GetMem(KeyBufferSize);
end;


//------------------------------------------------------------------------------
// initialize record buffer
//------------------------------------------------------------------------------
procedure TABSCursor.InternalInitKeyBuffer(RecordBuffer: TABSRecordBuffer);
begin
  FillChar(RecordBuffer^,KeyBufferSize,0);
  InternalInitRecord(RecordBuffer,False);
end;


//------------------------------------------------------------------------------
// save position
//------------------------------------------------------------------------------
function TABSCursor.SavePosition: Pointer;
begin
// Result := New(PABSCursorPos);
 Result := MemoryManager.GetMem(SizeOf(TABSCursorPos));
 PABSCursorPos(Result)^.FirstPosition := Self.FirstPosition;
 PABSCursorPos(Result)^.LastPosition := Self.LastPosition;
 PABSCursorPos(Result)^.RecordID := Self.CurrentRecordID;
end; // SavePosition


//------------------------------------------------------------------------------
// restore position
//------------------------------------------------------------------------------
procedure TABSCursor.RestorePosition(Pos: Pointer);
begin
 Self.FirstPosition := PABSCursorPos(Pos)^.FirstPosition;
 Self.LastPosition := PABSCursorPos(Pos)^.LastPosition;
 Self.CurrentRecordID := PABSCursorPos(Pos)^.RecordID;
end; // RestorePosition


//------------------------------------------------------------------------------
// free position
//------------------------------------------------------------------------------
procedure TABSCursor.FreePosition(Pos: Pointer);
begin
 MemoryManager.FreeAndNillMem(Pos);
end; // FreePosition


//------------------------------------------------------------------------------
// disable record bitmap
//------------------------------------------------------------------------------
procedure TABSCursor.DisableRecordBitmap;
begin
 if (RecordBitmap <> nil) then
  TABSRecordBitmap(RecordBitmap).Clear;
end; // DisableRecordBitmap


//------------------------------------------------------------------------------
// apply projection
//------------------------------------------------------------------------------
procedure TABSCursor.ApplyProjection(FieldNamesList, AliasList: TStringList);
var
  i,j,k: Integer;
  alias: string;
begin
  if (FieldNamesList.Count <> AliasList.Count) then
    raise EABSException.Create(10321,ErrorLDifferentListsLength,
            [FieldNamesList.Count,AliasList.Count]);
  if (FieldNamesList.Count = 0) then
    raise EABSException.Create(10322,ErrorLNoFieldsInProjection);
  FVisibleFieldDefs.Clear;
  for i := 0 to FieldNamesList.Count -1 do
   begin
    j := FFieldDefs.GetDefNumberByName(FieldNamesList[i]);
    if (j < 0) then
      raise EABSException.Create(10323,ErrorLCannotFindField,[FieldNamesList[i]]);
    FVisibleFieldDefs.AddCreated.Assign(FFieldDefs[j]);
    FVisibleFieldDefs[FVisibleFieldDefs.Count-1].FFieldNoReference := j;
    if (AliasList[i] <> '') then
      begin
        FVisibleFieldDefs[FVisibleFieldDefs.Count-1].Name := '';
        alias := AliasList[i];
        for k := 0 to FieldNamesList.Count do
          begin
            if (k > 0) then
              alias := AliasList[i]+'_'+IntToStr(k);
            if (FVisibleFieldDefs.GetFieldDefByName(alias) = nil) then
              break;
          end;
        FVisibleFieldDefs[FVisibleFieldDefs.Count-1].Name := alias;
      end;
   end;
//  FVisibleFieldDefs.RecalcFieldOffsets;
end;


//------------------------------------------------------------------------------
// return true if index applied
//------------------------------------------------------------------------------
function TABSCursor.IsIndexApplied: Boolean;
begin
  Result := (IndexID <> INVALID_OBJECT_ID);
end; // IsIndexApplied


//------------------------------------------------------------------------------
// return true if distinct applied
//------------------------------------------------------------------------------
function TABSCursor.IsDistinctApplied: Boolean;
begin
  Result := (FDistinctFieldCount > 0);
end; // IsDistinctApplied


//------------------------------------------------------------------------------
// return true if filter applied
//------------------------------------------------------------------------------
function TABSCursor.IsFilterApplied: Boolean;
begin
  Result := ((FilterExpression <> nil) or (FilterRecord <> nil) or
             (SQLFilterExpression <> nil));
end; // IsFilterApplied


//------------------------------------------------------------------------------
// return true if range is applied
//------------------------------------------------------------------------------
function TABSCursor.IsRangeApplied: Boolean;
begin
  Result := ((FRangeStartBuffer <> nil) or (FRangeEndBuffer <> nil));
end; // IsRangeApplied


//------------------------------------------------------------------------------
// reset range
//------------------------------------------------------------------------------
function TABSCursor.IsViewRestricted: Boolean;
begin
  Result := (IsFilterApplied or IsRangeApplied or IsDistinctApplied);
end; // IsViewRestricted


//------------------------------------------------------------------------------
// reset range
//------------------------------------------------------------------------------
procedure TABSCursor.ResetRange;
begin
  FRangeStartBuffer := nil;
  FRangeEndBuffer := nil;
  DisableRecordBitmap;
end; // ResetRange


//------------------------------------------------------------------------------
// apply range
//------------------------------------------------------------------------------
procedure TABSCursor.ApplyRange(
                          StartBuffer, EndBuffer: TABSRecordBuffer;
                          StartKeyFieldCount:     Integer;
                          EndKeyFieldCount:       Integer;
                          StartExclusive:         Boolean;
                          EndExclusive:           Boolean
                        );
begin
  FRangeStartBuffer := StartBuffer;
  FRangeEndBuffer := EndBuffer;
  FRangeStartKeyFieldCount := StartKeyFieldCount;
  FRangeEndKeyFieldCount := EndKeyFieldCount;
  FRangeStartExclusive := StartExclusive;
  FRangeEndExclusive := EndExclusive;
  DisableRecordBitmap;
end; // ApplyRange


//------------------------------------------------------------------------------
// set SQL Filter
//------------------------------------------------------------------------------
procedure TABSCursor.SetSQLFilter(FilterExpr: TObject; ParentQueryAO: TObject; ParentCursor: TABSCursor);
begin
  FSQLFilterExpression := FilterExpr;
  if FSQLFilterExpression <> nil then
    TABSExpression(FSQLFilterExpression).AssignCursor(self, TABSAO(ParentQueryAO), ParentCursor);
end; // SetSQLFilter



////////////////////////////////////////////////////////////////////////////////
//
// TABSSessionNamedObject
//
////////////////////////////////////////////////////////////////////////////////

//------------------------------------------------------------------------------
// Constructor
//------------------------------------------------------------------------------
constructor TABSSessionNamedObject.Create(Name: string);
begin
  FObjectID := INVALID_OBJECT_ID;
  FName := Name;
end;//Create


//------------------------------------------------------------------------------
// Constructor
//------------------------------------------------------------------------------
constructor TABSSessionNamedObject.Create(ObjectID: TABSObjectID);
begin
  FObjectID := ObjectID;
  FName := '';
end;//Create


////////////////////////////////////////////////////////////////////////////////
//
// TABSSessionNamedObjectSequenceValue
//
////////////////////////////////////////////////////////////////////////////////


//------------------------------------------------------------------------------
// Constructor
//------------------------------------------------------------------------------
constructor TABSSessionNamedObjectSequenceValue.Create(ObjectID: TABSObjectID;
  Value: TABSSequenceValue);
begin
  inherited Create(ObjectID);
  FValue := Value;
end;//Create



////////////////////////////////////////////////////////////////////////////////
//
// TABSBaseSession
//
////////////////////////////////////////////////////////////////////////////////


//------------------------------------------------------------------------------
// constructor
//------------------------------------------------------------------------------
constructor TABSBaseSession.Create;
begin
  FSessionNamedObjectList := TABSSortedStringPtrArray.Create;
  FSessionID := INVALID_SESSION_ID;
  FInTransaction := False;
end;//Create


//------------------------------------------------------------------------------
// destructor
//------------------------------------------------------------------------------
destructor TABSBaseSession.Destroy;
var i: integer;
begin
  for i:=0 to FSessionNamedObjectList.Count -1 do
    TABSSessionNamedObject(FSessionNamedObjectList[i]).Free;
  FSessionNamedObjectList.Free;
end;//destroy


//------------------------------------------------------------------------------
// Set object to session
//------------------------------------------------------------------------------
procedure TABSBaseSession.SetObject(Value: TABSSessionNamedObject);
var
  OldValue: TABSSessionNamedObject;
begin
  if (Value.ObjectID <> INVALID_OBJECT_ID) then
    OldValue := GetObjectByID(Value.ObjectID)
  else
    OldValue := GetObjectByName(Value.Name);
  // first, delete object from session
  if OldValue <> nil then
    begin
      OldValue.Free;
      FSessionNamedObjectList.Delete(FSessionNamedObjectList.IndexOf(OldValue));
    end;
  FSessionNamedObjectList.Add(Value);
end;//SetObject

//------------------------------------------------------------------------------
// Get Named object from session
//------------------------------------------------------------------------------
function TABSBaseSession.GetObjectByName(ObjectName: string): TABSSessionNamedObject;
var i: integer;
begin
  Result := nil;
  for i:=0 to FSessionNamedObjectList.Count -1 do
   if (AnsiUpperCase(ObjectName) =
       AnsiUpperCase(TABSSessionNamedObject(FSessionNamedObjectList[i]).Name)) then
    begin
     Result := TABSSessionNamedObject(FSessionNamedObjectList[i]);
     break;
    end;
end;//GetNamedObject


//------------------------------------------------------------------------------
// Get object from session
//------------------------------------------------------------------------------
function TABSBaseSession.GetObjectByID(id: TABSObjectID): TABSSessionNamedObject;
var i: integer;
begin
  Result := nil;
  for i:=0 to FSessionNamedObjectList.Count -1 do
    if (TABSSessionNamedObject(FSessionNamedObjectList[i]).ObjectID = id) then
    begin
        Result := TABSSessionNamedObject(FSessionNamedObjectList[i]);
        break;
    end;
end;//GetObjectByID


procedure TABSBaseSession.DeleteObject(id: TABSObjectID);
var
  Value: TABSSessionNamedObject;
begin
  Value := GetObjectByID(id);
  // first, delete object from session
  if Value <> nil then
  begin
    Value.Free;
    FSessionNamedObjectList.Delete(FSessionNamedObjectList.IndexOf(Value));
  end;
end;

end.
