8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-29 06:43:03 +01:00
firebird-mirror/src/jrd/pcmet.epp
2015-05-03 06:20:34 +00:00

296 lines
8.1 KiB
Plaintext

/*
* PROGRAM: JRD Access Method
* MODULE: pcmet.epp
* DESCRIPTION: Meta data for expression indices
*
* 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): ______________________________________.
*/
#include "firebird.h"
#include <string.h>
#include "../jrd/jrd.h"
#include "../jrd/irq.h"
#include "../jrd/tra.h"
#include "../jrd/val.h"
#include "../jrd/ods.h"
#include "../jrd/btr.h"
#include "../jrd/req.h"
#include "../jrd/exe.h"
#include "../jrd/met.h"
#include "../jrd/lck.h"
#include "../jrd/cmp_proto.h"
#include "../jrd/dfw_proto.h"
#include "../jrd/err_proto.h"
#include "../jrd/exe_proto.h"
#include "../yvalve/gds_proto.h"
#include "../jrd/idx_proto.h"
#include "../jrd/tra_proto.h"
#include "../jrd/lck_proto.h"
#include "../jrd/met_proto.h"
#include "../jrd/mov_proto.h"
#include "../jrd/pcmet_proto.h"
using namespace Jrd;
using namespace Firebird;
DATABASE DB = FILENAME "ODS.RDB";
void PCMET_expression_index(thread_db* tdbb, const MetaName& name, USHORT& id, jrd_tra* transaction)
{
/**************************************
*
* P C M E T _ e x p r e s s i o n _ i n d e x
*
**************************************
*
* Functional description
* Create a new expression index.
*
**************************************/
jrd_rel* relation = NULL;
index_desc idx;
MemoryPool* new_pool = NULL;
SET_TDBB(tdbb);
Jrd::Attachment* attachment = tdbb->getAttachment();
#ifdef DEV_BUILD
Database* dbb = tdbb->getDatabase();
#endif
MOVE_CLEAR(&idx, sizeof(index_desc));
AutoCacheRequest request(tdbb, irq_c_exp_index, IRQ_REQUESTS);
FOR(REQUEST_HANDLE request)
IDX IN RDB$INDICES CROSS
REL IN RDB$RELATIONS OVER RDB$RELATION_NAME WITH
IDX.RDB$EXPRESSION_BLR NOT MISSING AND
IDX.RDB$INDEX_NAME EQ name.c_str()
{
if (!relation)
{
relation = MET_relation(tdbb, REL.RDB$RELATION_ID);
if (relation->rel_name.length() == 0) {
relation->rel_name = REL.RDB$RELATION_NAME;
}
if (IDX.RDB$INDEX_ID && IDX.RDB$STATISTICS < 0.0)
{
SelectivityList selectivity(*tdbb->getDefaultPool());
const USHORT localId = IDX.RDB$INDEX_ID - 1;
IDX_statistics(tdbb, relation, localId, selectivity);
DFW_update_index(name.c_str(), localId, selectivity, transaction);
return;
}
if (IDX.RDB$INDEX_ID)
{
IDX_delete_index(tdbb, relation, IDX.RDB$INDEX_ID - 1);
MET_delete_dependencies(tdbb, name, obj_expression_index, transaction);
MODIFY IDX
IDX.RDB$INDEX_ID.NULL = TRUE;
END_MODIFY
}
if (IDX.RDB$INDEX_INACTIVE)
return;
if (IDX.RDB$SEGMENT_COUNT)
{
// Msg359: segments not allowed in expression index %s
ERR_post(Arg::Gds(isc_no_meta_update) <<
Arg::Gds(isc_no_segments_err) << Arg::Str(name));
}
if (IDX.RDB$UNIQUE_FLAG)
idx.idx_flags |= idx_unique;
if (IDX.RDB$INDEX_TYPE == 1)
idx.idx_flags |= idx_descending;
CompilerScratch* csb = 0;
// allocate a new pool to contain the expression tree for the expression index
new_pool = attachment->createPool();
{ // scope
Jrd::ContextPoolHolder context(tdbb, new_pool);
MET_scan_relation(tdbb, relation);
if (!IDX.RDB$EXPRESSION_BLR.NULL)
{
idx.idx_expression = static_cast<ValueExprNode*>(MET_get_dependencies(
tdbb, relation, NULL, 0, NULL, &IDX.RDB$EXPRESSION_BLR,
&idx.idx_expression_statement, &csb, name, obj_expression_index, 0,
transaction));
}
} // end scope
// fake a description of the index
idx.idx_count = 1;
idx.idx_flags |= idx_expressn;
idx.idx_expression->getDesc(tdbb, csb, &idx.idx_expression_desc);
idx.idx_rpt[0].idx_itype =
DFW_assign_index_type(tdbb, name,
idx.idx_expression_desc.dsc_dtype,
idx.idx_expression_desc.dsc_sub_type);
idx.idx_rpt[0].idx_selectivity = 0;
delete csb;
}
}
END_FOR
if (!relation)
{
if (new_pool)
attachment->deletePool(new_pool);
// Msg308: can't create index %s
ERR_post(Arg::Gds(isc_no_meta_update) <<
Arg::Gds(isc_idx_create_err) << Arg::Str(name));
}
// Actually create the index
SelectivityList selectivity(*tdbb->getDefaultPool());
jrd_tra* const current_transaction = tdbb->getTransaction();
jrd_req* const current_request = tdbb->getRequest();
try
{
fb_assert(id <= dbb->dbb_max_idx);
idx.idx_id = id;
IDX_create_index(tdbb, relation, &idx, name.c_str(), &id, transaction, selectivity);
fb_assert(id == idx.idx_id);
}
catch (const Exception&)
{
tdbb->setTransaction(current_transaction);
tdbb->setRequest(current_request);
throw;
}
tdbb->setTransaction(current_transaction);
tdbb->setRequest(current_request);
DFW_update_index(name.c_str(), idx.idx_id, selectivity, transaction);
// Get rid of the pool containing the expression tree
attachment->deletePool(new_pool);
}
void PCMET_lookup_index(thread_db* tdbb, jrd_rel* relation, index_desc* idx)
{
/**************************************
*
* P C M E T _ l o o k u p _ i n d e x
*
**************************************
*
* Functional description
* Lookup information about an index, in
* the metadata cache if possible.
*
**************************************/
SET_TDBB(tdbb);
Jrd::Attachment* attachment = tdbb->getAttachment();
// Check the index blocks for the relation to see if we have a cached block
IndexBlock* index_block;
for (index_block = relation->rel_index_blocks; index_block; index_block = index_block->idb_next)
{
if (index_block->idb_id == idx->idx_id)
break;
}
if (index_block && index_block->idb_expression)
{
idx->idx_expression = index_block->idb_expression;
idx->idx_expression_statement = index_block->idb_expression_statement;
memcpy(&idx->idx_expression_desc, &index_block->idb_expression_desc, sizeof(struct dsc));
return;
}
if (!(relation->rel_flags & REL_scanned) || (relation->rel_flags & REL_being_scanned))
{
MET_scan_relation(tdbb, relation);
}
CompilerScratch* csb = NULL;
AutoCacheRequest request(tdbb, irq_l_exp_index, IRQ_REQUESTS);
FOR(REQUEST_HANDLE request)
IDX IN RDB$INDICES WITH
IDX.RDB$RELATION_NAME EQ relation->rel_name.c_str() AND
IDX.RDB$INDEX_ID EQ idx->idx_id + 1
{
if (idx->idx_expression_statement)
{
idx->idx_expression_statement->release(tdbb);
idx->idx_expression_statement = NULL;
}
// parse the blr, making sure to create the resulting expression
// tree and request in its own pool so that it may be cached
// with the index block in the "permanent" metadata cache
{ // scope
Jrd::ContextPoolHolder context(tdbb, attachment->createPool());
idx->idx_expression = static_cast<ValueExprNode*>(MET_parse_blob(
tdbb, relation, &IDX.RDB$EXPRESSION_BLR, &csb,
&idx->idx_expression_statement, false, false));
} // end scope
}
END_FOR
if (csb)
idx->idx_expression->getDesc(tdbb, csb, &idx->idx_expression_desc);
delete csb;
// if there is no existing index block for this index, create
// one and link it in with the index blocks for this relation
if (!index_block)
index_block = IDX_create_index_block(tdbb, relation, idx->idx_id);
// if we can't get the lock, no big deal: just give up on caching the index info
if (!LCK_lock(tdbb, index_block->idb_lock, LCK_SR, LCK_NO_WAIT))
{
// clear lock error from status vector
fb_utils::init_status(tdbb->tdbb_status_vector);
return;
}
// whether the index block already existed or was just created,
// fill in the cached information about the index
index_block->idb_expression = idx->idx_expression;
index_block->idb_expression_statement = idx->idx_expression_statement;
memcpy(&index_block->idb_expression_desc, &idx->idx_expression_desc, sizeof(struct dsc));
}