text: /*
   *	PROGRAM:	JRD Access Method
   *	MODULE:		blb.h
   *	DESCRIPTION:	Blob handling definitions
   *
   * The contents of this file are subject to the Interbase Public
   * License Version 1.0 (the "License"); you may not use this file
   * except in compliance with the License. You may obtain a copy
   * of the License at http://www.Inprise.com/IPL.html
   *
   * Software distributed under the License is distributed on an
   * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
   * or implied. See the License for the specific language governing
   * rights and limitations under the License.
   *
   * The Original Code was created by Inprise Corporation
   * and its predecessors. Portions created by Inprise Corporation are
   * Copyright (C) Inprise Corporation.
   *
   * All Rights Reserved.
   * Contributor(s): ______________________________________.
   *
   * 2002.10.28 Sean Leyne - Code cleanup, removed obsolete "DecOSF" port
   *
   */
  
  #ifndef JRD_BLB_H
  #define JRD_BLB_H
  
  #include "../include/fb_blk.h"
  
  #include "../jrd/RecordNumber.h"
  #include "../jrd/EngineInterface.h"
  #include "../common/classes/array.h"
  #include "../common/classes/File.h"
  
  #include "firebird/Interface.h"
  #include "../common/classes/ImplementHelper.h"
  #include "../common/dsc.h"
  
  namespace Ods
  {
  	struct blob_page;
  	struct blh;
  }
  
  namespace Jrd
  {
  
  class Attachment;
  class BlobControl;
  class jrd_rel;
  class jrd_req;
  class jrd_tra;
  class vcl;
  class thread_db;
  struct win;
  class ValueExprNode;
  class ArrayField;
  struct impure_value;
  
  
  // Your basic blob block.
  
  class blb : public pool_alloc<type_blb>
  {
  public:
  	blb(MemoryPool& pool, USHORT page_size)
  		: blb_interface(NULL),
  		  blb_buffer(pool, page_size / sizeof(SLONG)),
  		  blb_has_buffer(true)
  	{
  	}
  
  	jrd_rel*	blb_relation;		// Relation, if known
  	JBlob* blb_interface;
  
  	ULONG blb_length;				// Total length of data sans segments
  	USHORT blb_flags;				// Interesting stuff (see below)
  
  	SSHORT blb_sub_type;			// Blob's declared sub-type
  	UCHAR blb_charset;				// Blob's charset
  
  	// inline functions
  	bool hasBuffer() const;
  	UCHAR* getBuffer();
  	void freeBuffer();
  	bool isSegmented() const;
  	Attachment* getAttachment();
  	jrd_tra* getTransaction();
  	USHORT getLevel() const;
  	ULONG getMaxSequence() const;
  	ULONG getTempId() const;
  	ULONG getSegmentCount() const;
  	USHORT getFragmentSize() const;
  	USHORT getMaxSegment() const;
  	// end inline
  
  	void	BLB_cancel(thread_db* tdbb);
  	void	BLB_check_well_formed(thread_db*, const dsc* desc);
  	bool	BLB_close(thread_db*);
  	static blb*	create(thread_db*, jrd_tra*, bid*);
  	static blb*	create2(thread_db*, jrd_tra*, bid*, USHORT, const UCHAR*, bool = false);
  	static Jrd::blb* get_array(Jrd::thread_db*, Jrd::jrd_tra*, const Jrd::bid*, Ods::InternalArrayDesc*);
  	ULONG	BLB_get_data(thread_db*, UCHAR*, SLONG, bool = true);
  	USHORT	BLB_get_segment(thread_db*, void*, USHORT);
  	static SLONG get_slice(Jrd::thread_db*, Jrd::jrd_tra*, const Jrd::bid*, const UCHAR*, USHORT,
  					const UCHAR*, SLONG, UCHAR*);
  	SLONG	BLB_lseek(USHORT, SLONG);
  	static void	move(thread_db* tdbb, dsc* from_desc, dsc* to_desc, const ValueExprNode* field);
  	static blb* open(thread_db*, jrd_tra*, const bid*);
  	static blb* open2(thread_db*, jrd_tra*, const bid*, USHORT, const UCHAR*, bool = false);
  	void	BLB_put_data(thread_db*, const UCHAR*, SLONG);
  	void	BLB_put_segment(thread_db*, const void*, USHORT);
  	static void	put_slice(thread_db*, jrd_tra*, bid*, const UCHAR*, USHORT, const UCHAR*, SLONG, UCHAR*);
  	static void release_array(Jrd::ArrayField*);
  	static void scalar(Jrd::thread_db*, Jrd::jrd_tra*, const Jrd::bid*, USHORT, const SLONG*, Jrd::impure_value*);
  
  	static void delete_blob_id(thread_db*, const bid*, ULONG, jrd_rel*);
  	void fromPageHeader(const Ods::blh* header);
  	void toPageHeader(Ods::blh* header) const;
  	void getFromPage(USHORT length, const UCHAR* data);
  	void storeToPage(USHORT* length, Firebird::Array<UCHAR>& buffer, const UCHAR** data, void* stack);
  
  private:
  	static blb* allocate_blob(thread_db*, jrd_tra*);
  	static blb* copy_blob(thread_db* tdbb, const bid* source, bid* destination,
  					USHORT bpb_length, const UCHAR* bpb, USHORT destPageSpaceID);
  	void delete_blob(thread_db*, ULONG);
  	Ods::blob_page* get_next_page(thread_db*, win*);
  	void insert_page(thread_db*);
  	void destroy(const bool purge_flag);
  
  	FB_SIZE_T blb_temp_size;		// size stored in transaction temp space
  	offset_t blb_temp_offset;		// offset in transaction temp space
  	Attachment*	blb_attachment;		// database attachment
  	jrd_tra*	blb_transaction;	// Parent transaction block
  	UCHAR*		blb_segment;		// Next segment to be addressed
  	BlobControl*	blb_filter;		// Blob filter control block, if any
  	bid			blb_blob_id;		// Id of materialized blob
  	vcl*		blb_pages;			// Vector of pages
  
  	Firebird::Array<SLONG> blb_buffer;	// buffer used in opened blobs - must be longword aligned
  
  	ULONG blb_temp_id;				// ID of newly created blob in transaction
  	ULONG blb_sequence;				// Blob page sequence
  	ULONG blb_lead_page;			// First page number
  	ULONG blb_seek;					// Seek location
  	ULONG blb_max_sequence;			// Number of data pages
  	ULONG blb_count;				// Number of segments
  
  	USHORT blb_pointers;			// Max pointer on a page
  	USHORT blb_clump_size;			// Size of data clump
  	USHORT blb_space_remaining;		// Data space left
  	USHORT blb_max_pages;			// Max pages in vector
  	USHORT blb_level;				// Storage type
  	USHORT blb_pg_space_id;			// page space
  	USHORT blb_fragment_size;		// Residual fragment size
  	USHORT blb_max_segment;			// Longest segment
  #ifdef CHECK_BLOB_FIELD_ACCESS_FOR_SELECT
  	USHORT blb_fld_id;				// Field ID
  #endif
  	bool blb_has_buffer;
  };
  
  const int BLB_temporary		= 1;		// Newly created blob
  const int BLB_eof			= 2;		// This blob is exhausted
  const int BLB_stream		= 4;		// Stream style blob
  const int BLB_closed		= 8;		// Temporary blob has been closed
  const int BLB_damaged		= 16;		// Blob is busted
  const int BLB_seek			= 32;		// Seek is pending
  const int BLB_large_scan	= 64;		// Blob is larger than page buffer cache
  
  /* Blob levels are:
  
  	0	small blob -- blob "record" is actual data
  	1	medium blob -- blob "record" is pointer to pages
  	2	large blob -- blob "record" is pointer to pages of pointers
  */
  
  
  inline bool blb::hasBuffer() const
  {
  	return blb_has_buffer;
  }
  
  inline UCHAR* blb::getBuffer()
  {
  	fb_assert(blb_has_buffer);
  	return (UCHAR*) blb_buffer.getBuffer(blb_buffer.getCapacity());
  }
  
  inline void blb::freeBuffer()
  {
  	fb_assert(blb_has_buffer);
  	blb_buffer.free();
  	blb_has_buffer = false;
  }
  
  inline bool blb::isSegmented() const
  {
  	return !(blb_flags & BLB_stream);
  }
  
  inline Attachment* blb::getAttachment()
  {
  	return blb_attachment;
  }
  
  inline jrd_tra* blb::getTransaction()
  {
  	return blb_transaction;
  }
  
  inline USHORT blb::getLevel() const
  {
  	return blb_level;
  }
  
  inline ULONG blb::getMaxSequence() const
  {
  	return blb_max_sequence;
  }
  
  inline ULONG blb::getTempId() const
  {
  	return blb_temp_id;
  }
  
  inline ULONG blb::getSegmentCount() const
  {
  	return blb_count;
  }
  
  inline USHORT blb::getFragmentSize() const
  {
  	return blb_fragment_size;
  }
  
  inline USHORT blb::getMaxSegment() const
  {
  	return blb_max_segment;
  }
  
  
  } //namespace Jrd
  
  #endif // JRD_BLB_H
  