/* * 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 #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 "../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 id = IDX.RDB$INDEX_ID - 1; IDX_statistics(tdbb, relation, id, selectivity); DFW_update_index(name.c_str(), id, 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(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) { // 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 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(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)) 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)); }