mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-30 20:03:03 +01:00
1072 lines
30 KiB
C++
1072 lines
30 KiB
C++
/*
|
|
* The contents of this file are subject to the Initial
|
|
* Developer's 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.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
|
|
*
|
|
* Software distributed under the License is distributed AS IS,
|
|
* 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 Dmitry Yemanov
|
|
* for the Firebird Open Source RDBMS project.
|
|
*
|
|
* Copyright (c) 2009 Dmitry Yemanov <dimitr@firebirdsql.org>
|
|
* and all contributors signed below.
|
|
*
|
|
* All Rights Reserved.
|
|
* Contributor(s): ______________________________________.
|
|
*/
|
|
|
|
#ifndef JRD_RECORD_SOURCE_H
|
|
#define JRD_RECORD_SOURCE_H
|
|
|
|
#include "../common/classes/array.h"
|
|
#include "../common/classes/objects_array.h"
|
|
#include "../common/classes/NestConst.h"
|
|
#include "../jrd/RecordSourceNodes.h"
|
|
#include "../jrd/req.h"
|
|
#include "../jrd/rse.h"
|
|
#include "../jrd/inf_pub.h"
|
|
|
|
namespace Jrd
|
|
{
|
|
class thread_db;
|
|
class jrd_req;
|
|
class jrd_prc;
|
|
class AggNode;
|
|
class BoolExprNode;
|
|
class Sort;
|
|
class CompilerScratch;
|
|
class RecordBuffer;
|
|
class BtrPageGCLock;
|
|
struct index_desc;
|
|
struct record_param;
|
|
struct temporary_key;
|
|
struct win;
|
|
class BaseBufferedStream;
|
|
class BufferedStream;
|
|
|
|
enum JoinType { INNER_JOIN, OUTER_JOIN, SEMI_JOIN, ANTI_JOIN };
|
|
|
|
// Abstract base class
|
|
|
|
class RecordSource
|
|
{
|
|
public:
|
|
virtual void open(thread_db* tdbb) const = 0;
|
|
virtual void close(thread_db* tdbb) const = 0;
|
|
|
|
virtual bool getRecord(thread_db* tdbb) const = 0;
|
|
virtual bool refetchRecord(thread_db* tdbb) const = 0;
|
|
virtual bool lockRecord(thread_db* tdbb) const = 0;
|
|
|
|
virtual void print(thread_db* tdbb, Firebird::string& plan,
|
|
bool detailed, unsigned level) const = 0;
|
|
|
|
virtual void markRecursive() = 0;
|
|
virtual void invalidateRecords(jrd_req* request) const = 0;
|
|
|
|
virtual void findUsedStreams(StreamList& streams, bool expandAll = false) const = 0;
|
|
virtual void nullRecords(thread_db* tdbb) const = 0;
|
|
|
|
virtual void setAnyBoolean(BoolExprNode* /*anyBoolean*/, bool /*ansiAny*/, bool /*ansiNot*/)
|
|
{
|
|
fb_assert(false);
|
|
}
|
|
|
|
virtual ~RecordSource();
|
|
|
|
static bool rejectDuplicate(const UCHAR* /*data1*/, const UCHAR* /*data2*/, void* /*userArg*/)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
protected:
|
|
// Generic impure block
|
|
struct Impure
|
|
{
|
|
ULONG irsb_flags;
|
|
};
|
|
|
|
static const ULONG irsb_open = 1;
|
|
static const ULONG irsb_first = 2;
|
|
static const ULONG irsb_joined = 4;
|
|
static const ULONG irsb_mustread = 8;
|
|
static const ULONG irsb_singular_processed = 16;
|
|
|
|
RecordSource()
|
|
: m_impure(0), m_recursive(false)
|
|
{}
|
|
|
|
static Firebird::string printName(thread_db* tdbb, const Firebird::string& name, bool quote = true);
|
|
static Firebird::string printName(thread_db* tdbb, const Firebird::string& name,
|
|
const Firebird::string& alias);
|
|
|
|
static Firebird::string printIndent(unsigned level);
|
|
static void printInversion(thread_db* tdbb, const InversionNode* inversion,
|
|
Firebird::string& plan, bool detailed,
|
|
unsigned level, bool navigation = false);
|
|
|
|
static void saveRecord(thread_db* tdbb, record_param* rpb);
|
|
static void restoreRecord(thread_db* tdbb, record_param* rpb);
|
|
|
|
ULONG m_impure;
|
|
bool m_recursive;
|
|
};
|
|
|
|
|
|
// Helper class implementing some common methods
|
|
|
|
class RecordStream : public RecordSource
|
|
{
|
|
public:
|
|
RecordStream(CompilerScratch* csb, StreamType stream, const Format* format = NULL);
|
|
|
|
virtual bool refetchRecord(thread_db* tdbb) const;
|
|
virtual bool lockRecord(thread_db* tdbb) const;
|
|
|
|
virtual void markRecursive();
|
|
virtual void invalidateRecords(jrd_req* request) const;
|
|
|
|
virtual void findUsedStreams(StreamList& streams, bool expandAll = false) const;
|
|
virtual void nullRecords(thread_db* tdbb) const;
|
|
|
|
protected:
|
|
const StreamType m_stream;
|
|
const Format* const m_format;
|
|
};
|
|
|
|
|
|
// Primary (table scan) access methods
|
|
|
|
class FullTableScan : public RecordStream
|
|
{
|
|
public:
|
|
FullTableScan(CompilerScratch* csb, const Firebird::string& alias,
|
|
StreamType stream, jrd_rel* relation);
|
|
|
|
void open(thread_db* tdbb) const;
|
|
void close(thread_db* tdbb) const;
|
|
|
|
bool getRecord(thread_db* tdbb) const;
|
|
|
|
void print(thread_db* tdbb, Firebird::string& plan,
|
|
bool detailed, unsigned level) const;
|
|
|
|
private:
|
|
const Firebird::string m_alias;
|
|
jrd_rel* const m_relation;
|
|
};
|
|
|
|
class BitmapTableScan : public RecordStream
|
|
{
|
|
struct Impure : public RecordSource::Impure
|
|
{
|
|
RecordBitmap** irsb_bitmap;
|
|
};
|
|
|
|
public:
|
|
BitmapTableScan(CompilerScratch* csb, const Firebird::string& alias,
|
|
StreamType stream, jrd_rel* relation, InversionNode* inversion);
|
|
|
|
void open(thread_db* tdbb) const;
|
|
void close(thread_db* tdbb) const;
|
|
|
|
bool getRecord(thread_db* tdbb) const;
|
|
|
|
void print(thread_db* tdbb, Firebird::string& plan,
|
|
bool detailed, unsigned level) const;
|
|
|
|
private:
|
|
const Firebird::string m_alias;
|
|
jrd_rel* const m_relation;
|
|
NestConst<InversionNode> const m_inversion;
|
|
};
|
|
|
|
class IndexTableScan : public RecordStream
|
|
{
|
|
struct Impure : public RecordSource::Impure
|
|
{
|
|
RecordNumber irsb_nav_number; // last record number
|
|
ULONG irsb_nav_page; // index page number
|
|
SLONG irsb_nav_incarnation; // buffer/page incarnation counter
|
|
RecordBitmap** irsb_nav_bitmap; // bitmap for inversion tree
|
|
RecordBitmap* irsb_nav_records_visited; // bitmap of records already retrieved
|
|
BtrPageGCLock* irsb_nav_btr_gc_lock; // lock to prevent removal of currently walked index page
|
|
USHORT irsb_nav_offset; // page offset of current index node
|
|
USHORT irsb_nav_upper_length; // length of upper key value
|
|
USHORT irsb_nav_length; // length of expanded key
|
|
UCHAR irsb_nav_data[1]; // expanded key, upper bound, and index desc
|
|
};
|
|
|
|
public:
|
|
IndexTableScan(CompilerScratch* csb, const Firebird::string& alias,
|
|
StreamType stream, jrd_rel* relation,
|
|
InversionNode* index, USHORT keyLength);
|
|
|
|
void open(thread_db* tdbb) const;
|
|
void close(thread_db* tdbb) const;
|
|
|
|
bool getRecord(thread_db* tdbb) const;
|
|
|
|
void print(thread_db* tdbb, Firebird::string& plan,
|
|
bool detailed, unsigned level) const;
|
|
|
|
void setInversion(InversionNode* inversion, BoolExprNode* condition)
|
|
{
|
|
fb_assert(!m_inversion && !m_condition);
|
|
m_inversion = inversion;
|
|
m_condition = condition;
|
|
}
|
|
|
|
private:
|
|
int compareKeys(const index_desc*, const UCHAR*, USHORT, const temporary_key*, USHORT) const;
|
|
bool findSavedNode(thread_db* tdbb, Impure* impure, win* window, UCHAR**) const;
|
|
UCHAR* getPosition(thread_db* tdbb, Impure* impure, win* window) const;
|
|
UCHAR* openStream(thread_db* tdbb, Impure* impure, win* window) const;
|
|
void setPage(thread_db* tdbb, Impure* impure, win* window) const;
|
|
void setPosition(thread_db* tdbb, Impure* impure, record_param*,
|
|
win* window, const UCHAR*, const temporary_key&) const;
|
|
bool setupBitmaps(thread_db* tdbb, Impure* impure) const;
|
|
|
|
const Firebird::string m_alias;
|
|
jrd_rel* const m_relation;
|
|
NestConst<InversionNode> const m_index;
|
|
NestConst<InversionNode> m_inversion;
|
|
NestConst<BoolExprNode> m_condition;
|
|
const FB_SIZE_T m_length;
|
|
FB_SIZE_T m_offset;
|
|
};
|
|
|
|
class ExternalTableScan : public RecordStream
|
|
{
|
|
struct Impure : public RecordSource::Impure
|
|
{
|
|
FB_UINT64 irsb_position;
|
|
};
|
|
|
|
public:
|
|
ExternalTableScan(CompilerScratch* csb, const Firebird::string& alias,
|
|
StreamType stream, jrd_rel* relation);
|
|
|
|
void open(thread_db* tdbb) const;
|
|
void close(thread_db* tdbb) const;
|
|
|
|
bool getRecord(thread_db* tdbb) const;
|
|
bool refetchRecord(thread_db* tdbb) const;
|
|
bool lockRecord(thread_db* tdbb) const;
|
|
|
|
void print(thread_db* tdbb, Firebird::string& plan,
|
|
bool detailed, unsigned level) const;
|
|
|
|
private:
|
|
jrd_rel* const m_relation;
|
|
const Firebird::string m_alias;
|
|
};
|
|
|
|
class VirtualTableScan : public RecordStream
|
|
{
|
|
public:
|
|
VirtualTableScan(CompilerScratch* csb, const Firebird::string& alias,
|
|
StreamType stream, jrd_rel* relation);
|
|
|
|
void open(thread_db* tdbb) const;
|
|
void close(thread_db* tdbb) const;
|
|
|
|
bool getRecord(thread_db* tdbb) const;
|
|
bool refetchRecord(thread_db* tdbb) const;
|
|
bool lockRecord(thread_db* tdbb) const;
|
|
|
|
void print(thread_db* tdbb, Firebird::string& plan,
|
|
bool detailed, unsigned level) const;
|
|
|
|
protected:
|
|
virtual const Format* getFormat(thread_db* tdbb, jrd_rel* relation) const = 0;
|
|
virtual bool retrieveRecord(thread_db* tdbb, jrd_rel* relation,
|
|
FB_UINT64 position, Record* record) const = 0;
|
|
|
|
private:
|
|
jrd_rel* const m_relation;
|
|
const Firebird::string m_alias;
|
|
};
|
|
|
|
class ProcedureScan : public RecordStream
|
|
{
|
|
struct Impure : public RecordSource::Impure
|
|
{
|
|
jrd_req* irsb_req_handle;
|
|
UCHAR* irsb_message;
|
|
};
|
|
|
|
public:
|
|
ProcedureScan(CompilerScratch* csb, const Firebird::string& alias, StreamType stream,
|
|
const jrd_prc* procedure, const ValueListNode* sourceList,
|
|
const ValueListNode* targetList, MessageNode* message);
|
|
|
|
void open(thread_db* tdbb) const;
|
|
void close(thread_db* tdbb) const;
|
|
|
|
bool getRecord(thread_db* tdbb) const;
|
|
bool refetchRecord(thread_db* tdbb) const;
|
|
bool lockRecord(thread_db* tdbb) const;
|
|
|
|
void print(thread_db* tdbb, Firebird::string& plan,
|
|
bool detailed, unsigned level) const;
|
|
|
|
private:
|
|
void assignParams(thread_db* tdbb, const dsc* from_desc, const dsc* flag_desc,
|
|
const UCHAR* msg, const dsc* to_desc, SSHORT to_id, Record* record) const;
|
|
|
|
const Firebird::string m_alias;
|
|
const jrd_prc* const m_procedure;
|
|
const ValueListNode* m_sourceList;
|
|
const ValueListNode* m_targetList;
|
|
NestConst<MessageNode> const m_message;
|
|
};
|
|
|
|
|
|
// Filtering (one -> one) access methods
|
|
|
|
class SingularStream : public RecordSource
|
|
{
|
|
public:
|
|
SingularStream(CompilerScratch* csb, RecordSource* next);
|
|
|
|
void open(thread_db* tdbb) const;
|
|
void close(thread_db* tdbb) const;
|
|
|
|
bool getRecord(thread_db* tdbb) const;
|
|
bool refetchRecord(thread_db* tdbb) const;
|
|
bool lockRecord(thread_db* tdbb) const;
|
|
|
|
void print(thread_db* tdbb, Firebird::string& plan,
|
|
bool detailed, unsigned level) const;
|
|
|
|
void markRecursive();
|
|
void invalidateRecords(jrd_req* request) const;
|
|
|
|
void findUsedStreams(StreamList& streams, bool expandAll = false) const;
|
|
void nullRecords(thread_db* tdbb) const;
|
|
|
|
private:
|
|
void doGetRecord(thread_db* tdbb) const;
|
|
|
|
NestConst<RecordSource> m_next;
|
|
StreamList m_streams;
|
|
};
|
|
|
|
class LockedStream : public RecordSource
|
|
{
|
|
public:
|
|
LockedStream(CompilerScratch* csb, RecordSource* next);
|
|
|
|
void open(thread_db* tdbb) const;
|
|
void close(thread_db* tdbb) const;
|
|
|
|
bool getRecord(thread_db* tdbb) const;
|
|
bool refetchRecord(thread_db* tdbb) const;
|
|
bool lockRecord(thread_db* tdbb) const;
|
|
|
|
void print(thread_db* tdbb, Firebird::string& plan,
|
|
bool detailed, unsigned level) const;
|
|
|
|
void markRecursive();
|
|
void invalidateRecords(jrd_req* request) const;
|
|
|
|
void findUsedStreams(StreamList& streams, bool expandAll = false) const;
|
|
void nullRecords(thread_db* tdbb) const;
|
|
|
|
private:
|
|
NestConst<RecordSource> m_next;
|
|
};
|
|
|
|
class FirstRowsStream : public RecordSource
|
|
{
|
|
struct Impure : public RecordSource::Impure
|
|
{
|
|
SINT64 irsb_count;
|
|
};
|
|
|
|
public:
|
|
FirstRowsStream(CompilerScratch* csb, RecordSource* next, ValueExprNode* value);
|
|
|
|
void open(thread_db* tdbb) const;
|
|
void close(thread_db* tdbb) const;
|
|
|
|
bool getRecord(thread_db* tdbb) const;
|
|
bool refetchRecord(thread_db* tdbb) const;
|
|
bool lockRecord(thread_db* tdbb) const;
|
|
|
|
void print(thread_db* tdbb, Firebird::string& plan,
|
|
bool detailed, unsigned level) const;
|
|
|
|
void markRecursive();
|
|
void invalidateRecords(jrd_req* request) const;
|
|
|
|
void findUsedStreams(StreamList& streams, bool expandAll = false) const;
|
|
void nullRecords(thread_db* tdbb) const;
|
|
|
|
void setAnyBoolean(BoolExprNode* anyBoolean, bool ansiAny, bool ansiNot)
|
|
{
|
|
m_next->setAnyBoolean(anyBoolean, ansiAny, ansiNot);
|
|
}
|
|
|
|
private:
|
|
NestConst<RecordSource> m_next;
|
|
NestConst<ValueExprNode> const m_value;
|
|
};
|
|
|
|
class SkipRowsStream : public RecordSource
|
|
{
|
|
struct Impure : public RecordSource::Impure
|
|
{
|
|
SINT64 irsb_count;
|
|
};
|
|
|
|
public:
|
|
SkipRowsStream(CompilerScratch* csb, RecordSource* next, ValueExprNode* value);
|
|
|
|
void open(thread_db* tdbb) const;
|
|
void close(thread_db* tdbb) const;
|
|
|
|
bool getRecord(thread_db* tdbb) const;
|
|
bool refetchRecord(thread_db* tdbb) const;
|
|
bool lockRecord(thread_db* tdbb) const;
|
|
|
|
void print(thread_db* tdbb, Firebird::string& plan,
|
|
bool detailed, unsigned level) const;
|
|
|
|
void markRecursive();
|
|
void invalidateRecords(jrd_req* request) const;
|
|
|
|
void findUsedStreams(StreamList& streams, bool expandAll = false) const;
|
|
void nullRecords(thread_db* tdbb) const;
|
|
|
|
void setAnyBoolean(BoolExprNode* anyBoolean, bool ansiAny, bool ansiNot)
|
|
{
|
|
m_next->setAnyBoolean(anyBoolean, ansiAny, ansiNot);
|
|
}
|
|
|
|
private:
|
|
NestConst<RecordSource> m_next;
|
|
NestConst<ValueExprNode> const m_value;
|
|
};
|
|
|
|
class FilteredStream : public RecordSource
|
|
{
|
|
public:
|
|
FilteredStream(CompilerScratch* csb, RecordSource* next, BoolExprNode* boolean);
|
|
|
|
void open(thread_db* tdbb) const;
|
|
void close(thread_db* tdbb) const;
|
|
|
|
bool getRecord(thread_db* tdbb) const;
|
|
bool refetchRecord(thread_db* tdbb) const;
|
|
bool lockRecord(thread_db* tdbb) const;
|
|
|
|
void print(thread_db* tdbb, Firebird::string& plan,
|
|
bool detailed, unsigned level) const;
|
|
|
|
void markRecursive();
|
|
void invalidateRecords(jrd_req* request) const;
|
|
|
|
void findUsedStreams(StreamList& streams, bool expandAll = false) const;
|
|
void nullRecords(thread_db* tdbb) const;
|
|
|
|
void setAnyBoolean(BoolExprNode* anyBoolean, bool ansiAny, bool ansiNot)
|
|
{
|
|
fb_assert(!m_anyBoolean);
|
|
m_anyBoolean = anyBoolean;
|
|
|
|
m_ansiAny = ansiAny;
|
|
m_ansiAll = !ansiAny;
|
|
m_ansiNot = ansiNot;
|
|
}
|
|
|
|
private:
|
|
bool evaluateBoolean(thread_db* tdbb) const;
|
|
|
|
NestConst<RecordSource> m_next;
|
|
NestConst<BoolExprNode> const m_boolean;
|
|
NestConst<BoolExprNode> m_anyBoolean;
|
|
bool m_ansiAny;
|
|
bool m_ansiAll;
|
|
bool m_ansiNot;
|
|
};
|
|
|
|
class SortedStream : public RecordSource
|
|
{
|
|
struct Impure : public RecordSource::Impure
|
|
{
|
|
Sort* irsb_sort;
|
|
};
|
|
|
|
public:
|
|
static const USHORT FLAG_PROJECT = 0x1; // sort is really a project
|
|
static const USHORT FLAG_UNIQUE = 0x2; // sorts using unique key - for distinct and group by
|
|
static const USHORT FLAG_KEY_VARY = 0x4; // sort key contains varying length string(s)
|
|
|
|
// Special values for SortMap::Item::fieldId.
|
|
static const SSHORT ID_DBKEY = -1; // dbkey value
|
|
static const SSHORT ID_DBKEY_VALID = -2; // dbkey valid flag
|
|
static const SSHORT ID_TRANS = -3; // transaction id of record
|
|
|
|
// Sort map block
|
|
class SortMap : public Firebird::PermanentStorage
|
|
{
|
|
public:
|
|
struct Item
|
|
{
|
|
void clear()
|
|
{
|
|
desc.clear();
|
|
flagOffset = fieldId = 0;
|
|
stream = 0;
|
|
node = NULL;
|
|
}
|
|
|
|
StreamType stream; // stream for field id
|
|
dsc desc; // relative descriptor
|
|
ULONG flagOffset; // offset of missing flag
|
|
SSHORT fieldId; // id for field (or ID constants)
|
|
NestConst<ValueExprNode> node; // expression node
|
|
};
|
|
|
|
explicit SortMap(MemoryPool& p)
|
|
: PermanentStorage(p),
|
|
length(0),
|
|
keyLength(0),
|
|
flags(0),
|
|
keyItems(p),
|
|
items(p)
|
|
{
|
|
}
|
|
|
|
ULONG length; // sort record length
|
|
ULONG keyLength; // key length
|
|
USHORT flags; // misc sort flags
|
|
Firebird::Array<sort_key_def> keyItems; // address of key descriptors
|
|
Firebird::Array<Item> items;
|
|
};
|
|
|
|
SortedStream(CompilerScratch* csb, RecordSource* next, SortMap* map);
|
|
|
|
void open(thread_db* tdbb) const;
|
|
void close(thread_db* tdbb) const;
|
|
|
|
bool getRecord(thread_db* tdbb) const;
|
|
bool refetchRecord(thread_db* tdbb) const;
|
|
bool lockRecord(thread_db* tdbb) const;
|
|
|
|
void print(thread_db* tdbb, Firebird::string& plan,
|
|
bool detailed, unsigned level) const;
|
|
|
|
void markRecursive();
|
|
void invalidateRecords(jrd_req* request) const;
|
|
|
|
void findUsedStreams(StreamList& streams, bool expandAll = false) const;
|
|
void nullRecords(thread_db* tdbb) const;
|
|
|
|
void setAnyBoolean(BoolExprNode* anyBoolean, bool ansiAny, bool ansiNot)
|
|
{
|
|
m_next->setAnyBoolean(anyBoolean, ansiAny, ansiNot);
|
|
}
|
|
|
|
ULONG getLength() const
|
|
{
|
|
return m_map->length;
|
|
}
|
|
|
|
ULONG getKeyLength() const
|
|
{
|
|
return m_map->keyLength;
|
|
}
|
|
|
|
bool compareKeys(const UCHAR* p, const UCHAR* q) const;
|
|
|
|
UCHAR* getData(thread_db* tdbb) const;
|
|
void mapData(thread_db* tdbb, jrd_req* request, UCHAR* data) const;
|
|
|
|
private:
|
|
Sort* init(thread_db* tdbb) const;
|
|
|
|
NestConst<RecordSource> m_next;
|
|
const SortMap* const m_map;
|
|
};
|
|
|
|
// Make moves in a window without going out of partition boundaries.
|
|
class SlidingWindow
|
|
{
|
|
public:
|
|
SlidingWindow(thread_db* aTdbb, const BaseBufferedStream* aStream,
|
|
const NestValueArray* aGroup, jrd_req* aRequest);
|
|
~SlidingWindow();
|
|
|
|
bool move(SINT64 delta);
|
|
|
|
private:
|
|
thread_db* tdbb;
|
|
const BaseBufferedStream* const stream;
|
|
const NestValueArray* group;
|
|
jrd_req* request;
|
|
Firebird::Array<impure_value> partitionKeys;
|
|
bool moved;
|
|
FB_UINT64 savedPosition;
|
|
};
|
|
|
|
class AggregatedStream : public RecordStream
|
|
{
|
|
enum State
|
|
{
|
|
STATE_PROCESS_EOF = 0, // We processed everything now process (EOF)
|
|
STATE_PENDING, // Values are pending from a prior fetch
|
|
STATE_EOF_FOUND, // We encountered EOF from the last attempted fetch
|
|
STATE_GROUPING // Entering EVL group before fetching the first record
|
|
};
|
|
|
|
struct Impure : public RecordSource::Impure
|
|
{
|
|
State state;
|
|
FB_UINT64 pending;
|
|
impure_value* impureValues;
|
|
};
|
|
|
|
public:
|
|
AggregatedStream(thread_db* tdbb, CompilerScratch* csb, StreamType stream,
|
|
const NestValueArray* group, MapNode* map, BaseBufferedStream* next,
|
|
const NestValueArray* order);
|
|
|
|
AggregatedStream(thread_db* tdbb, CompilerScratch* csb, StreamType stream,
|
|
const NestValueArray* group, MapNode* map, RecordSource* next);
|
|
|
|
void open(thread_db* tdbb) const;
|
|
void close(thread_db* tdbb) const;
|
|
|
|
bool getRecord(thread_db* tdbb) const;
|
|
bool refetchRecord(thread_db* tdbb) const;
|
|
bool lockRecord(thread_db* tdbb) const;
|
|
|
|
void print(thread_db* tdbb, Firebird::string& plan,
|
|
bool detailed, unsigned level) const;
|
|
|
|
void markRecursive();
|
|
void invalidateRecords(jrd_req* request) const;
|
|
|
|
void findUsedStreams(StreamList& streams, bool expandAll = false) const;
|
|
void nullRecords(thread_db* tdbb) const;
|
|
|
|
private:
|
|
void init(thread_db* tdbb, CompilerScratch* csb);
|
|
|
|
State evaluateGroup(thread_db* tdbb, State state) const;
|
|
void cacheValues(thread_db* tdbb, jrd_req* request,
|
|
const NestValueArray* group, unsigned impureOffset) const;
|
|
bool lookForChange(thread_db* tdbb, jrd_req* request,
|
|
const NestValueArray* group, unsigned impureOffset) const;
|
|
void finiDistinct(thread_db* tdbb, jrd_req* request) const;
|
|
|
|
NestConst<BaseBufferedStream> m_bufferedStream;
|
|
NestConst<RecordSource> m_next;
|
|
const NestValueArray* const m_group;
|
|
NestConst<MapNode> m_map;
|
|
const NestValueArray* const m_order;
|
|
NestValueArray m_winPassSources;
|
|
NestValueArray m_winPassTargets;
|
|
};
|
|
|
|
class WindowedStream : public RecordSource
|
|
{
|
|
public:
|
|
WindowedStream(thread_db* tdbb, CompilerScratch* csb,
|
|
Firebird::ObjectsArray<WindowSourceNode::Partition>& partitions, RecordSource* next);
|
|
|
|
void open(thread_db* tdbb) const;
|
|
void close(thread_db* tdbb) const;
|
|
|
|
bool getRecord(thread_db* tdbb) const;
|
|
bool refetchRecord(thread_db* tdbb) const;
|
|
bool lockRecord(thread_db* tdbb) const;
|
|
|
|
void print(thread_db* tdbb, Firebird::string& plan,
|
|
bool detailed, unsigned level) const;
|
|
|
|
void markRecursive();
|
|
void invalidateRecords(jrd_req* request) const;
|
|
|
|
void findUsedStreams(StreamList& streams, bool expandAll = false) const;
|
|
void nullRecords(thread_db* tdbb) const;
|
|
|
|
private:
|
|
NestConst<BufferedStream> m_next;
|
|
NestConst<RecordSource> m_joinedStream;
|
|
};
|
|
|
|
// Abstract class for different implementations of buffered streams.
|
|
class BaseBufferedStream : public RecordSource
|
|
{
|
|
public:
|
|
virtual void locate(thread_db* tdbb, FB_UINT64 position) const = 0;
|
|
virtual FB_UINT64 getCount(thread_db* tdbb) const = 0;
|
|
virtual FB_UINT64 getPosition(jrd_req* request) const = 0;
|
|
};
|
|
|
|
class BufferedStream : public BaseBufferedStream
|
|
{
|
|
struct FieldMap
|
|
{
|
|
static const UCHAR REGULAR_FIELD = 1;
|
|
static const UCHAR TRANSACTION_ID = 2;
|
|
static const UCHAR DBKEY_NUMBER = 3;
|
|
static const UCHAR DBKEY_VALID = 4;
|
|
|
|
FieldMap() : map_stream(0), map_id(0), map_type(0)
|
|
{}
|
|
|
|
FieldMap(UCHAR type, StreamType stream, ULONG id)
|
|
: map_stream(stream), map_id(id), map_type(type)
|
|
{}
|
|
|
|
StreamType map_stream;
|
|
USHORT map_id;
|
|
UCHAR map_type;
|
|
};
|
|
|
|
struct Impure : public RecordSource::Impure
|
|
{
|
|
RecordBuffer* irsb_buffer;
|
|
FB_UINT64 irsb_position;
|
|
};
|
|
|
|
public:
|
|
BufferedStream(CompilerScratch* csb, RecordSource* next);
|
|
|
|
void open(thread_db* tdbb) const;
|
|
void close(thread_db* tdbb) const;
|
|
|
|
bool getRecord(thread_db* tdbb) const;
|
|
bool refetchRecord(thread_db* tdbb) const;
|
|
bool lockRecord(thread_db* tdbb) const;
|
|
|
|
void print(thread_db* tdbb, Firebird::string& plan,
|
|
bool detailed, unsigned level) const;
|
|
|
|
void markRecursive();
|
|
void invalidateRecords(jrd_req* request) const;
|
|
|
|
void findUsedStreams(StreamList& streams, bool expandAll = false) const;
|
|
void nullRecords(thread_db* tdbb) const;
|
|
|
|
void locate(thread_db* tdbb, FB_UINT64 position) const;
|
|
FB_UINT64 getCount(thread_db* tdbb) const;
|
|
|
|
FB_UINT64 getPosition(jrd_req* request) const
|
|
{
|
|
Impure* const impure = request->getImpure<Impure>(m_impure);
|
|
return impure->irsb_position;
|
|
}
|
|
|
|
private:
|
|
NestConst<RecordSource> m_next;
|
|
Firebird::HalfStaticArray<FieldMap, OPT_STATIC_ITEMS> m_map;
|
|
const Format* m_format;
|
|
};
|
|
|
|
|
|
// Multiplexing (many -> one) access methods
|
|
|
|
class NestedLoopJoin : public RecordSource
|
|
{
|
|
public:
|
|
NestedLoopJoin(CompilerScratch* csb, FB_SIZE_T count, RecordSource* const* args);
|
|
NestedLoopJoin(CompilerScratch* csb, RecordSource* outer, RecordSource* inner,
|
|
BoolExprNode* boolean, JoinType joinType);
|
|
|
|
void open(thread_db* tdbb) const;
|
|
void close(thread_db* tdbb) const;
|
|
|
|
bool getRecord(thread_db* tdbb) const;
|
|
bool refetchRecord(thread_db* tdbb) const;
|
|
bool lockRecord(thread_db* tdbb) const;
|
|
|
|
void print(thread_db* tdbb, Firebird::string& plan,
|
|
bool detailed, unsigned level) const;
|
|
|
|
void markRecursive();
|
|
void invalidateRecords(jrd_req* request) const;
|
|
|
|
void findUsedStreams(StreamList& streams, bool expandAll = false) const;
|
|
void nullRecords(thread_db* tdbb) const;
|
|
|
|
private:
|
|
bool fetchRecord(thread_db*, FB_SIZE_T) const;
|
|
|
|
const JoinType m_joinType;
|
|
Firebird::Array<NestConst<RecordSource> > m_args;
|
|
NestConst<BoolExprNode> const m_boolean;
|
|
};
|
|
|
|
class FullOuterJoin : public RecordSource
|
|
{
|
|
public:
|
|
FullOuterJoin(CompilerScratch* csb, RecordSource* arg1, RecordSource* arg2);
|
|
|
|
void open(thread_db* tdbb) const;
|
|
void close(thread_db* tdbb) const;
|
|
|
|
bool getRecord(thread_db* tdbb) const;
|
|
bool refetchRecord(thread_db* tdbb) const;
|
|
bool lockRecord(thread_db* tdbb) const;
|
|
|
|
void print(thread_db* tdbb, Firebird::string& plan,
|
|
bool detailed, unsigned level) const;
|
|
|
|
void markRecursive();
|
|
void invalidateRecords(jrd_req* request) const;
|
|
|
|
void findUsedStreams(StreamList& streams, bool expandAll = false) const;
|
|
void nullRecords(thread_db* tdbb) const;
|
|
|
|
private:
|
|
NestConst<RecordSource> m_arg1;
|
|
NestConst<RecordSource> m_arg2;
|
|
};
|
|
|
|
class HashJoin : public RecordSource
|
|
{
|
|
class HashTable;
|
|
|
|
typedef Firebird::Array<USHORT> KeyLengthArray;
|
|
typedef Firebird::Array<UCHAR> KeyBuffer;
|
|
|
|
struct SubStream
|
|
{
|
|
union
|
|
{
|
|
RecordSource* source;
|
|
BufferedStream* buffer;
|
|
};
|
|
|
|
NestValueArray* keys;
|
|
KeyLengthArray* keyLengths;
|
|
ULONG totalKeyLength;
|
|
};
|
|
|
|
struct Impure : public RecordSource::Impure
|
|
{
|
|
KeyBuffer* irsb_arg_buffer;
|
|
HashTable* irsb_hash_table;
|
|
UCHAR* irsb_leader_buffer;
|
|
ULONG* irsb_record_counts;
|
|
};
|
|
|
|
public:
|
|
HashJoin(thread_db* tdbb, CompilerScratch* csb, FB_SIZE_T count,
|
|
RecordSource* const* args, NestValueArray* const* keys);
|
|
|
|
void open(thread_db* tdbb) const;
|
|
void close(thread_db* tdbb) const;
|
|
|
|
bool getRecord(thread_db* tdbb) const;
|
|
bool refetchRecord(thread_db* tdbb) const;
|
|
bool lockRecord(thread_db* tdbb) const;
|
|
|
|
void print(thread_db* tdbb, Firebird::string& plan,
|
|
bool detailed, unsigned level) const;
|
|
|
|
void markRecursive();
|
|
void invalidateRecords(jrd_req* request) const;
|
|
|
|
void findUsedStreams(StreamList& streams, bool expandAll = false) const;
|
|
void nullRecords(thread_db* tdbb) const;
|
|
|
|
private:
|
|
void computeKeys(thread_db* tdbb, jrd_req* request,
|
|
const SubStream& sub, UCHAR* buffer) const;
|
|
bool fetchRecord(thread_db* tdbb, Impure* impure, FB_SIZE_T stream) const;
|
|
|
|
SubStream m_leader;
|
|
Firebird::Array<SubStream> m_args;
|
|
};
|
|
|
|
class MergeJoin : public RecordSource
|
|
{
|
|
struct MergeFile
|
|
{
|
|
TempSpace* mfb_space; // merge file uses SORT I/O routines
|
|
ULONG mfb_equal_records; // equality group cardinality
|
|
ULONG mfb_record_size; // matches sort map length
|
|
ULONG mfb_current_block; // current merge block in buffer
|
|
ULONG mfb_block_size; // merge block I/O size
|
|
ULONG mfb_blocking_factor; // merge equality records per block
|
|
UCHAR* mfb_block_data; // merge block I/O buffer
|
|
};
|
|
|
|
struct Impure : public RecordSource::Impure
|
|
{
|
|
// CVC: should this value exist for compatibility? It's not used.
|
|
USHORT irsb_mrg_count; // next stream in group
|
|
struct irsb_mrg_repeat
|
|
{
|
|
SLONG irsb_mrg_equal; // queue of equal records
|
|
SLONG irsb_mrg_equal_end; // end of the equal queue
|
|
SLONG irsb_mrg_equal_current; // last fetched record from equal queue
|
|
SLONG irsb_mrg_last_fetched; // first sort merge record of next group
|
|
SSHORT irsb_mrg_order; // logical merge order by substream
|
|
MergeFile irsb_mrg_file; // merge equivalence file
|
|
} irsb_mrg_rpt[1];
|
|
};
|
|
|
|
static const FB_SIZE_T MERGE_BLOCK_SIZE = 65536;
|
|
|
|
public:
|
|
MergeJoin(CompilerScratch* csb, FB_SIZE_T count,
|
|
SortedStream* const* args,
|
|
const NestValueArray* const* keys);
|
|
|
|
void open(thread_db* tdbb) const;
|
|
void close(thread_db* tdbb) const;
|
|
|
|
bool getRecord(thread_db* tdbb) const;
|
|
bool refetchRecord(thread_db* tdbb) const;
|
|
bool lockRecord(thread_db* tdbb) const;
|
|
|
|
void print(thread_db* tdbb, Firebird::string& plan,
|
|
bool detailed, unsigned level) const;
|
|
|
|
void markRecursive();
|
|
void invalidateRecords(jrd_req* request) const;
|
|
|
|
void findUsedStreams(StreamList& streams, bool expandAll = false) const;
|
|
void nullRecords(thread_db* tdbb) const;
|
|
|
|
private:
|
|
int compare(thread_db* tdbb, const NestValueArray* node1,
|
|
const NestValueArray* node2) const;
|
|
UCHAR* getData(thread_db* tdbb, MergeFile* mfb, SLONG record) const;
|
|
SLONG getRecord(thread_db* tdbb, FB_SIZE_T index) const;
|
|
bool fetchRecord(thread_db* tdbb, FB_SIZE_T index) const;
|
|
|
|
Firebird::Array<NestConst<SortedStream> > m_args;
|
|
Firebird::Array<const NestValueArray*> m_keys;
|
|
};
|
|
|
|
class Union : public RecordStream
|
|
{
|
|
struct Impure : public RecordSource::Impure
|
|
{
|
|
USHORT irsb_count;
|
|
};
|
|
|
|
public:
|
|
Union(CompilerScratch* csb, StreamType stream,
|
|
FB_SIZE_T argCount, RecordSource* const* args, NestConst<MapNode>* maps,
|
|
FB_SIZE_T streamCount, const StreamType* streams);
|
|
|
|
void open(thread_db* tdbb) const;
|
|
void close(thread_db* tdbb) const;
|
|
|
|
bool getRecord(thread_db* tdbb) const;
|
|
bool refetchRecord(thread_db* tdbb) const;
|
|
bool lockRecord(thread_db* tdbb) const;
|
|
|
|
void print(thread_db* tdbb, Firebird::string& plan,
|
|
bool detailed, unsigned level) const;
|
|
|
|
void markRecursive();
|
|
void invalidateRecords(jrd_req* request) const;
|
|
void findUsedStreams(StreamList& streams, bool expandAll = false) const;
|
|
|
|
private:
|
|
Firebird::Array<NestConst<RecordSource> > m_args;
|
|
Firebird::Array<NestConst<MapNode> > m_maps;
|
|
StreamList m_streams;
|
|
};
|
|
|
|
class RecursiveStream : public RecordStream
|
|
{
|
|
static const FB_SIZE_T MAX_RECURSE_LEVEL = 1024;
|
|
|
|
enum Mode { ROOT, RECURSE };
|
|
|
|
struct Impure: public RecordSource::Impure
|
|
{
|
|
USHORT irsb_level;
|
|
Mode irsb_mode;
|
|
UCHAR* irsb_stack;
|
|
UCHAR* irsb_data;
|
|
};
|
|
|
|
public:
|
|
RecursiveStream(CompilerScratch* csb, StreamType stream, StreamType mapStream,
|
|
RecordSource* root, RecordSource* inner,
|
|
const MapNode* rootMap, const MapNode* innerMap,
|
|
FB_SIZE_T streamCount, const StreamType* innerStreams,
|
|
ULONG saveOffset);
|
|
|
|
void open(thread_db* tdbb) const;
|
|
void close(thread_db* tdbb) const;
|
|
|
|
bool getRecord(thread_db* tdbb) const;
|
|
bool refetchRecord(thread_db* tdbb) const;
|
|
bool lockRecord(thread_db* tdbb) const;
|
|
|
|
void print(thread_db* tdbb, Firebird::string& plan,
|
|
bool detailed, unsigned level) const;
|
|
|
|
void markRecursive();
|
|
void invalidateRecords(jrd_req* request) const;
|
|
void findUsedStreams(StreamList& streams, bool expandAll = false) const;
|
|
|
|
private:
|
|
void cleanupLevel(jrd_req* request, Impure* impure) const;
|
|
|
|
const StreamType m_mapStream;
|
|
NestConst<RecordSource> m_root;
|
|
NestConst<RecordSource> m_inner;
|
|
const MapNode* const m_rootMap;
|
|
const MapNode* const m_innerMap;
|
|
StreamList m_innerStreams;
|
|
const ULONG m_saveOffset;
|
|
FB_SIZE_T m_saveSize;
|
|
};
|
|
|
|
class ConditionalStream : public RecordSource
|
|
{
|
|
struct Impure : public RecordSource::Impure
|
|
{
|
|
const RecordSource* irsb_next;
|
|
};
|
|
|
|
public:
|
|
ConditionalStream(CompilerScratch* csb, RecordSource* first, RecordSource* second,
|
|
BoolExprNode* boolean);
|
|
|
|
void open(thread_db* tdbb) const;
|
|
void close(thread_db* tdbb) const;
|
|
|
|
bool getRecord(thread_db* tdbb) const;
|
|
bool refetchRecord(thread_db* tdbb) const;
|
|
bool lockRecord(thread_db* tdbb) const;
|
|
|
|
void print(thread_db* tdbb, Firebird::string& plan,
|
|
bool detailed, unsigned level) const;
|
|
|
|
void markRecursive();
|
|
void invalidateRecords(jrd_req* request) const;
|
|
|
|
void findUsedStreams(StreamList& streams, bool expandAll = false) const;
|
|
void nullRecords(thread_db* tdbb) const;
|
|
|
|
private:
|
|
NestConst<RecordSource> m_first;
|
|
NestConst<RecordSource> m_second;
|
|
NestConst<BoolExprNode> const m_boolean;
|
|
};
|
|
|
|
} // namespace
|
|
|
|
#endif // JRD_RECORD_SOURCE_H
|