2009-12-09 19:45:44 +01:00
|
|
|
/*
|
|
|
|
* 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): ______________________________________.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "firebird.h"
|
|
|
|
#include "../jrd/align.h"
|
|
|
|
#include "../jrd/jrd.h"
|
|
|
|
#include "../jrd/req.h"
|
|
|
|
#include "../jrd/cmp_proto.h"
|
|
|
|
#include "../jrd/evl_proto.h"
|
2015-02-19 15:15:00 +01:00
|
|
|
#include "../jrd/met_proto.h"
|
2009-12-09 19:45:44 +01:00
|
|
|
#include "../jrd/mov_proto.h"
|
2015-02-19 15:15:00 +01:00
|
|
|
#include "../jrd/vio_proto.h"
|
2009-12-09 19:45:44 +01:00
|
|
|
|
|
|
|
#include "RecordSource.h"
|
|
|
|
|
|
|
|
using namespace Firebird;
|
|
|
|
using namespace Jrd;
|
|
|
|
|
|
|
|
// --------------------------
|
|
|
|
// Data access: record buffer
|
|
|
|
// --------------------------
|
|
|
|
|
|
|
|
BufferedStream::BufferedStream(CompilerScratch* csb, RecordSource* next)
|
|
|
|
: m_next(next), m_map(csb->csb_pool)
|
|
|
|
{
|
|
|
|
fb_assert(m_next);
|
|
|
|
|
|
|
|
m_impure = CMP_impure(csb, sizeof(Impure));
|
|
|
|
|
2011-02-20 16:34:08 +01:00
|
|
|
StreamList streams;
|
2009-12-09 19:45:44 +01:00
|
|
|
m_next->findUsedStreams(streams);
|
|
|
|
|
2009-12-10 02:32:47 +01:00
|
|
|
Array<dsc> fields;
|
2009-12-09 19:45:44 +01:00
|
|
|
|
2011-02-20 16:34:08 +01:00
|
|
|
for (StreamList::iterator i = streams.begin(); i != streams.end(); ++i)
|
2009-12-09 19:45:44 +01:00
|
|
|
{
|
2012-04-12 11:02:13 +02:00
|
|
|
const StreamType stream = *i;
|
2009-12-09 19:45:44 +01:00
|
|
|
CompilerScratch::csb_repeat* const tail = &csb->csb_rpt[stream];
|
2014-12-01 22:53:29 +01:00
|
|
|
tail->csb_flags |= csb_offline;
|
2009-12-09 19:45:44 +01:00
|
|
|
|
2009-12-13 11:41:53 +01:00
|
|
|
UInt32Bitmap::Accessor accessor(tail->csb_fields);
|
2009-12-09 19:45:44 +01:00
|
|
|
|
|
|
|
if (accessor.getFirst())
|
|
|
|
{
|
|
|
|
do {
|
|
|
|
const USHORT id = (USHORT) accessor.current();
|
|
|
|
const Format* const format = tail->csb_format; // CMP_format(tdbb, csb, stream);
|
|
|
|
const dsc* const desc = &format->fmt_desc[id];
|
2009-12-14 13:56:27 +01:00
|
|
|
m_map.add(FieldMap(FieldMap::REGULAR_FIELD, stream, id));
|
2009-12-09 19:45:44 +01:00
|
|
|
fields.add(*desc);
|
2009-12-10 02:32:47 +01:00
|
|
|
} while (accessor.getNext());
|
2009-12-09 19:45:44 +01:00
|
|
|
}
|
2009-12-14 13:56:27 +01:00
|
|
|
|
|
|
|
dsc desc;
|
|
|
|
|
|
|
|
desc.makeLong(0);
|
|
|
|
m_map.add(FieldMap(FieldMap::TRANSACTION_ID, stream, 0));
|
|
|
|
fields.add(desc);
|
|
|
|
|
|
|
|
desc.makeInt64(0);
|
|
|
|
m_map.add(FieldMap(FieldMap::DBKEY_NUMBER, stream, 0));
|
|
|
|
fields.add(desc);
|
|
|
|
|
|
|
|
desc.makeText(1, CS_BINARY);
|
|
|
|
m_map.add(FieldMap(FieldMap::DBKEY_VALID, stream, 0));
|
|
|
|
fields.add(desc);
|
2009-12-09 19:45:44 +01:00
|
|
|
}
|
|
|
|
|
2014-07-17 20:48:46 +02:00
|
|
|
const FB_SIZE_T count = fields.getCount();
|
2011-02-02 12:31:04 +01:00
|
|
|
Format* const format = Format::newFormat(csb->csb_pool, count);
|
2013-07-16 08:22:27 +02:00
|
|
|
format->fmt_length = FLAG_BYTES(count);
|
2009-12-09 19:45:44 +01:00
|
|
|
|
2014-07-17 20:48:46 +02:00
|
|
|
for (FB_SIZE_T i = 0; i < count; i++)
|
2009-12-09 19:45:44 +01:00
|
|
|
{
|
2010-07-06 13:09:32 +02:00
|
|
|
dsc& desc = format->fmt_desc[i] = fields[i];
|
2013-07-16 08:22:27 +02:00
|
|
|
|
2009-12-14 13:56:27 +01:00
|
|
|
if (desc.dsc_dtype >= dtype_aligned)
|
2014-07-28 15:01:10 +02:00
|
|
|
format->fmt_length = FB_ALIGN(format->fmt_length, type_alignments[desc.dsc_dtype]);
|
2013-07-16 08:22:27 +02:00
|
|
|
|
|
|
|
desc.dsc_address = (UCHAR*)(IPTR) format->fmt_length;
|
|
|
|
format->fmt_length += desc.dsc_length;
|
2009-12-09 19:45:44 +01:00
|
|
|
}
|
|
|
|
|
2010-07-06 13:09:32 +02:00
|
|
|
m_format = format;
|
2009-12-09 19:45:44 +01:00
|
|
|
}
|
|
|
|
|
2010-07-05 20:37:35 +02:00
|
|
|
void BufferedStream::open(thread_db* tdbb) const
|
2009-12-09 19:45:44 +01:00
|
|
|
{
|
|
|
|
jrd_req* const request = tdbb->getRequest();
|
2010-04-05 23:20:08 +02:00
|
|
|
Impure* const impure = request->getImpure<Impure>(m_impure);
|
2009-12-09 19:45:44 +01:00
|
|
|
|
2010-01-06 16:40:39 +01:00
|
|
|
impure->irsb_flags = irsb_open | irsb_mustread;
|
2009-12-09 19:45:44 +01:00
|
|
|
|
|
|
|
m_next->open(tdbb);
|
|
|
|
|
|
|
|
delete impure->irsb_buffer;
|
|
|
|
MemoryPool& pool = *tdbb->getDefaultPool();
|
2010-03-03 16:02:01 +01:00
|
|
|
impure->irsb_buffer = FB_NEW(pool) RecordBuffer(pool, m_format);
|
2009-12-09 19:45:44 +01:00
|
|
|
|
2010-01-06 16:40:39 +01:00
|
|
|
impure->irsb_position = 0;
|
|
|
|
}
|
|
|
|
|
2010-07-05 20:37:35 +02:00
|
|
|
void BufferedStream::close(thread_db* tdbb) const
|
2010-01-06 16:40:39 +01:00
|
|
|
{
|
|
|
|
jrd_req* const request = tdbb->getRequest();
|
|
|
|
|
|
|
|
invalidateRecords(request);
|
|
|
|
|
2010-04-05 23:20:08 +02:00
|
|
|
Impure* const impure = request->getImpure<Impure>(m_impure);
|
2010-01-06 16:40:39 +01:00
|
|
|
|
|
|
|
if (impure->irsb_flags & irsb_open)
|
|
|
|
{
|
|
|
|
impure->irsb_flags &= ~irsb_open;
|
|
|
|
|
|
|
|
delete impure->irsb_buffer;
|
|
|
|
impure->irsb_buffer = NULL;
|
|
|
|
|
|
|
|
m_next->close(tdbb);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-07-05 20:37:35 +02:00
|
|
|
bool BufferedStream::getRecord(thread_db* tdbb) const
|
2010-01-06 16:40:39 +01:00
|
|
|
{
|
2012-12-17 18:33:45 +01:00
|
|
|
if (--tdbb->tdbb_quantum < 0)
|
|
|
|
JRD_reschedule(tdbb, 0, true);
|
|
|
|
|
2010-01-06 16:40:39 +01:00
|
|
|
jrd_req* const request = tdbb->getRequest();
|
2010-04-05 23:20:08 +02:00
|
|
|
Impure* const impure = request->getImpure<Impure>(m_impure);
|
2010-01-06 16:40:39 +01:00
|
|
|
|
|
|
|
if (!(impure->irsb_flags & irsb_open))
|
|
|
|
return false;
|
|
|
|
|
2015-02-19 15:15:00 +01:00
|
|
|
dsc from, to;
|
|
|
|
|
2009-12-09 19:45:44 +01:00
|
|
|
Record* const buffer_record = impure->irsb_buffer->getTempRecord();
|
|
|
|
|
2010-01-06 16:40:39 +01:00
|
|
|
if (impure->irsb_flags & irsb_mustread)
|
2009-12-09 19:45:44 +01:00
|
|
|
{
|
2010-01-06 16:40:39 +01:00
|
|
|
if (!m_next->getRecord(tdbb))
|
|
|
|
{
|
2010-01-18 22:37:47 +01:00
|
|
|
// ASF: There is nothing more to read, so remove irsb_mustread flag.
|
|
|
|
// That's important if m_next is reused in another stream and our caller
|
2010-01-25 07:48:09 +01:00
|
|
|
// relies on this BufferedStream being non-lazy, like WindowedStream does.
|
2010-01-18 22:37:47 +01:00
|
|
|
impure->irsb_flags &= ~irsb_mustread;
|
2010-01-06 16:40:39 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-02-19 15:15:00 +01:00
|
|
|
buffer_record->nullify();
|
|
|
|
|
2011-03-04 08:52:08 +01:00
|
|
|
// Assign the fields to the record to be stored
|
2014-07-17 20:48:46 +02:00
|
|
|
for (FB_SIZE_T i = 0; i < m_map.getCount(); i++)
|
2009-12-09 19:45:44 +01:00
|
|
|
{
|
2009-12-14 13:56:27 +01:00
|
|
|
const FieldMap& map = m_map[i];
|
2009-12-09 19:45:44 +01:00
|
|
|
|
|
|
|
record_param* const rpb = &request->req_rpb[map.map_stream];
|
2015-02-19 15:15:00 +01:00
|
|
|
Record* const record = rpb->rpb_record;
|
|
|
|
|
|
|
|
if (map.map_type == FieldMap::REGULAR_FIELD)
|
|
|
|
{
|
|
|
|
if (!EVL_field(rpb->rpb_relation, record, map.map_id, &from))
|
|
|
|
continue;
|
|
|
|
}
|
2009-12-09 19:45:44 +01:00
|
|
|
|
2013-03-17 18:35:53 +01:00
|
|
|
buffer_record->clearNull(i);
|
2011-03-04 08:52:08 +01:00
|
|
|
|
2015-02-19 15:15:00 +01:00
|
|
|
if (!EVL_field(rpb->rpb_relation, buffer_record, (USHORT) i, &to))
|
2011-03-03 15:12:41 +01:00
|
|
|
fb_assert(false);
|
2009-12-14 13:56:27 +01:00
|
|
|
|
|
|
|
switch (map.map_type)
|
2009-12-09 19:45:44 +01:00
|
|
|
{
|
2009-12-14 13:56:27 +01:00
|
|
|
case FieldMap::REGULAR_FIELD:
|
2015-02-19 15:15:00 +01:00
|
|
|
MOV_move(tdbb, &from, &to);
|
2009-12-14 13:56:27 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case FieldMap::TRANSACTION_ID:
|
2012-05-19 14:04:37 +02:00
|
|
|
*reinterpret_cast<ULONG*>(to.dsc_address) = rpb->rpb_transaction_nr;
|
2009-12-14 13:56:27 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case FieldMap::DBKEY_NUMBER:
|
|
|
|
*reinterpret_cast<SINT64*>(to.dsc_address) = rpb->rpb_number.getValue();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FieldMap::DBKEY_VALID:
|
|
|
|
*to.dsc_address = (UCHAR) rpb->rpb_number.isValid();
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
fb_assert(false);
|
2009-12-09 19:45:44 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Put the record into the buffer
|
|
|
|
impure->irsb_buffer->store(buffer_record);
|
|
|
|
}
|
2010-01-06 16:40:39 +01:00
|
|
|
else
|
2009-12-09 19:45:44 +01:00
|
|
|
{
|
2010-01-06 16:40:39 +01:00
|
|
|
// Read the record from the buffer
|
|
|
|
if (!impure->irsb_buffer->fetch(impure->irsb_position, buffer_record))
|
|
|
|
return false;
|
2009-12-14 13:56:27 +01:00
|
|
|
|
2015-02-19 15:15:00 +01:00
|
|
|
StreamType stream = INVALID_STREAM;
|
|
|
|
|
2010-01-06 16:40:39 +01:00
|
|
|
// Assign fields back to their original streams
|
2014-07-17 20:48:46 +02:00
|
|
|
for (FB_SIZE_T i = 0; i < m_map.getCount(); i++)
|
2009-12-09 19:45:44 +01:00
|
|
|
{
|
2010-01-06 16:40:39 +01:00
|
|
|
const FieldMap& map = m_map[i];
|
|
|
|
|
|
|
|
record_param* const rpb = &request->req_rpb[map.map_stream];
|
2015-02-19 15:15:00 +01:00
|
|
|
|
|
|
|
if (map.map_stream != stream)
|
|
|
|
{
|
|
|
|
stream = map.map_stream;
|
|
|
|
|
|
|
|
// See SortedStream::mapData() for explanations why we need
|
|
|
|
// to upgrade the record format
|
|
|
|
|
|
|
|
if (rpb->rpb_relation && !rpb->rpb_number.isValid())
|
|
|
|
VIO_record(tdbb, rpb, MET_current(tdbb, rpb->rpb_relation), tdbb->getDefaultPool());
|
|
|
|
}
|
|
|
|
|
2010-01-06 16:40:39 +01:00
|
|
|
Record* const record = rpb->rpb_record;
|
2015-02-19 15:15:00 +01:00
|
|
|
record->reset();
|
2010-01-06 16:40:39 +01:00
|
|
|
|
2015-02-19 15:15:00 +01:00
|
|
|
if (!EVL_field(rpb->rpb_relation, buffer_record, (USHORT) i, &from))
|
2009-12-14 13:56:27 +01:00
|
|
|
{
|
2010-01-06 16:40:39 +01:00
|
|
|
fb_assert(map.map_type == FieldMap::REGULAR_FIELD);
|
2015-02-19 15:15:00 +01:00
|
|
|
record->setNull(map.map_id);
|
2010-01-06 16:40:39 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (map.map_type)
|
|
|
|
{
|
|
|
|
case FieldMap::REGULAR_FIELD:
|
2009-12-14 13:56:27 +01:00
|
|
|
{
|
2015-02-19 15:15:00 +01:00
|
|
|
EVL_field(rpb->rpb_relation, record, map.map_id, &to);
|
2010-01-06 16:40:39 +01:00
|
|
|
MOV_move(tdbb, &from, &to);
|
2015-02-19 15:15:00 +01:00
|
|
|
record->clearNull(map.map_id);
|
2010-01-06 16:40:39 +01:00
|
|
|
}
|
|
|
|
break;
|
2009-12-14 13:56:27 +01:00
|
|
|
|
2010-01-06 16:40:39 +01:00
|
|
|
case FieldMap::TRANSACTION_ID:
|
2012-05-19 14:04:37 +02:00
|
|
|
rpb->rpb_transaction_nr = *reinterpret_cast<ULONG*>(from.dsc_address);
|
2010-01-06 16:40:39 +01:00
|
|
|
break;
|
2009-12-14 13:56:27 +01:00
|
|
|
|
2010-01-06 16:40:39 +01:00
|
|
|
case FieldMap::DBKEY_NUMBER:
|
|
|
|
rpb->rpb_number.setValue(*reinterpret_cast<SINT64*>(from.dsc_address));
|
|
|
|
break;
|
2009-12-14 13:56:27 +01:00
|
|
|
|
2010-01-06 16:40:39 +01:00
|
|
|
case FieldMap::DBKEY_VALID:
|
|
|
|
rpb->rpb_number.setValid(*from.dsc_address != 0);
|
|
|
|
break;
|
2009-12-14 13:56:27 +01:00
|
|
|
|
2010-01-06 16:40:39 +01:00
|
|
|
default:
|
|
|
|
fb_assert(false);
|
|
|
|
}
|
2009-12-09 19:45:44 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impure->irsb_position++;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-07-05 20:37:35 +02:00
|
|
|
bool BufferedStream::refetchRecord(thread_db* tdbb) const
|
2009-12-09 19:45:44 +01:00
|
|
|
{
|
|
|
|
return m_next->refetchRecord(tdbb);
|
|
|
|
}
|
|
|
|
|
2010-07-05 20:37:35 +02:00
|
|
|
bool BufferedStream::lockRecord(thread_db* tdbb) const
|
2009-12-09 19:45:44 +01:00
|
|
|
{
|
|
|
|
return m_next->lockRecord(tdbb);
|
|
|
|
}
|
|
|
|
|
2011-02-02 12:31:04 +01:00
|
|
|
void BufferedStream::print(thread_db* tdbb, string& plan, bool detailed, unsigned level) const
|
2009-12-09 19:45:44 +01:00
|
|
|
{
|
2011-02-02 12:31:04 +01:00
|
|
|
if (detailed)
|
2014-02-01 10:42:30 +01:00
|
|
|
{
|
|
|
|
string extras;
|
|
|
|
extras.printf(" (record length: %"ULONGFORMAT")", m_format->fmt_length);
|
|
|
|
|
|
|
|
plan += printIndent(++level) + "Record Buffer" + extras;
|
|
|
|
}
|
2009-12-09 19:45:44 +01:00
|
|
|
|
2011-02-02 12:31:04 +01:00
|
|
|
m_next->print(tdbb, plan, detailed, level);
|
2009-12-09 19:45:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void BufferedStream::markRecursive()
|
|
|
|
{
|
|
|
|
m_next->markRecursive();
|
|
|
|
}
|
|
|
|
|
2011-12-14 07:45:24 +01:00
|
|
|
void BufferedStream::findUsedStreams(StreamList& streams, bool expandAll) const
|
2009-12-09 19:45:44 +01:00
|
|
|
{
|
2011-12-14 07:45:24 +01:00
|
|
|
m_next->findUsedStreams(streams, expandAll);
|
2009-12-09 19:45:44 +01:00
|
|
|
}
|
|
|
|
|
2010-07-05 20:37:35 +02:00
|
|
|
void BufferedStream::invalidateRecords(jrd_req* request) const
|
2009-12-09 19:45:44 +01:00
|
|
|
{
|
|
|
|
m_next->invalidateRecords(request);
|
|
|
|
}
|
|
|
|
|
2010-07-05 20:37:35 +02:00
|
|
|
void BufferedStream::nullRecords(thread_db* tdbb) const
|
2009-12-09 19:45:44 +01:00
|
|
|
{
|
|
|
|
m_next->nullRecords(tdbb);
|
|
|
|
}
|
|
|
|
|
2010-07-06 13:09:32 +02:00
|
|
|
void BufferedStream::locate(thread_db* tdbb, FB_UINT64 position) const
|
2009-12-09 19:45:44 +01:00
|
|
|
{
|
2010-01-06 16:40:39 +01:00
|
|
|
jrd_req* const request = tdbb->getRequest();
|
2010-04-05 23:20:08 +02:00
|
|
|
Impure* const impure = request->getImpure<Impure>(m_impure);
|
2010-01-06 16:40:39 +01:00
|
|
|
|
|
|
|
// If we haven't fetched and cached the underlying stream completely, do it now
|
|
|
|
if (impure->irsb_flags & irsb_mustread)
|
|
|
|
{
|
|
|
|
while (this->getRecord(tdbb))
|
|
|
|
; // no-op
|
2010-01-19 17:32:02 +01:00
|
|
|
fb_assert(!(impure->irsb_flags & irsb_mustread));
|
2010-01-06 16:40:39 +01:00
|
|
|
}
|
|
|
|
|
2009-12-09 19:45:44 +01:00
|
|
|
impure->irsb_position = position;
|
|
|
|
}
|
|
|
|
|
2013-09-20 09:06:08 +02:00
|
|
|
FB_UINT64 BufferedStream::getCount(thread_db* tdbb) const
|
2009-12-09 19:45:44 +01:00
|
|
|
{
|
2013-09-20 09:06:08 +02:00
|
|
|
jrd_req* const request = tdbb->getRequest();
|
2010-04-05 23:20:08 +02:00
|
|
|
Impure* const impure = request->getImpure<Impure>(m_impure);
|
2013-09-20 09:06:08 +02:00
|
|
|
|
|
|
|
// If we haven't fetched and cached the underlying stream completely, do it now
|
|
|
|
if (impure->irsb_flags & irsb_mustread)
|
|
|
|
{
|
|
|
|
while (this->getRecord(tdbb))
|
|
|
|
; // no-op
|
|
|
|
fb_assert(!(impure->irsb_flags & irsb_mustread));
|
|
|
|
}
|
|
|
|
|
2009-12-09 19:45:44 +01:00
|
|
|
return impure->irsb_buffer ? impure->irsb_buffer->getCount() : 0;
|
|
|
|
}
|