| 1272 | }; |
| 1273 | |
| 1274 | class MergeJoin : public RecordSource |
| 1275 | { |
| 1276 | struct MergeFile |
| 1277 | { |
| 1278 | TempSpace* mfb_space; // merge file uses SORT I/O routines |
| 1279 | ULONG mfb_equal_records; // equality group cardinality |
| 1280 | ULONG mfb_record_size; // matches sort map length |
| 1281 | ULONG mfb_current_block; // current merge block in buffer |
| 1282 | ULONG mfb_block_size; // merge block I/O size |
| 1283 | ULONG mfb_blocking_factor; // merge equality records per block |
| 1284 | UCHAR* mfb_block_data; // merge block I/O buffer |
| 1285 | }; |
| 1286 | |
| 1287 | struct Impure : public RecordSource::Impure |
| 1288 | { |
| 1289 | // CVC: should this value exist for compatibility? It's not used. |
| 1290 | USHORT irsb_mrg_count; // next stream in group |
| 1291 | struct irsb_mrg_repeat |
| 1292 | { |
| 1293 | SLONG irsb_mrg_equal; // queue of equal records |
| 1294 | SLONG irsb_mrg_equal_end; // end of the equal queue |
| 1295 | SLONG irsb_mrg_equal_current; // last fetched record from equal queue |
| 1296 | SLONG irsb_mrg_last_fetched; // first sort merge record of next group |
| 1297 | SSHORT irsb_mrg_order; // logical merge order by substream |
| 1298 | MergeFile irsb_mrg_file; // merge equivalence file |
| 1299 | } irsb_mrg_rpt[1]; |
| 1300 | }; |
| 1301 | |
| 1302 | static const FB_SIZE_T MERGE_BLOCK_SIZE = 65536; |
| 1303 | |
| 1304 | public: |
| 1305 | MergeJoin(CompilerScratch* csb, FB_SIZE_T count, |
| 1306 | SortedStream* const* args, |
| 1307 | const NestValueArray* const* keys); |
| 1308 | |
| 1309 | void close(thread_db* tdbb) const override; |
| 1310 | |
| 1311 | bool refetchRecord(thread_db* tdbb) const override; |
| 1312 | WriteLockResult lockRecord(thread_db* tdbb) const override; |
| 1313 | |
| 1314 | void getChildren(Firebird::Array<const RecordSource*>& children) const override; |
| 1315 | |
| 1316 | void print(thread_db* tdbb, Firebird::string& plan, |
| 1317 | bool detailed, unsigned level, bool recurse) const override; |
| 1318 | |
| 1319 | void markRecursive() override; |
| 1320 | void invalidateRecords(Request* request) const override; |
| 1321 | |
| 1322 | void findUsedStreams(StreamList& streams, bool expandAll = false) const override; |
| 1323 | bool isDependent(const StreamList& streams) const override; |
| 1324 | void nullRecords(thread_db* tdbb) const override; |
| 1325 | |
| 1326 | protected: |
| 1327 | void internalOpen(thread_db* tdbb) const override; |
| 1328 | bool internalGetRecord(thread_db* tdbb) const override; |
| 1329 | |
| 1330 | private: |
| 1331 | int compare(thread_db* tdbb, const NestValueArray* node1, |