void setCharSet(thread_db* tdbb, EngineAttachmentInfo* attInfo, T* obj) { attachment->att_charset = attInfo->adminCharSet; if (!obj) return; Utf8 charSetName[MAX_SQL_IDENTIFIER_SIZE]; { // scope Attachment::Checkout attCout(attachment, FB_FUNCTION); LocalStatus status; obj->getCharSet(&status, attInfo->context, charSetName, MAX_SQL_IDENTIFIER_LEN); status.check(); charSetName[MAX_SQL_IDENTIFIER_LEN] = '\0'; } USHORT charSetId; if (!MET_get_char_coll_subtype(tdbb, &charSetId, reinterpret_cast<const UCHAR*>(charSetName), static_cast<USHORT>(strlen(charSetName)))) { status_exception::raise(Arg::Gds(isc_charset_not_found) << Arg::Str(charSetName)); } attachment->att_charset = charSetId; }
void ExtEngineManager::Trigger::execute(thread_db* tdbb, ExternalTrigger::Action action, record_param* oldRpb, record_param* newRpb) const { EngineAttachmentInfo* attInfo = extManager->getEngineAttachment(tdbb, engine); ContextManager<ExternalTrigger> ctxManager(tdbb, attInfo, trigger, CallerName(obj_trigger, trg->name)); // ASF: Using Array instead of HalfStaticArray to not need to do alignment hacks here. Array<UCHAR> oldMsg; Array<UCHAR> newMsg; if (oldRpb) setValues(tdbb, oldMsg, oldRpb); if (newRpb) setValues(tdbb, newMsg, newRpb); { // scope Attachment::Checkout attCout(tdbb->getAttachment(), FB_FUNCTION); LocalStatus status; trigger->execute(&status, attInfo->context, action, (oldMsg.hasData() ? oldMsg.begin() : NULL), (newMsg.hasData() ? newMsg.begin() : NULL)); status.check(); } if (newRpb) { // Move data back from the message to the record. Record* record = newRpb->rpb_record; UCHAR* p = newMsg.begin(); for (unsigned i = 0; i < format->fmt_count / 2u; ++i) { USHORT fieldPos = fieldsPos[i]; dsc target; bool readonly = !EVL_field(newRpb->rpb_relation, record, fieldPos, &target) && target.dsc_address && !(target.dsc_flags & DSC_null); if (!readonly) { SSHORT* nullSource = (SSHORT*) (p + (IPTR) format->fmt_desc[i * 2 + 1].dsc_address); if (*nullSource == 0) { dsc source = format->fmt_desc[i * 2]; source.dsc_address += (IPTR) p; MOV_move(tdbb, &source, &target); record->clearNull(fieldPos); } else record->setNull(fieldPos); } } } }
void ExtEngineManager::Function::execute(thread_db* tdbb, UCHAR* inMsg, UCHAR* outMsg) const { EngineAttachmentInfo* attInfo = extManager->getEngineAttachment(tdbb, engine); ContextManager<ExternalFunction> ctxManager(tdbb, attInfo, function, (udf->getName().package.isEmpty() ? CallerName(obj_udf, udf->getName().identifier) : CallerName(obj_package_header, udf->getName().package))); Attachment::Checkout attCout(tdbb->getAttachment(), FB_FUNCTION); LocalStatus status; function->execute(&status, attInfo->context, inMsg, outMsg); status.check(); }
ExtEngineManager::Trigger::Trigger(thread_db* tdbb, MemoryPool& pool, ExtEngineManager* aExtManager, ExternalEngine* aEngine, RoutineMetadata* aMetadata, ExternalTrigger* aTrigger, const Jrd::Trigger* aTrg) : extManager(aExtManager), engine(aEngine), metadata(aMetadata), trigger(aTrigger), trg(aTrg), fieldsPos(pool), database(tdbb->getDatabase()) { dsc shortDesc; shortDesc.makeShort(0); jrd_rel* relation = trg->relation; if (relation) { GenericMap<Left<MetaName, USHORT> > fieldsMap; for (FB_SIZE_T i = 0; i < relation->rel_fields->count(); ++i) { jrd_fld* field = (*relation->rel_fields)[i]; if (field) fieldsMap.put(field->fld_name, (USHORT) i); } format = Routine::createFormat(pool, metadata->triggerFields, false); LocalStatus status; for (unsigned i = 0; i < format->fmt_count / 2u; ++i) { const char* fieldName = metadata->triggerFields->getField(&status, i); status.check(); USHORT pos; if (!fieldsMap.get(fieldName, pos)) fb_assert(false); else fieldsPos.add(pos); } } }
ExtEngineManager::ResultSet::ResultSet(thread_db* tdbb, UCHAR* inMsg, UCHAR* outMsg, const ExtEngineManager::Procedure* aProcedure) : procedure(aProcedure), attachment(tdbb->getAttachment()), firstFetch(true) { attInfo = procedure->extManager->getEngineAttachment(tdbb, procedure->engine); ContextManager<ExternalProcedure> ctxManager(tdbb, attInfo, procedure->procedure, (procedure->prc->getName().package.isEmpty() ? CallerName(obj_procedure, procedure->prc->getName().identifier) : CallerName(obj_package_header, procedure->prc->getName().package))); charSet = attachment->att_charset; Attachment::Checkout attCout(attachment, FB_FUNCTION); LocalStatus status; resultSet = procedure->procedure->open(&status, attInfo->context, inMsg, outMsg); status.check(); }
bool ExtEngineManager::ResultSet::fetch(thread_db* tdbb) { bool wasFirstFetch = firstFetch; firstFetch = false; if (!resultSet) return wasFirstFetch; ContextManager<ExternalProcedure> ctxManager(tdbb, attInfo, charSet, (procedure->prc->getName().package.isEmpty() ? CallerName(obj_procedure, procedure->prc->getName().identifier) : CallerName(obj_package_header, procedure->prc->getName().package))); fb_assert(attachment == tdbb->getAttachment()); Attachment::Checkout attCout(attachment, FB_FUNCTION); LocalStatus status; bool ret = resultSet->fetch(&status); status.check(); return ret; }
void ExtEngineManager::setupAdminCharSet(thread_db* tdbb, ExternalEngine* engine, EngineAttachmentInfo* attInfo) { ContextManager<ExternalFunction> ctxManager(tdbb, attInfo, CS_UTF8); Utf8 charSetName[MAX_SQL_IDENTIFIER_SIZE] = "NONE"; LocalStatus status; engine->open(&status, attInfo->context, charSetName, MAX_SQL_IDENTIFIER_LEN); status.check(); charSetName[MAX_SQL_IDENTIFIER_LEN] = '\0'; if (!MET_get_char_coll_subtype(tdbb, &attInfo->adminCharSet, reinterpret_cast<const UCHAR*>(charSetName), static_cast<USHORT>(strlen(charSetName)))) { status_exception::raise( Arg::Gds(isc_charset_not_found) << Arg::Str(charSetName)); } }
void ExtEngineManager::makeTrigger(thread_db* tdbb, CompilerScratch* csb, Jrd::Trigger* trg, const MetaName& engine, const string& entryPoint, const string& body, ExternalTrigger::Type type) { string entryPointTrimmed = entryPoint; entryPointTrimmed.trim(); EngineAttachmentInfo* attInfo = getEngineAttachment(tdbb, engine); ContextManager<ExternalTrigger> ctxManager(tdbb, attInfo, attInfo->adminCharSet, CallerName(obj_trigger, trg->name)); ///MemoryPool& pool = *tdbb->getDefaultPool(); MemoryPool& pool = *getDefaultMemoryPool(); AutoPtr<RoutineMetadata> metadata(FB_NEW(pool) RoutineMetadata(pool)); metadata->name = trg->name; metadata->entryPoint = entryPointTrimmed; metadata->body = body; metadata->triggerType = type; jrd_rel* relation = trg->relation; if (relation) { metadata->triggerTable = relation->rel_name; MsgMetadata* fieldsMsg = new MsgMetadata; metadata->triggerFields = fieldsMsg; Format* relFormat = relation->rel_current_format; for (FB_SIZE_T i = 0; i < relation->rel_fields->count(); ++i) { jrd_fld* field = (*relation->rel_fields)[i]; if (field) fieldsMsg->addItem(field->fld_name, !field->fld_not_null, relFormat->fmt_desc[i]); } } LocalStatus status; RefPtr<IMetadataBuilder> fieldsBuilder(REF_NO_INCR, relation ? metadata->triggerFields->getBuilder(&status) : NULL); if (relation) { status.check(); } ExternalTrigger* externalTrigger; { // scope Attachment::Checkout attCout(tdbb->getAttachment(), FB_FUNCTION); LocalStatus status; externalTrigger = attInfo->engine->makeTrigger(&status, attInfo->context, metadata, fieldsBuilder); status.check(); if (!externalTrigger) { status_exception::raise( Arg::Gds(isc_eem_trig_not_returned) << trg->name << engine); } if (relation) { metadata->triggerFields = fieldsBuilder->getMetadata(&status); status.check(); } } try { trg->extTrigger = FB_NEW(getPool()) Trigger(tdbb, pool, this, attInfo->engine, metadata.release(), externalTrigger, trg); CompoundStmtNode* mainNode = FB_NEW(getPool()) CompoundStmtNode(getPool()); ExtTriggerNode* extTriggerNode = FB_NEW(getPool()) ExtTriggerNode(getPool(), trg->extTrigger); mainNode->statements.add(extTriggerNode); PAR_preparsed_node(tdbb, trg->relation, mainNode, NULL, &csb, &trg->statement, true, 0); } catch (...) { Attachment::Checkout attCout(tdbb->getAttachment(), FB_FUNCTION); externalTrigger->dispose(); throw; } }
void ExtEngineManager::makeProcedure(thread_db* tdbb, CompilerScratch* csb, jrd_prc* prc, const MetaName& engine, const string& entryPoint, const string& body) { string entryPointTrimmed = entryPoint; entryPointTrimmed.trim(); EngineAttachmentInfo* attInfo = getEngineAttachment(tdbb, engine); ContextManager<ExternalProcedure> ctxManager(tdbb, attInfo, attInfo->adminCharSet, (prc->getName().package.isEmpty() ? CallerName(obj_procedure, prc->getName().identifier) : CallerName(obj_package_header, prc->getName().package))); ///MemoryPool& pool = *tdbb->getDefaultPool(); MemoryPool& pool = *getDefaultMemoryPool(); AutoPtr<RoutineMetadata> metadata(FB_NEW(pool) RoutineMetadata(pool)); metadata->package = prc->getName().package; metadata->name = prc->getName().identifier; metadata->entryPoint = entryPointTrimmed; metadata->body = body; metadata->inputParameters = Routine::createMetadata(prc->getInputFields()); metadata->outputParameters = Routine::createMetadata(prc->getOutputFields()); LocalStatus status; RefPtr<IMetadataBuilder> inBuilder(REF_NO_INCR, metadata->inputParameters->getBuilder(&status)); status.check(); RefPtr<IMetadataBuilder> outBuilder(REF_NO_INCR, metadata->outputParameters->getBuilder(&status)); status.check(); ExternalProcedure* externalProcedure; { // scope Attachment::Checkout attCout(tdbb->getAttachment(), FB_FUNCTION); externalProcedure = attInfo->engine->makeProcedure(&status, attInfo->context, metadata, inBuilder, outBuilder); status.check(); if (!externalProcedure) { status_exception::raise( Arg::Gds(isc_eem_proc_not_returned) << prc->getName().toString() << engine); } metadata->inputParameters = inBuilder->getMetadata(&status); status.check(); metadata->outputParameters = outBuilder->getMetadata(&status); status.check(); } prc->setInputFormat(Routine::createFormat(pool, metadata->inputParameters, false)); prc->setOutputFormat(Routine::createFormat(pool, metadata->outputParameters, true)); try { prc->setExternal(FB_NEW(getPool()) Procedure(tdbb, this, attInfo->engine, metadata.release(), externalProcedure, prc)); CompoundStmtNode* mainNode = FB_NEW(getPool()) CompoundStmtNode(getPool()); ExtMessageNode* inMessageNode = prc->getInputFields().hasData() ? FB_NEW(getPool()) ExtMessageNode(tdbb, getPool(), csb, 0, prc->getInputFields(), prc->getInputFormat()) : NULL; if (inMessageNode) mainNode->statements.add(inMessageNode); ExtMessageNode* outMessageNode = FB_NEW(getPool()) ExtMessageNode(tdbb, getPool(), csb, 1, prc->getOutputFields(), prc->getOutputFormat()); mainNode->statements.add(outMessageNode); ExtInitOutputNode* initOutputNode = FB_NEW(getPool()) ExtInitOutputNode( tdbb, getPool(), csb, outMessageNode); mainNode->statements.add(initOutputNode); ReceiveNode* receiveNode = inMessageNode ? FB_NEW(getPool()) ReceiveNode(getPool()) : NULL; if (inMessageNode) { receiveNode->message = inMessageNode; receiveNode->statement = FB_NEW(getPool()) ExtValidationNode( getPool(), inMessageNode, true, true); mainNode->statements.add(receiveNode); } ExtProcedureNode* extProcedureNode = FB_NEW(getPool()) ExtProcedureNode(getPool(), receiveNode, prc->getExternal()); mainNode->statements.add(extProcedureNode); extProcedureNode->message = outMessageNode; extProcedureNode->statement = FB_NEW(getPool()) ExtValidationNode( getPool(), outMessageNode, true, false); JrdStatement* statement = prc->getStatement(); PAR_preparsed_node(tdbb, NULL, mainNode, NULL, &csb, &statement, false, 0); prc->setStatement(statement); } catch (...) { Attachment::Checkout attCout(tdbb->getAttachment(), FB_FUNCTION); externalProcedure->dispose(); throw; } }
void ExtEngineManager::makeProcedure(thread_db* tdbb, jrd_prc* prc, const MetaName& engine, const string& entryPoint, const string& body) { string entryPointTrimmed = entryPoint; entryPointTrimmed.trim(); EngineAttachmentInfo* attInfo = getEngineAttachment(tdbb, engine); ContextManager<ExternalProcedure> ctxManager(tdbb, attInfo, attInfo->adminCharSet, (prc->getName().package.isEmpty() ? CallerName(obj_procedure, prc->getName().identifier) : CallerName(obj_package_header, prc->getName().package))); ///MemoryPool& pool = *tdbb->getDefaultPool(); MemoryPool& pool = *getDefaultMemoryPool(); AutoPtr<RoutineMetadata> metadata(FB_NEW(pool) RoutineMetadata(pool)); metadata->package = prc->getName().package; metadata->name = prc->getName().identifier; metadata->entryPoint = entryPointTrimmed; metadata->body = body; metadata->inputParameters = Routine::createMetadata(prc->getInputFields()); metadata->outputParameters = Routine::createMetadata(prc->getOutputFields()); LocalStatus status; RefPtr<IMetadataBuilder> inBuilder(metadata->inputParameters->getBuilder(&status)); status.check(); inBuilder->release(); RefPtr<IMetadataBuilder> outBuilder(metadata->outputParameters->getBuilder(&status)); status.check(); outBuilder->release(); ExternalProcedure* externalProcedure; { // scope Attachment::Checkout attCout(tdbb->getAttachment(), FB_FUNCTION); externalProcedure = attInfo->engine->makeProcedure(&status, attInfo->context, metadata, inBuilder, outBuilder); status.check(); if (!externalProcedure) { status_exception::raise( Arg::Gds(isc_eem_proc_not_returned) << prc->getName().toString() << engine); } metadata->inputParameters = inBuilder->getMetadata(&status); status.check(); metadata->outputParameters = outBuilder->getMetadata(&status); status.check(); } try { prc->setInputFormat(Routine::createFormat(pool, metadata->inputParameters, false)); prc->setOutputFormat(Routine::createFormat(pool, metadata->outputParameters, false)); prc->setExternal(FB_NEW(getPool()) Procedure(tdbb, this, attInfo->engine, metadata.release(), externalProcedure, prc)); } catch (...) { Attachment::Checkout attCout(tdbb->getAttachment(), FB_FUNCTION); externalProcedure->dispose(); throw; } }