8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-02-02 10:00:38 +01:00

Functions support

This commit is contained in:
AlexPeshkoff 2024-07-12 18:38:29 +03:00
parent 38ffaf4a1f
commit bfe98c33e5
6 changed files with 95 additions and 49 deletions

View File

@ -1791,7 +1791,12 @@ void CreateAlterFunctionNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsql
compile(tdbb, dsqlScratch);
executeAlter(tdbb, dsqlScratch, transaction, true, false); // second pass
{ // scope
// avoid modify routine dfw during second pass on CREATE
AutoSetRestoreFlag<ULONG> noDfw(&tdbb->tdbb_flags, altered ? 0 : TDBB_dont_post_dfw, true);
executeAlter(tdbb, dsqlScratch, transaction, true, false); // second pass
}
if (package.isEmpty())
{
@ -1889,6 +1894,9 @@ void CreateAlterFunctionNode::executeCreate(thread_db* tdbb, DsqlCompilerScratch
if (package.isEmpty())
storePrivileges(tdbb, transaction, name, obj_udf, EXEC_PRIVILEGES);
// avoid modify routine dfw when execute CREATE
AutoSetRestoreFlag<ULONG> noDfw(&tdbb->tdbb_flags, TDBB_dont_post_dfw, true);
executeAlter(tdbb, dsqlScratch, transaction, false, false);
}
@ -1899,6 +1907,7 @@ bool CreateAlterFunctionNode::executeAlter(thread_db* tdbb, DsqlCompilerScratch*
bool modified = false;
unsigned returnPos = 0;
MetaId id;
AutoCacheRequest requestHandle(tdbb, drq_m_funcs2, DYN_REQUESTS);
@ -1913,10 +1922,17 @@ bool CreateAlterFunctionNode::executeAlter(thread_db* tdbb, DsqlCompilerScratch*
Arg::Gds(isc_dyn_cannot_mod_sysfunc) << MetaName(FUN.RDB$FUNCTION_NAME));
}
if (!secondPass && runTriggers && package.isEmpty())
id = FUN.RDB$FUNCTION_ID;
if (!secondPass && runTriggers)
{
executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE,
DDL_TRIGGER_ALTER_FUNCTION, name, NULL);
if (package.isEmpty())
{
executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE,
DDL_TRIGGER_ALTER_FUNCTION, name, NULL);
}
MetadataCache::oldVersion(tdbb, obj_udf, id);
}
MODIFY FUN
@ -2104,6 +2120,9 @@ bool CreateAlterFunctionNode::executeAlter(thread_db* tdbb, DsqlCompilerScratch*
}
}
if (secondPass && modified)
MetadataCache::newVersion(tdbb, obj_udf, id);
return modified;
}
@ -2442,6 +2461,7 @@ void AlterExternalFunctionNode::execute(thread_db* tdbb, DsqlCompilerScratch* ds
AutoCacheRequest request(tdbb, drq_m_fun, DYN_REQUESTS);
bool found = false;
MetaId id;
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
FUN IN RDB$FUNCTIONS
@ -2456,6 +2476,8 @@ void AlterExternalFunctionNode::execute(thread_db* tdbb, DsqlCompilerScratch* ds
if (!FUN.RDB$ENGINE_NAME.NULL || !FUN.RDB$FUNCTION_BLR.NULL)
status_exception::raise(Arg::Gds(isc_dyn_newfc_oldsyntax) << name);
MetadataCache::oldVersion(tdbb, obj_udf, (id = FUN.RDB$FUNCTION_ID));
MODIFY FUN
if (clauses.name.hasData())
{
@ -2480,6 +2502,7 @@ void AlterExternalFunctionNode::execute(thread_db* tdbb, DsqlCompilerScratch* ds
if (found)
{
MetadataCache::newVersion(tdbb, obj_udf, id);
executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_ALTER_FUNCTION,
name, NULL);
}
@ -2566,6 +2589,10 @@ void DropFunctionNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch
// run all statements under savepoint control
AutoSavePoint savePoint(tdbb, transaction);
bool found = false;
MetaId id;
//MetadataCache::oldVersion(tdbb, obj_udf, id); missing ID in the node
MetadataCache::lookup_function(tdbb, QualifiedName(name, ""), CacheFlag::AUTOCREATE);
dropArguments(tdbb, transaction, name, package);
@ -2589,12 +2616,12 @@ void DropFunctionNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch
name, NULL);
}
id = FUN.RDB$FUNCTION_ID;
ERASE FUN;
found = true;
if (!FUN.RDB$SECURITY_CLASS.NULL)
deleteSecurityClass(tdbb, transaction, FUN.RDB$SECURITY_CLASS);
found = true;
}
END_FOR
@ -2617,10 +2644,15 @@ void DropFunctionNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch
END_FOR
}
if (found && package.isEmpty())
if (found)
{
executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_DROP_FUNCTION,
name, NULL);
MetadataCache::erase(tdbb, obj_udf, id);
if (package.isEmpty())
{
executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_DROP_FUNCTION,
name, NULL);
}
}
savePoint.release(); // everything is ok

View File

@ -64,7 +64,7 @@ Function* Function::lookup(thread_db* tdbb, MetaId id, ObjectBase::Flag flags)
{
Database* const dbb = tdbb->getDatabase();
Function* function = dbb->dbb_mdc->getFunction(tdbb, id, flags | CacheFlag::AUTOCREATE);
Function* function = dbb->dbb_mdc->getFunction(tdbb, id, flags);
return function;
}
@ -77,27 +77,7 @@ Function* Function::create(thread_db* tdbb, MemoryPool& pool, Cached::Function*
Function* Function::lookup(thread_db* tdbb, const QualifiedName& name, ObjectBase::Flag flags)
{
Attachment* const attachment = tdbb->getAttachment();
Database* const dbb = tdbb->getDatabase();
// See if we already know the function by name
Function* function = dbb->dbb_mdc->lookup_function(tdbb, name);
if (function)
return function;
// We need to look up the function in RDB$FUNCTIONS
AutoCacheRequest request(tdbb, irq_l_fun_name, IRQ_REQUESTS);
FOR(REQUEST_HANDLE request)
X IN RDB$FUNCTIONS
WITH X.RDB$FUNCTION_NAME EQ name.identifier.c_str() AND
X.RDB$PACKAGE_NAME EQUIV NULLIF(name.package.c_str(), '')
{
if (!function)
function = dbb->dbb_mdc->getFunction(tdbb, X.RDB$FUNCTION_ID, flags);
}
END_FOR
return function;
return MetadataCache::lookup_function(tdbb, name, flags);
}
Lock* Function::makeLock(thread_db* tdbb, MemoryPool& p)

View File

@ -911,7 +911,7 @@ ProcedureSourceNode* ProcedureSourceNode::parse(thread_db* tdbb, CompilerScratch
case blr_pid:
case blr_pid2:
{
const SSHORT pid = csb->csb_blr_reader.getWord();
const SSHORT procId = csb->csb_blr_reader.getWord();
if (blrOp == blr_pid2)
{
@ -919,8 +919,8 @@ ProcedureSourceNode* ProcedureSourceNode::parse(thread_db* tdbb, CompilerScratch
csb->csb_blr_reader.getString(*aliasString);
}
proc = MetadataCache::lookupProcedure(tdbb, pid, CacheFlag::AUTOCREATE);
name.identifier.printf("id %d", pid);
proc = MetadataCache::lookupProcedure(tdbb, procId, CacheFlag::AUTOCREATE);
name.identifier.printf("id %d", procId);
break;
}

View File

@ -1095,8 +1095,8 @@ namespace
X.RDB$PACKAGE_NAME EQUIV NULLIF(work->dfw_package.c_str(), '')
{
blobId = X.RDB$FUNCTION_BLR;
routine = Function::lookup(tdbb,
QualifiedName(work->dfw_name, work->dfw_package), !compile);
routine = Function::lookup(tdbb, QualifiedName(work->dfw_name, work->dfw_package),
(compile ? 0 : CacheFlag::NOSCAN) | CacheFlag::AUTOCREATE);
}
END_FOR
@ -1254,7 +1254,6 @@ static const deferred_task task_table[] =
{ dfw_modify_procedure, ProcedureManager::modifyRoutine },
{ dfw_modify_function, FunctionManager::modifyRoutine },
{ dfw_delete_prm, delete_parameter },
{ dfw_create_collation, create_collation },
{ dfw_delete_collation, delete_collation },
/*

View File

@ -2591,18 +2591,18 @@ jrd_prc* MetadataCache::lookup_procedure(thread_db* tdbb, const QualifiedName& n
Attachment* attachment = tdbb->getAttachment();
MetadataCache* mdc = attachment->att_database->dbb_mdc;
// See if we already know the procedure by name
for (auto procedure : mdc->mdc_procedures)
{
if (procedure && procedure->getName() == name)
{
return procedure->getObject(tdbb, CacheFlag::AUTOCREATE);
}
}
auto* proc = mdc->mdc_procedures.lookup(tdbb,
[name] (Cached::Procedure* proc) { return proc->getName() == name; });
if (proc)
return proc->getObject(tdbb, flags);
if (!(flags & CacheFlag::AUTOCREATE))
return nullptr;
// We need to look up the procedure name in RDB$PROCEDURES
jrd_prc* procedure = nullptr;
@ -2614,11 +2614,11 @@ jrd_prc* MetadataCache::lookup_procedure(thread_db* tdbb, const QualifiedName& n
WITH P.RDB$PROCEDURE_NAME EQ name.identifier.c_str() AND
P.RDB$PACKAGE_NAME EQUIV NULLIF(name.package.c_str(), '')
{
fb_assert(!procedure);
procedure = mdc->mdc_procedures.getObject(tdbb, P.RDB$PROCEDURE_ID, flags);
}
END_FOR
return procedure;
}
@ -2643,7 +2643,7 @@ jrd_prc* MetadataCache::lookup_procedure_id(thread_db* tdbb, MetaId id, ObjectBa
}
Function* MetadataCache::lookup_function(thread_db* tdbb, const QualifiedName& name)
Function* MetadataCache::lookup_function(thread_db* tdbb, const QualifiedName& name, ObjectBase::Flag flags)
{
/************************************************
*
@ -2656,7 +2656,38 @@ Function* MetadataCache::lookup_function(thread_db* tdbb, const QualifiedName& n
* ASCIZ name.
*
**************************************/
return Function::lookup(tdbb, name, CacheFlag::AUTOCREATE);
SET_TDBB(tdbb);
Attachment* attachment = tdbb->getAttachment();
MetadataCache* mdc = attachment->att_database->dbb_mdc;
// See if we already know the function by name
auto* func = mdc->mdc_functions.lookup(tdbb,
[name] (Cached::Function* func) { return func->getName() == name; });
if (func)
return func->getObject(tdbb, flags);
if (!(flags & CacheFlag::AUTOCREATE))
return nullptr;
// We need to look up the function in RDB$FUNCTIONS
Function* function = nullptr;
AutoCacheRequest request(tdbb, irq_l_fun_name, IRQ_REQUESTS);
FOR(REQUEST_HANDLE request)
X IN RDB$FUNCTIONS
WITH X.RDB$FUNCTION_NAME EQ name.identifier.c_str() AND
X.RDB$PACKAGE_NAME EQUIV NULLIF(name.package.c_str(), '')
{
fb_assert(!function);
function = mdc->getFunction(tdbb, X.RDB$FUNCTION_ID, flags);
}
END_FOR
return function;
}
@ -5217,7 +5248,7 @@ Cached::Function* MetadataCache::lookupFunction(thread_db* tdbb, const Qualified
MetadataCache* mdc = tdbb->getDatabase()->dbb_mdc;
// See if we already know the relation by name
// See if we already know the function by name
auto* rc = mdc->mdc_functions.lookup(tdbb, [name](RoutinePermanent* func) { return func->name == name; });
if (rc || !(flags & CacheFlag::AUTOCREATE))
@ -5353,6 +5384,10 @@ void MetadataCache::changeVersion(thread_db* tdbb, Changer cmd, ObjectType objTy
changeVers(tdbb, cmd, mdc->mdc_charsets, id);
break;
case obj_udf:
changeVers(tdbb, cmd, mdc->mdc_functions, id);
break;
/*
case :
changeVers(tdbb, cmd, mdc->, id);

View File

@ -288,7 +288,7 @@ public:
void load_ddl_triggers(thread_db* tdbb, bool force = false);
static jrd_prc* lookup_procedure(thread_db* tdbb, const QualifiedName& name, ObjectBase::Flag flags);
static jrd_prc* lookup_procedure_id(thread_db* tdbb, MetaId id, ObjectBase::Flag flags);
static Function* lookup_function(thread_db* tdbb, const QualifiedName& name);
static Function* lookup_function(thread_db* tdbb, const QualifiedName& name, ObjectBase::Flag flags);
static Function* lookup_function(thread_db* tdbb, MetaId id, ObjectBase::Flag flags);
static Cached::Procedure* lookupProcedure(thread_db* tdbb, const QualifiedName& name, ObjectBase::Flag flags);
static Cached::Procedure* lookupProcedure(thread_db* tdbb, MetaId id, ObjectBase::Flag flags);