8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-31 11:23:02 +01:00
firebird-mirror/src/jrd/pcmet.epp
dimitr 42fbd2615b Front ported CORE-2833: Changing data that affects an expression index that contains references to null date fields fails.
Also, removed the duplicated (and, at the first glance, unnecessary) code that forced us to deal with the already_attached flag. To be tested in the field.
2010-02-26 09:02:22 +00:00

303 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/common.h"
#include "../jrd/ibase.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 "../jrd/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);
Database* dbb = tdbb->getDatabase();
MOVE_CLEAR(&idx, sizeof(index_desc));
jrd_req* request = CMP_find_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 (!REQUEST(irq_c_exp_index))
{
REQUEST(irq_c_exp_index) = request;
}
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 id = IDX.RDB$INDEX_ID - 1;
IDX_statistics(tdbb, relation, id, selectivity);
DFW_update_index(name.c_str(), id, selectivity, transaction);
EXE_unwind(tdbb, request);
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)
{
EXE_unwind(tdbb, request);
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 = dbb->createPool();
{ // scope
Jrd::ContextPoolHolder context(tdbb, new_pool);
MET_scan_relation(tdbb, relation);
if (!IDX.RDB$EXPRESSION_BLR.NULL)
{
idx.idx_expression = MET_get_dependencies(tdbb, relation,
NULL, 0, NULL,
&IDX.RDB$EXPRESSION_BLR,
&idx.idx_expression_request,
&csb, name,
obj_expression_index, 0,
transaction);
}
} // end scope
// fake a description of the index
idx.idx_count = 1;
idx.idx_flags |= idx_expressn;
CMP_get_desc(tdbb, csb, idx.idx_expression, &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 (!REQUEST(irq_c_exp_index))
{
REQUEST(irq_c_exp_index) = request;
}
if (!relation)
{
// 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();
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);
tdbb->setTransaction(current_transaction);
DFW_update_index(name.c_str(), idx.idx_id, selectivity, transaction);
// Get rid of the pool containing the expression tree
dbb->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);
Database* dbb = tdbb->getDatabase();
// 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_request = index_block->idb_expression_request;
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;
jrd_req* request = CMP_find_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 (!REQUEST(irq_l_exp_index))
{
REQUEST(irq_l_exp_index) = request;
}
if (idx->idx_expression_request)
{
CMP_release(tdbb, idx->idx_expression_request);
idx->idx_expression_request = 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, dbb->createPool());
idx->idx_expression =
MET_parse_blob(tdbb, relation, &IDX.RDB$EXPRESSION_BLR, &csb,
&idx->idx_expression_request, false);
} // end scope
END_FOR;
if (!REQUEST(irq_l_exp_index))
{
REQUEST(irq_l_exp_index) = request;
}
if (csb)
{
CMP_get_desc(tdbb, csb, idx->idx_expression, &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))
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_request = idx->idx_expression_request;
memcpy(&index_block->idb_expression_desc, &idx->idx_expression_desc, sizeof(struct dsc));
}