const StmtNode* EXE_looper(thread_db* tdbb, jrd_req* request, const StmtNode* node) { /************************************** * * E X E _ l o o p e r * ************************************** * * Functional description * Cycle thru request execution tree. Return next node for * execution on stall or request complete. * **************************************/ if (!request->req_transaction) ERR_post(Arg::Gds(isc_req_no_trans)); SET_TDBB(tdbb); Jrd::Attachment* attachment = tdbb->getAttachment(); jrd_tra* sysTransaction = attachment->getSysTransaction(); Database* dbb = tdbb->getDatabase(); if (!node || node->kind != DmlNode::KIND_STATEMENT) BUGCHECK(147); // Save the old pool and request to restore on exit StmtNode::ExeState exeState(tdbb, request, request->req_transaction); Jrd::ContextPoolHolder context(tdbb, request->req_pool); fb_assert(request->req_caller == NULL); request->req_caller = exeState.oldRequest; const SLONG save_point_number = (request->req_transaction->tra_save_point) ? request->req_transaction->tra_save_point->sav_number : 0; tdbb->tdbb_flags &= ~(TDBB_stack_trace_done | TDBB_sys_error); // Execute stuff until we drop const JrdStatement* statement = request->getStatement(); while (node && !(request->req_flags & req_stall)) { try { if (request->req_operation == jrd_req::req_evaluate) { if (--tdbb->tdbb_quantum < 0) JRD_reschedule(tdbb, 0, true); if (node->hasLineColumn) { request->req_src_line = node->line; request->req_src_column = node->column; } } node = node->execute(tdbb, request, &exeState); if (exeState.exit) return node; } // try catch (const Firebird::Exception& ex) { ex.stuffException(tdbb->tdbb_status_vector); request->adjustCallerStats(); // Ensure the transaction hasn't disappeared in the meantime fb_assert(request->req_transaction); // Skip this handling for errors coming from the nested looper calls, // as they're already handled properly. The only need is to undo // our own savepoints. if (exeState.catchDisabled) { if (request->req_transaction != sysTransaction) { while (request->req_transaction->tra_save_point && request->req_transaction->tra_save_point->sav_number >= save_point_number) { ++request->req_transaction->tra_save_point->sav_verb_count; VIO_verb_cleanup(tdbb, request->req_transaction); } } ERR_punt(); } // If the database is already bug-checked, then get out if (dbb->dbb_flags & DBB_bugcheck) Firebird::status_exception::raise(tdbb->tdbb_status_vector); // Since an error happened, the current savepoint needs to be undone if (request->req_transaction != sysTransaction && request->req_transaction->tra_save_point) { ++request->req_transaction->tra_save_point->sav_verb_count; VIO_verb_cleanup(tdbb, request->req_transaction); } exeState.errorPending = true; exeState.catchDisabled = true; request->req_operation = jrd_req::req_unwind; request->req_label = 0; if (!(tdbb->tdbb_flags & TDBB_stack_trace_done) && !(tdbb->tdbb_flags & TDBB_sys_error)) { stuff_stack_trace(request); tdbb->tdbb_flags |= TDBB_stack_trace_done; } } } // while() request->adjustCallerStats(); fb_assert(request->req_auto_trans.getCount() == 0); // If there is no node, assume we have finished processing the // request unless we are in the middle of processing an // asynchronous message if (!node) { // Close active cursors for (const Cursor* const* ptr = request->req_cursors.begin(); ptr < request->req_cursors.end(); ++ptr) { if (*ptr) (*ptr)->close(tdbb); } request->req_flags &= ~(req_active | req_reserved); request->req_timestamp.invalidate(); release_blobs(tdbb, request); } request->req_next = node; fb_assert(request->req_caller == exeState.oldRequest); request->req_caller = NULL; // Ensure the transaction hasn't disappeared in the meantime fb_assert(request->req_transaction); // In the case of a pending error condition (one which did not // result in a exception to the top of looper), we need to // delete the last savepoint if (exeState.errorPending) { if (request->req_transaction != sysTransaction) { while (request->req_transaction->tra_save_point && request->req_transaction->tra_save_point->sav_number >= save_point_number) { ++request->req_transaction->tra_save_point->sav_verb_count; VIO_verb_cleanup(tdbb, request->req_transaction); } } ERR_punt(); } // if the request was aborted, assume that we have already // longjmp'ed to the top of looper, and therefore that the // last savepoint has already been deleted if (request->req_flags & req_abort) { ERR_post(Arg::Gds(isc_req_sync)); } return node; }
RelationPages* jrd_rel::getPagesInternal(thread_db* tdbb, TraNumber tran, bool allocPages) { if (tdbb->tdbb_flags & TDBB_use_db_page_space) return &rel_pages_base; Jrd::Attachment* attachment = tdbb->getAttachment(); Database* dbb = tdbb->getDatabase(); ULONG inst_id; // Vlad asked for this compile-time check to make sure we can contain a txn number here typedef int RangeCheck[sizeof(inst_id) >= sizeof(TraNumber)]; if (rel_flags & REL_temp_tran) { if (tran > 0 && tran != MAX_TRA_NUMBER) //if (tran > 0) inst_id = tran; else if (tdbb->tdbb_temp_traid) inst_id = tdbb->tdbb_temp_traid; else if (tdbb->getTransaction()) inst_id = tdbb->getTransaction()->tra_number; else // called without transaction, maybe from OPT or CMP ? return &rel_pages_base; } else inst_id = PAG_attachment_id(tdbb); if (!rel_pages_inst) rel_pages_inst = FB_NEW(*rel_pool) RelationPagesInstances(*rel_pool); FB_SIZE_T pos; if (!rel_pages_inst->find(inst_id, pos)) { if (!allocPages) return 0; RelationPages* newPages = rel_pages_free; if (!newPages) { const size_t BULK_ALLOC = 8; RelationPages* allocatedPages = newPages = FB_NEW(*rel_pool) RelationPages[BULK_ALLOC]; rel_pages_free = ++allocatedPages; for (size_t i = 1; i < BULK_ALLOC - 1; i++, allocatedPages++) allocatedPages->rel_next_free = allocatedPages + 1; } else { rel_pages_free = newPages->rel_next_free; newPages->rel_next_free = 0; } fb_assert(newPages->useCount == 0); newPages->addRef(); newPages->rel_instance_id = inst_id; newPages->rel_pg_space_id = dbb->dbb_page_manager.getTempPageSpaceID(tdbb); rel_pages_inst->add(newPages); // create primary pointer page and index root page DPM_create_relation_pages(tdbb, this, newPages); #ifdef VIO_DEBUG VIO_trace(DEBUG_WRITES, "jrd_rel::getPages inst %"ULONGFORMAT", ppp %"SLONGFORMAT", irp %"SLONGFORMAT", addr 0x%x\n", newPages->rel_instance_id, newPages->rel_pages ? (*newPages->rel_pages)[0] : 0, newPages->rel_index_root, newPages); #endif // create indexes MemoryPool* pool = tdbb->getDefaultPool(); const bool poolCreated = !pool; if (poolCreated) pool = dbb->createPool(); Jrd::ContextPoolHolder context(tdbb, pool); jrd_tra* idxTran = tdbb->getTransaction(); if (!idxTran) idxTran = attachment->getSysTransaction(); IndexDescAlloc* indices = NULL; // read indices from "base" index root page const USHORT idx_count = BTR_all(tdbb, this, &indices, &rel_pages_base); const index_desc* const end = indices->items + idx_count; for (index_desc* idx = indices->items; idx < end; idx++) { Firebird::MetaName idx_name; MET_lookup_index(tdbb, idx_name, this->rel_name, idx->idx_id + 1); idx->idx_root = 0; SelectivityList selectivity(*pool); IDX_create_index(tdbb, this, idx, idx_name.c_str(), NULL, idxTran, selectivity); #ifdef VIO_DEBUG VIO_trace(DEBUG_WRITES, "jrd_rel::getPages inst %"ULONGFORMAT", irp %"SLONGFORMAT", idx %u, idx_root %"SLONGFORMAT", addr 0x%x\n", newPages->rel_instance_id, newPages->rel_index_root, idx->idx_id, idx->idx_root, newPages); #endif } if (poolCreated) dbb->deletePool(pool); delete indices; return newPages; } RelationPages* pages = (*rel_pages_inst)[pos]; fb_assert(pages->rel_instance_id == inst_id); return pages; }