8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-23 22:03:03 +01:00

Support for PSQL functions (other JRD changes). Still work in progress.

This commit is contained in:
dimitr 2009-12-21 17:43:01 +00:00
parent 34d21655d1
commit debe65bcfb
22 changed files with 438 additions and 401 deletions

View File

@ -455,8 +455,7 @@ public:
vcl* dbb_pc_transactions; // active precommitted transactions vcl* dbb_pc_transactions; // active precommitted transactions
BackupManager* dbb_backup_manager; // physical backup manager BackupManager* dbb_backup_manager; // physical backup manager
Firebird::TimeStamp dbb_creation_date; // creation date Firebird::TimeStamp dbb_creation_date; // creation date
Firebird::GenericMap<Firebird::Pair<Firebird::Left< Firebird::Array<Function*> dbb_functions; // User defined functions
Firebird::QualifiedName, UserFunction*> > > dbb_functions; // User defined functions
Firebird::GenericMap<Firebird::Pair<Firebird::Left< Firebird::GenericMap<Firebird::Pair<Firebird::Left<
Firebird::MetaName, USHORT> > > dbb_charset_ids; // Character set ids Firebird::MetaName, USHORT> > > dbb_charset_ids; // Character set ids

View File

@ -49,6 +49,7 @@
#include "../jrd/Relation.h" #include "../jrd/Relation.h"
#include "../jrd/RecordBuffer.h" #include "../jrd/RecordBuffer.h"
#include "../jrd/DatabaseSnapshot.h" #include "../jrd/DatabaseSnapshot.h"
#include "../jrd/Function.h"
#include "../common/utils_proto.h" #include "../common/utils_proto.h"
@ -1133,6 +1134,14 @@ void DatabaseSnapshot::putCall(const jrd_req* request, Writer& writer, int stat_
record.storeString(f_mon_call_name, request->req_procedure->prc_name.identifier); record.storeString(f_mon_call_name, request->req_procedure->prc_name.identifier);
record.storeInteger(f_mon_call_type, obj_procedure); record.storeInteger(f_mon_call_type, obj_procedure);
} }
else if (request->req_function)
{
if (request->req_function->fun_name.qualifier.hasData())
record.storeString(f_mon_call_pkg_name, request->req_function->fun_name.qualifier);
record.storeString(f_mon_call_name, request->req_function->fun_name.identifier);
record.storeInteger(f_mon_call_type, obj_udf);
}
else if (!request->req_trg_name.isEmpty()) else if (!request->req_trg_name.isEmpty())
{ {
record.storeString(f_mon_call_name, request->req_trg_name); record.storeString(f_mon_call_name, request->req_trg_name);

View File

@ -44,6 +44,7 @@
#include "../jrd/met_proto.h" #include "../jrd/met_proto.h"
#include "../jrd/mov_proto.h" #include "../jrd/mov_proto.h"
#include "../jrd/thread_proto.h" #include "../jrd/thread_proto.h"
#include "../jrd/Function.h"
#include "../common/classes/auto.h" #include "../common/classes/auto.h"
#include "../common/classes/fb_string.h" #include "../common/classes/fb_string.h"
#include "../common/classes/init.h" #include "../common/classes/init.h"
@ -375,7 +376,7 @@ static InitInstance<GenericMap<Pair<Full<MetaName, string> > > > enginesModules;
ExtEngineManager::Function::Function(thread_db* tdbb, ExtEngineManager* aExtManager, ExtEngineManager::Function::Function(thread_db* tdbb, ExtEngineManager* aExtManager,
ExternalEngine* aEngine, Firebird::ExternalFunction* aFunction, ExternalEngine* aEngine, Firebird::ExternalFunction* aFunction,
const UserFunction* aUdf) const Jrd::Function* aUdf)
: extManager(aExtManager), : extManager(aExtManager),
engine(aEngine), engine(aEngine),
function(aFunction), function(aFunction),
@ -411,7 +412,7 @@ void ExtEngineManager::Function::execute(thread_db* tdbb, jrd_nod* args, impure_
for (int i = 0; i < args->nod_count; ++i) for (int i = 0; i < args->nod_count; ++i)
{ {
impureArgsPtr->vlu_desc = udf->fun_rpt[i + 1].fun_desc; impureArgsPtr->vlu_desc = udf->fun_args[i + 1].fun_parameter->prm_desc;
if (impureArgsPtr->vlu_desc.isText()) if (impureArgsPtr->vlu_desc.isText())
{ {
@ -747,7 +748,7 @@ void ExtEngineManager::closeAttachment(thread_db* tdbb, Attachment* /*attachment
} }
ExtEngineManager::Function* ExtEngineManager::makeFunction(thread_db* tdbb, const UserFunction* udf, ExtEngineManager::Function* ExtEngineManager::makeFunction(thread_db* tdbb, const Jrd::Function* udf,
const Firebird::MetaName& engine, const Firebird::string& entryPoint, const Firebird::MetaName& engine, const Firebird::string& entryPoint,
const Firebird::string& body) const Firebird::string& body)
{ {

View File

@ -44,7 +44,7 @@ class Attachment;
class Database; class Database;
class Format; class Format;
class Trigger; class Trigger;
class UserFunction; class Function;
class ValueImpl; class ValueImpl;
class ValuesImpl; class ValuesImpl;
struct impure_value; struct impure_value;
@ -127,7 +127,7 @@ public:
Function(thread_db* tdbb, ExtEngineManager* aExtManager, Function(thread_db* tdbb, ExtEngineManager* aExtManager,
Firebird::ExternalEngine* aEngine, Firebird::ExternalEngine* aEngine,
Firebird::ExternalFunction* aFunction, Firebird::ExternalFunction* aFunction,
const UserFunction* aUdf); const Jrd::Function* aUdf);
~Function(); ~Function();
void execute(thread_db* tdbb, jrd_nod* args, impure_value* impure); void execute(thread_db* tdbb, jrd_nod* args, impure_value* impure);
@ -136,7 +136,7 @@ public:
ExtEngineManager* extManager; ExtEngineManager* extManager;
Firebird::ExternalEngine* engine; Firebird::ExternalEngine* engine;
Firebird::ExternalFunction* function; Firebird::ExternalFunction* function;
const UserFunction* udf; const Jrd::Function* udf;
Database* database; Database* database;
}; };
@ -221,7 +221,7 @@ public:
public: public:
void closeAttachment(thread_db* tdbb, Attachment* attachment); void closeAttachment(thread_db* tdbb, Attachment* attachment);
Function* makeFunction(thread_db* tdbb, const UserFunction* udf, Function* makeFunction(thread_db* tdbb, const Jrd::Function* udf,
const Firebird::MetaName& engine, const Firebird::string& entryPoint, const Firebird::MetaName& engine, const Firebird::string& entryPoint,
const Firebird::string& body); const Firebird::string& body);
Procedure* makeProcedure(thread_db* tdbb, const jrd_prc* prc, Procedure* makeProcedure(thread_db* tdbb, const jrd_prc* prc,

View File

@ -59,6 +59,7 @@
#include "../jrd/intl.h" #include "../jrd/intl.h"
#include "../jrd/btr.h" #include "../jrd/btr.h"
#include "../jrd/sort.h" #include "../jrd/sort.h"
#include "../jrd/acl.h"
#include "../jrd/gdsassert.h" #include "../jrd/gdsassert.h"
#include "../jrd/cmp_proto.h" #include "../jrd/cmp_proto.h"
#include "../jrd/dsc_proto.h" #include "../jrd/dsc_proto.h"
@ -94,6 +95,7 @@
#include "../jrd/ValuesImpl.h" #include "../jrd/ValuesImpl.h"
#include "../jrd/recsrc/RecordSource.h" #include "../jrd/recsrc/RecordSource.h"
#include "../jrd/recsrc/Cursor.h" #include "../jrd/recsrc/Cursor.h"
#include "../jrd/Function.h"
using Firebird::AutoSetRestore; using Firebird::AutoSetRestore;
@ -299,9 +301,15 @@ static void build_external_access(thread_db* tdbb, ExternalAccessList& list, jrd
// Add externals recursively // Add externals recursively
if (item->exa_action == ExternalAccess::exa_procedure) if (item->exa_action == ExternalAccess::exa_procedure)
{ {
jrd_prc* prc = MET_lookup_procedure_id(tdbb, item->exa_prc_id, false, false, 0); jrd_prc* const procedure = MET_lookup_procedure_id(tdbb, item->exa_prc_id, false, false, 0);
if (prc && prc->prc_request) if (procedure && procedure->prc_request)
build_external_access(tdbb, list, prc->prc_request); build_external_access(tdbb, list, procedure->prc_request);
}
else if (item->exa_action == ExternalAccess::exa_function)
{
Function* const function = Function::lookup(tdbb, item->exa_fun_id, false, false, 0);
if (function && function->fun_request)
build_external_access(tdbb, list, function->fun_request);
} }
else else
{ {
@ -395,7 +403,7 @@ static void verify_trigger_access(thread_db* tdbb, jrd_rel* owner_relation, trig
const SecurityClass* sec_class = SCL_get_class(tdbb, access->acc_security_name.c_str()); const SecurityClass* sec_class = SCL_get_class(tdbb, access->acc_security_name.c_str());
SCL_check_access(tdbb, sec_class, SCL_check_access(tdbb, sec_class,
(access->acc_view_id) ? access->acc_view_id : (view ? view->rel_id : 0), (access->acc_view_id) ? access->acc_view_id : (view ? view->rel_id : 0),
t.request->req_trg_name, NULL, NULL, access->acc_mask, id_trigger, t.request->req_trg_name, access->acc_mask,
access->acc_type, access->acc_name, access->acc_r_name); access->acc_type, access->acc_name, access->acc_r_name);
} }
} }
@ -425,26 +433,56 @@ void CMP_verify_access(thread_db* tdbb, jrd_req* request)
{ {
if (item->exa_action == ExternalAccess::exa_procedure) if (item->exa_action == ExternalAccess::exa_procedure)
{ {
jrd_prc* prc = MET_lookup_procedure_id(tdbb, item->exa_prc_id, false, false, 0); jrd_prc* const procedure = MET_lookup_procedure_id(tdbb, item->exa_prc_id, false, false, 0);
if (!prc->prc_request) if (!procedure->prc_request)
continue; continue;
for (const AccessItem* access = prc->prc_request->req_access.begin(); for (const AccessItem* access = procedure->prc_request->req_access.begin();
access < prc->prc_request->req_access.end(); access < procedure->prc_request->req_access.end();
access++) access++)
{ {
const SecurityClass* sec_class = SCL_get_class(tdbb, access->acc_security_name.c_str()); const SecurityClass* sec_class = SCL_get_class(tdbb, access->acc_security_name.c_str());
if (prc->prc_name.qualifier.isEmpty()) if (procedure->prc_name.qualifier.isEmpty())
{ {
SCL_check_access(tdbb, sec_class, access->acc_view_id, NULL, SCL_check_access(tdbb, sec_class, access->acc_view_id,
prc->prc_name.identifier, NULL, access->acc_mask, access->acc_type, id_procedure, procedure->prc_name.identifier,
access->acc_mask, access->acc_type,
access->acc_name, access->acc_r_name); access->acc_name, access->acc_r_name);
} }
else else
{ {
SCL_check_access(tdbb, sec_class, access->acc_view_id, NULL, SCL_check_access(tdbb, sec_class, access->acc_view_id,
NULL, prc->prc_name.qualifier, access->acc_mask, access->acc_type, id_package, procedure->prc_name.qualifier,
access->acc_mask, access->acc_type,
access->acc_name, access->acc_r_name);
}
}
}
else if (item->exa_action == ExternalAccess::exa_function)
{
Function* const function = Function::lookup(tdbb, item->exa_fun_id, false, false, 0);
if (!function->fun_request)
continue;
for (const AccessItem* access = function->fun_request->req_access.begin();
access < function->fun_request->req_access.end();
access++)
{
const SecurityClass* sec_class = SCL_get_class(tdbb, access->acc_security_name.c_str());
if (function->fun_name.qualifier.isEmpty())
{
SCL_check_access(tdbb, sec_class, access->acc_view_id,
id_function, function->fun_name.identifier,
access->acc_mask, access->acc_type,
access->acc_name, access->acc_r_name);
}
else
{
SCL_check_access(tdbb, sec_class, access->acc_view_id,
id_package, function->fun_name.qualifier,
access->acc_mask, access->acc_type,
access->acc_name, access->acc_r_name); access->acc_name, access->acc_r_name);
} }
} }
@ -474,7 +512,7 @@ void CMP_verify_access(thread_db* tdbb, jrd_req* request)
verify_trigger_access(tdbb, relation, relation->rel_post_erase, view); verify_trigger_access(tdbb, relation, relation->rel_post_erase, view);
break; break;
default: default:
continue; // should never happen, silence the compiler fb_assert(false);
} }
} }
} }
@ -494,17 +532,32 @@ void CMP_verify_access(thread_db* tdbb, jrd_req* request)
{ {
const SecurityClass* sec_class = SCL_get_class(tdbb, access->acc_security_name.c_str()); const SecurityClass* sec_class = SCL_get_class(tdbb, access->acc_security_name.c_str());
Firebird::MetaName trgName( Firebird::MetaName objName;
useCallerPrivs && transaction->tra_caller_name.type == obj_trigger ? SLONG objType = 0;
transaction->tra_caller_name.name : NULL);
Firebird::MetaName prcName(
useCallerPrivs && transaction->tra_caller_name.type == obj_procedure ?
transaction->tra_caller_name.name : NULL);
Firebird::MetaName pkgName(
useCallerPrivs && transaction->tra_caller_name.type == obj_package_header ?
transaction->tra_caller_name.name : NULL);
SCL_check_access(tdbb, sec_class, access->acc_view_id, trgName, prcName, pkgName, if (useCallerPrivs)
{
if (transaction->tra_caller_name.type == obj_trigger)
{
objType = id_trigger;
}
else if (transaction->tra_caller_name.type == obj_procedure)
{
objType = id_procedure;
}
else if (transaction->tra_caller_name.type == obj_udf)
{
objType = id_function;
}
else if (transaction->tra_caller_name.type == obj_package_header)
{
objType = id_package;
}
objName = transaction->tra_caller_name.name;
}
SCL_check_access(tdbb, sec_class, access->acc_view_id, objType, objName,
access->acc_mask, access->acc_type, access->acc_name, access->acc_r_name); access->acc_mask, access->acc_type, access->acc_name, access->acc_r_name);
} }
} }
@ -544,26 +597,48 @@ jrd_req* CMP_clone_request(thread_db* tdbb, jrd_req* request, USHORT level, bool
return clone; return clone;
} }
if (validate) { if (validate)
jrd_prc* procedure = request->req_procedure; {
jrd_prc* const procedure = request->req_procedure;
if (procedure) if (procedure)
{ {
const TEXT* prc_sec_name = (procedure->prc_security_name.length() > 0 ? const TEXT* sec_name = (procedure->prc_security_name.length() > 0 ?
procedure->prc_security_name.c_str() : NULL); procedure->prc_security_name.c_str() : NULL);
const SecurityClass* sec_class = SCL_get_class(tdbb, prc_sec_name); const SecurityClass* sec_class = SCL_get_class(tdbb, sec_name);
if (procedure->prc_name.qualifier.isEmpty()) if (procedure->prc_name.qualifier.isEmpty())
{ {
SCL_check_access(tdbb, sec_class, 0, NULL, NULL, NULL, SCL_execute, SCL_check_access(tdbb, sec_class, 0, 0, NULL, SCL_execute,
object_procedure, procedure->prc_name.identifier); object_procedure, procedure->prc_name.identifier);
} }
else else
{ {
SCL_check_access(tdbb, sec_class, 0, NULL, NULL, NULL, SCL_execute, SCL_check_access(tdbb, sec_class, 0, 0, NULL, SCL_execute,
object_package, procedure->prc_name.qualifier); object_package, procedure->prc_name.qualifier);
} }
} }
Function* const function = request->req_function;
if (function)
{
const TEXT* sec_name = (function->fun_security_name.length() > 0 ?
function->fun_security_name.c_str() : NULL);
const SecurityClass* sec_class = SCL_get_class(tdbb, sec_name);
if (procedure->prc_name.qualifier.isEmpty())
{
SCL_check_access(tdbb, sec_class, 0, 0, NULL, SCL_execute,
object_function, function->fun_name.identifier);
}
else
{
SCL_check_access(tdbb, sec_class, 0, 0, NULL, SCL_execute,
object_package, function->fun_name.qualifier);
}
}
CMP_verify_access(tdbb, request); CMP_verify_access(tdbb, request);
} }
@ -586,6 +661,7 @@ jrd_req* CMP_clone_request(thread_db* tdbb, jrd_req* request, USHORT level, bool
clone->req_top_node = request->req_top_node; clone->req_top_node = request->req_top_node;
clone->req_trg_name = request->req_trg_name; clone->req_trg_name = request->req_trg_name;
clone->req_procedure = request->req_procedure; clone->req_procedure = request->req_procedure;
clone->req_function = request->req_function;
clone->req_flags = request->req_flags & REQ_FLAGS_CLONE_MASK; clone->req_flags = request->req_flags & REQ_FLAGS_CLONE_MASK;
clone->req_last_xcp = request->req_last_xcp; clone->req_last_xcp = request->req_last_xcp;
clone->req_charset = request->req_charset; clone->req_charset = request->req_charset;
@ -1951,16 +2027,17 @@ void CMP_get_desc(thread_db* tdbb, CompilerScratch* csb, jrd_nod* node, DSC* des
case nod_function: case nod_function:
{ {
const UserFunction* function = (UserFunction*) node->nod_arg[e_fun_function]; const Function* const function = (Function*) node->nod_arg[e_fun_function];
// Null value for the function indicates that the function was not // Null value for the function indicates that the function was not
// looked up during parsing the blr. This is true if the function // looked up during parsing the BLR. This is true if the function
// referenced in the procedure blr was dropped before dropping the // referenced in the procedure BLR was dropped before dropping the
// procedure itself. Ignore the case because we are currently trying // procedure itself. Ignore the case because we are currently trying
// to drop the procedure. // to drop the procedure.
// For normal requests, function would never be null. We would have // For normal requests, function would never be null. We would have
// created a valid block while parsing in par_function/par.c. // created a valid block while parsing in par_function/par.c.
if (function) { if (function)
*desc = function->fun_rpt[function->fun_return_arg].fun_desc; {
*desc = function->fun_args[function->fun_return_arg].fun_parameter->prm_desc;
} }
else else
{ {
@ -2266,6 +2343,9 @@ jrd_req* CMP_make_request(thread_db* tdbb, CompilerScratch* csb, bool internal_f
coll->incUseCount(tdbb); coll->incUseCount(tdbb);
break; break;
} }
case Resource::rsc_function:
resource->rsc_fun->addRef();
break;
default: default:
BUGCHECK(219); // msg 219 request of unknown resource BUGCHECK(219); // msg 219 request of unknown resource
} }
@ -2399,6 +2479,9 @@ void CMP_post_resource( ResourceList* rsc_ptr, void* obj, Resource::rsc_s type,
case Resource::rsc_collation: case Resource::rsc_collation:
resource.rsc_coll = (Collation*) obj; resource.rsc_coll = (Collation*) obj;
break; break;
case Resource::rsc_function:
resource.rsc_fun = (Function*) obj;
break;
default: default:
BUGCHECK(220); // msg 220 unknown resource BUGCHECK(220); // msg 220 unknown resource
break; break;
@ -2452,7 +2535,7 @@ void CMP_decrement_prc_use_count(thread_db* tdbb, jrd_prc* procedure)
// The procedure will be different than in dbb_procedures only if it is a // The procedure will be different than in dbb_procedures only if it is a
// floating copy, i.e. an old copy or a deleted procedure. // floating copy, i.e. an old copy or a deleted procedure.
if ((procedure->prc_use_count == 0) && if ((procedure->prc_use_count == 0) &&
( (*tdbb->getDatabase()->dbb_procedures)[procedure->prc_id] != procedure)) // &procedure->prc_header)) ( (*tdbb->getDatabase()->dbb_procedures)[procedure->prc_id] != procedure))
{ {
if (procedure->prc_request) if (procedure->prc_request)
{ {
@ -2521,6 +2604,9 @@ void CMP_release(thread_db* tdbb, jrd_req* request)
coll->decUseCount(tdbb); coll->decUseCount(tdbb);
break; break;
} }
case Resource::rsc_function:
resource->rsc_fun->release(tdbb);
break;
default: default:
BUGCHECK(220); // msg 220 release of unknown resource BUGCHECK(220); // msg 220 release of unknown resource
break; break;
@ -2648,6 +2734,19 @@ void CMP_shutdown_database(thread_db* tdbb)
} }
} }
// release all function existence locks that might have been taken
for (Function** iter = dbb->dbb_functions.begin();
iter < dbb->dbb_functions.end(); ++iter)
{
Function* const function = *iter;
if (function)
{
function->releaseLocks(tdbb);
}
}
// release collation existence locks // release collation existence locks
dbb->releaseIntlObjects(); dbb->releaseIntlObjects();
@ -4096,6 +4195,39 @@ jrd_nod* CMP_pass1(thread_db* tdbb, CompilerScratch* csb, jrd_nod* node)
Resource::rsc_procedure, procedure->prc_id); Resource::rsc_procedure, procedure->prc_id);
break; break;
case nod_function:
{
Function* const function = (Function*) node->nod_arg[e_fun_function];
if (!(csb->csb_g_flags & (csb_internal | csb_ignore_perm)))
{
const TEXT* sec_name =
(function->fun_security_name.length() > 0 ? function->fun_security_name.c_str() : NULL);
if (function->fun_name.qualifier.isEmpty())
{
CMP_post_access(tdbb, csb, sec_name, 0, SCL_execute, object_function,
function->fun_name.identifier.c_str());
}
else
{
CMP_post_access(tdbb, csb, sec_name, 0, SCL_execute, object_package,
function->fun_name.qualifier.c_str());
}
ExternalAccess temp(ExternalAccess::exa_function, function->fun_id);
size_t idx;
if (!csb->csb_external.find(temp, idx))
{
csb->csb_external.insert(idx, temp);
}
}
CMP_post_resource(&csb->csb_resources, function,
Resource::rsc_function, function->fun_id);
}
break;
case nod_store: case nod_store:
if (pass1_store(tdbb, csb, node)) if (pass1_store(tdbb, csb, node))
{ {
@ -6284,7 +6416,7 @@ static void post_procedure_access(thread_db* tdbb, CompilerScratch* csb, jrd_prc
} }
// Add the procedure to list of external objects accessed // Add the procedure to list of external objects accessed
ExternalAccess temp(procedure->prc_id); ExternalAccess temp(ExternalAccess::exa_procedure, procedure->prc_id);
size_t idx; size_t idx;
if (!csb->csb_external.find(temp, idx)) if (!csb->csb_external.find(temp, idx))
csb->csb_external.insert(idx, temp); csb->csb_external.insert(idx, temp);

View File

@ -373,7 +373,7 @@ static TEXT_PTR merge_file[] = { "MERGE EQUIVALENCE FILE BLOCK", 0};
static TEXT_PTR River[] = { "SORT MERGE RIVER", 0}; static TEXT_PTR River[] = { "SORT MERGE RIVER", 0};
static TEXT_PTR UserId[] = { "USER IDENTIFICATION BLOCK ", 0}; static TEXT_PTR UserId[] = { "USER IDENTIFICATION BLOCK ", 0};
static TEXT_PTR Attachment[] = { "ATTACHMENT BLOCK", 0}; static TEXT_PTR Attachment[] = { "ATTACHMENT BLOCK", 0};
static TEXT_PTR UserFunction[] = { "FUNCTION", 0}; static TEXT_PTR Function[] = { "FUNCTION", 0};
static TEXT_PTR IndexedRelationship[] = { "INDEXED RELATIONSHIP", 0}; static TEXT_PTR IndexedRelationship[] = { "INDEXED RELATIONSHIP", 0};
static TEXT_PTR AccessItem[] = { "ACCESS", 0}; static TEXT_PTR AccessItem[] = { "ACCESS", 0};
static TEXT_PTR Resource[] = { "RESOURCE", 0}; static TEXT_PTR Resource[] = { "RESOURCE", 0};

View File

@ -2650,8 +2650,6 @@ static bool create_procedure(thread_db* tdbb, SSHORT phase, DeferredWork* work,
if (!procedure) { if (!procedure) {
return false; return false;
} }
// Never used.
procedure->prc_flags |= PRC_create;
} }
break; break;
} }

View File

@ -115,6 +115,7 @@
#include "../jrd/recsrc/RecordSource.h" #include "../jrd/recsrc/RecordSource.h"
#include "../jrd/recsrc/Cursor.h" #include "../jrd/recsrc/Cursor.h"
#include "../common/classes/Aligner.h" #include "../common/classes/Aligner.h"
#include "../jrd/Function.h"
const int TEMP_LENGTH = 128; const int TEMP_LENGTH = 128;
@ -930,9 +931,10 @@ dsc* EVL_expr(thread_db* tdbb, jrd_nod* const node)
} }
case nod_function: case nod_function:
FUN_evaluate(tdbb, reinterpret_cast<UserFunction*>(node->nod_arg[e_fun_function]), {
node->nod_arg[e_fun_args], impure); Function* const function = reinterpret_cast<Function*>(node->nod_arg[e_fun_function]);
return &impure->vlu_desc; return function->execute(tdbb, node->nod_arg[e_fun_args], impure);
}
case nod_sys_function: case nod_sys_function:
{ {

View File

@ -110,6 +110,7 @@
#include "../jrd/ValuesImpl.h" #include "../jrd/ValuesImpl.h"
#include "../jrd/recsrc/RecordSource.h" #include "../jrd/recsrc/RecordSource.h"
#include "../jrd/recsrc/Cursor.h" #include "../jrd/recsrc/Cursor.h"
#include "../jrd/Function.h"
using namespace Jrd; using namespace Jrd;
@ -751,7 +752,9 @@ void EXE_receive(thread_db* tdbb,
const bool external = request->req_procedure && request->req_procedure->prc_external; const bool external = request->req_procedure && request->req_procedure->prc_external;
if (external) if (external)
{
execute_looper(tdbb, request, transaction, jrd_req::req_sync); execute_looper(tdbb, request, transaction, jrd_req::req_sync);
}
else else
{ {
if (request->req_message->nod_type == nod_stall) if (request->req_message->nod_type == nod_stall)
@ -1821,6 +1824,11 @@ static void stuff_stack_trace(const jrd_req* request)
name = "At procedure '"; name = "At procedure '";
name += req->req_procedure->prc_name.toString().c_str(); name += req->req_procedure->prc_name.toString().c_str();
} }
else if (req->req_function)
{
name = "At function '";
name += req->req_function->fun_name.toString().c_str();
}
if (! name.isEmpty()) if (! name.isEmpty())
{ {

View File

@ -499,14 +499,16 @@ struct Resource
rsc_relation, rsc_relation,
rsc_procedure, rsc_procedure,
rsc_index, rsc_index,
rsc_collation rsc_collation,
rsc_function
}; };
enum rsc_s rsc_type; enum rsc_s rsc_type;
USHORT rsc_id; // Id of the resource USHORT rsc_id; // Id of the resource
jrd_rel* rsc_rel; // Relation block jrd_rel* rsc_rel; // Relation block
jrd_prc* rsc_prc; // Procedure block jrd_prc* rsc_prc; // Procedure block
Collation* rsc_coll; // Collation block Collation* rsc_coll; // Collation block
Function* rsc_fun; // Function block
static bool greaterThan(const Resource& i1, const Resource& i2) static bool greaterThan(const Resource& i1, const Resource& i2)
{ {
@ -586,23 +588,29 @@ struct ExternalAccess
enum exa_act enum exa_act
{ {
exa_procedure, exa_procedure,
exa_function,
exa_insert, exa_insert,
exa_update, exa_update,
exa_delete exa_delete
}; };
exa_act exa_action; exa_act exa_action;
USHORT exa_prc_id; USHORT exa_prc_id;
USHORT exa_fun_id;
USHORT exa_rel_id; USHORT exa_rel_id;
USHORT exa_view_id; USHORT exa_view_id;
// Procedure // Procedure
ExternalAccess(USHORT prc_id) : ExternalAccess(exa_act action, USHORT id) :
exa_action(exa_procedure), exa_prc_id(prc_id), exa_rel_id(0), exa_view_id(0) exa_action(action),
exa_prc_id(action == exa_procedure ? id : 0),
exa_fun_id(action == exa_function ? id : 0),
exa_rel_id(0), exa_view_id(0)
{ } { }
// Trigger // Trigger
ExternalAccess(exa_act action, USHORT rel_id, USHORT view_id) : ExternalAccess(exa_act action, USHORT rel_id, USHORT view_id) :
exa_action(action), exa_prc_id(0), exa_rel_id(rel_id), exa_view_id(view_id) exa_action(action), exa_prc_id(0), exa_fun_id(0),
exa_rel_id(rel_id), exa_view_id(view_id)
{ } { }
static bool greaterThan(const ExternalAccess& i1, const ExternalAccess& i2) static bool greaterThan(const ExternalAccess& i1, const ExternalAccess& i2)
@ -611,6 +619,8 @@ struct ExternalAccess
return i1.exa_action > i2.exa_action; return i1.exa_action > i2.exa_action;
if (i1.exa_prc_id != i2.exa_prc_id) if (i1.exa_prc_id != i2.exa_prc_id)
return i1.exa_prc_id > i2.exa_prc_id; return i1.exa_prc_id > i2.exa_prc_id;
if (i1.exa_fun_id != i2.exa_fun_id)
return i1.exa_fun_id > i2.exa_fun_id;
if (i1.exa_rel_id != i2.exa_rel_id) if (i1.exa_rel_id != i2.exa_rel_id)
return i1.exa_rel_id > i2.exa_rel_id; return i1.exa_rel_id > i2.exa_rel_id;
if (i1.exa_view_id != i2.exa_view_id) if (i1.exa_view_id != i2.exa_view_id)

View File

@ -39,6 +39,7 @@
#include "../mov_proto.h" #include "../mov_proto.h"
#include "../mov_proto.h" #include "../mov_proto.h"
#include "../PreparedStatement.h" #include "../PreparedStatement.h"
#include "../Function.h"
#include "InternalDS.h" #include "InternalDS.h"
@ -363,6 +364,14 @@ void InternalStatement::doPrepare(thread_db* tdbb, const string& sql)
else else
tran->tra_caller_name = CallerName(obj_package_header, request->req_procedure->prc_name.qualifier); tran->tra_caller_name = CallerName(obj_package_header, request->req_procedure->prc_name.qualifier);
} }
else if (request && request->req_function &&
request->req_function->fun_name.identifier.hasData())
{
if (request->req_function->fun_name.qualifier.isEmpty())
tran->tra_caller_name = CallerName(obj_udf, request->req_function->fun_name.identifier);
else
tran->tra_caller_name = CallerName(obj_package_header, request->req_function->fun_name.qualifier);
}
else else
tran->tra_caller_name = CallerName(); tran->tra_caller_name = CallerName();
} }

View File

@ -64,6 +64,7 @@
#include "../common/classes/auto.h" #include "../common/classes/auto.h"
#include "../common/utils_proto.h" #include "../common/utils_proto.h"
#include "../common/classes/FpeControl.h" #include "../common/classes/FpeControl.h"
#include "../jrd/Function.h"
#ifdef WIN_NT #ifdef WIN_NT
#define LIBNAME "ib_util" #define LIBNAME "ib_util"
@ -211,23 +212,6 @@ T CALL_UDF(Database* dbb, int (*entrypoint)(), UDF_ARG* args)
DATABASE DB = FILENAME "ODS.RDB"; DATABASE DB = FILENAME "ODS.RDB";
#define EXCEPTION_MESSAGE "The user defined function: \t%s\n\t referencing entrypoint: \t%s\n\t in module: \t%s\n\tcaused the fatal exception:"
// Blob passing structure
// Updated definitions from the static functions shown below
struct udf_blob
{
SSHORT (*blob_get_segment) (blb*, UCHAR*, USHORT, USHORT*);
void* blob_handle;
SLONG blob_number_segments;
SLONG blob_max_segment;
SLONG blob_total_length;
void (*blob_put_segment) (blb*, const UCHAR*, USHORT);
SLONG (*blob_seek) (blb*, USHORT, SLONG);
};
class OwnedBlobStack : public Stack<blb*> class OwnedBlobStack : public Stack<blb*>
{ {
public: public:
@ -304,7 +288,7 @@ static void blob_put_segment(blb*, const UCHAR*, USHORT);
static SLONG blob_lseek(blb*, USHORT, SLONG); static SLONG blob_lseek(blb*, USHORT, SLONG);
static SLONG get_scalar_array(fun_repeat*, DSC*, scalar_array_desc*, UCharStack&); static SLONG get_scalar_array(fun_repeat*, DSC*, scalar_array_desc*, UCharStack&);
static void invoke(thread_db* tdbb, static void invoke(thread_db* tdbb,
UserFunction* function, Function* function,
fun_repeat* return_ptr, fun_repeat* return_ptr,
impure_value* value, impure_value* value,
UDF_ARG* args, UDF_ARG* args,
@ -314,7 +298,7 @@ static void invoke(thread_db* tdbb,
static bool private_move(Jrd::thread_db* tdbb, dsc* from, dsc* to); static bool private_move(Jrd::thread_db* tdbb, dsc* from, dsc* to);
void FUN_evaluate(thread_db* tdbb, UserFunction* function, jrd_nod* node, impure_value* value) void FUN_evaluate(thread_db* tdbb, Function* function, jrd_nod* node, impure_value* value)
{ {
/************************************** /**************************************
* *
@ -336,49 +320,20 @@ void FUN_evaluate(thread_db* tdbb, UserFunction* function, jrd_nod* node, impure
SET_TDBB(tdbb); SET_TDBB(tdbb);
fun_repeat* return_ptr = function->fun_rpt + function->fun_return_arg; fun_repeat* return_ptr = &function->fun_args[function->fun_return_arg];
value->vlu_desc = return_ptr->fun_desc;
value->vlu_desc.dsc_address = (UCHAR *) & value->vlu_misc;
UCharStack array_stack;
jrd_req* request = tdbb->getRequest(); jrd_req* request = tdbb->getRequest();
// CVC: restoring the null flag seems like a Borland hack to try to // CVC: restoring the null flag seems like a Borland hack to try to
// patch a bug with null handling. There's no evident reason to restore it // patch a bug with null handling. There's no evident reason to restore it
// because EVL_expr() resets it every time it's called. Kept it for now. // because EVL_expr() resets it every time it's called. Kept it for now.
const bool null_flag = ((request->req_flags & req_null) == req_null); const bool null_flag = ((request->req_flags & req_null) == req_null);
UCharStack array_stack;
// Trap any potential errors // Trap any potential errors
try { try {
// If the return data type is any of the string types,
// allocate space to hold value
if (value->vlu_desc.dsc_dtype <= dtype_varying)
{
const USHORT ret_length = value->vlu_desc.dsc_length;
VaryingString* string = value->vlu_string;
if (string && string->str_length < ret_length)
{
delete string;
string = NULL;
}
if (!string)
{
string = FB_NEW_RPT(*tdbb->getDefaultPool(), ret_length) VaryingString;
string->str_length = ret_length;
value->vlu_string = string;
}
value->vlu_desc.dsc_address = string->str_data;
}
if (function->fun_external)
{
function->fun_external->execute(tdbb, node, value);
return;
}
UDF_ARG args[MAX_UDF_ARGUMENTS + 1]; UDF_ARG args[MAX_UDF_ARGUMENTS + 1];
HalfStaticArray<UCHAR, 800> temp; HalfStaticArray<UCHAR, 800> temp;
@ -403,8 +358,8 @@ void FUN_evaluate(thread_db* tdbb, UserFunction* function, jrd_nod* node, impure
double d; double d;
// Process arguments // Process arguments
const fun_repeat* const end = function->fun_rpt + 1 + function->fun_count; const fun_repeat* const end = function->fun_args.end();
for (fun_repeat* tail = function->fun_rpt + 1; tail < end; ++tail) for (fun_repeat* tail = function->fun_args.begin() + 1; tail < end; ++tail)
{ {
DSC* input; DSC* input;
if (tail == return_ptr) if (tail == return_ptr)
@ -441,7 +396,7 @@ void FUN_evaluate(thread_db* tdbb, UserFunction* function, jrd_nod* node, impure
continue; continue;
} }
temp_desc = tail->fun_desc; temp_desc = tail->fun_parameter->prm_desc;
temp_desc.dsc_address = temp_ptr; temp_desc.dsc_address = temp_ptr;
// CVC: There's a theoretical possibility of overflowing "length" here. // CVC: There's a theoretical possibility of overflowing "length" here.
USHORT length = FB_ALIGN(temp_desc.dsc_length, FB_DOUBLE_ALIGN); USHORT length = FB_ALIGN(temp_desc.dsc_length, FB_DOUBLE_ALIGN);
@ -459,7 +414,7 @@ void FUN_evaluate(thread_db* tdbb, UserFunction* function, jrd_nod* node, impure
continue; continue;
} }
if (tail->fun_desc.dsc_dtype == dtype_blob) if (tail->fun_parameter->prm_desc.dsc_dtype == dtype_blob)
{ {
length = sizeof(udf_blob); length = sizeof(udf_blob);
} }
@ -470,7 +425,7 @@ void FUN_evaluate(thread_db* tdbb, UserFunction* function, jrd_nod* node, impure
{ {
// Probably for arrays and blobs it's better to preserve the // Probably for arrays and blobs it's better to preserve the
// current behavior that sends a zeroed memory chunk. // current behavior that sends a zeroed memory chunk.
switch (tail->fun_desc.dsc_dtype) switch (tail->fun_parameter->prm_desc.dsc_dtype)
{ {
case dtype_quad: case dtype_quad:
case dtype_array: case dtype_array:
@ -491,11 +446,11 @@ void FUN_evaluate(thread_db* tdbb, UserFunction* function, jrd_nod* node, impure
{ {
SLONG l; SLONG l;
SLONG* lp; SLONG* lp;
switch (tail->fun_desc.dsc_dtype) switch (tail->fun_parameter->prm_desc.dsc_dtype)
{ {
case dtype_short: case dtype_short:
{ {
const SSHORT s = MOV_get_long(input, (SSHORT) tail->fun_desc.dsc_scale); const SSHORT s = MOV_get_long(input, (SSHORT) tail->fun_parameter->prm_desc.dsc_scale);
if (tail->fun_mechanism == FUN_value) if (tail->fun_mechanism == FUN_value)
{ {
// For (apparent) portability reasons, SHORT by value // For (apparent) portability reasons, SHORT by value
@ -514,7 +469,7 @@ void FUN_evaluate(thread_db* tdbb, UserFunction* function, jrd_nod* node, impure
break; break;
case dtype_long: case dtype_long:
l = MOV_get_long(input, (SSHORT) tail->fun_desc.dsc_scale); l = MOV_get_long(input, (SSHORT) tail->fun_parameter->prm_desc.dsc_scale);
if (tail->fun_mechanism == FUN_value) if (tail->fun_mechanism == FUN_value)
{ {
*arg_ptr++ = (UDF_ARG)(IPTR)l; *arg_ptr++ = (UDF_ARG)(IPTR)l;
@ -549,7 +504,7 @@ void FUN_evaluate(thread_db* tdbb, UserFunction* function, jrd_nod* node, impure
case dtype_int64: case dtype_int64:
{ {
SINT64* pi64; SINT64* pi64;
const SINT64 i64 = MOV_get_int64(input, (SSHORT) tail->fun_desc.dsc_scale); const SINT64 i64 = MOV_get_int64(input, (SSHORT) tail->fun_parameter->prm_desc.dsc_scale);
if (tail->fun_mechanism == FUN_value) if (tail->fun_mechanism == FUN_value)
{ {
@ -768,138 +723,6 @@ void FUN_evaluate(thread_db* tdbb, UserFunction* function, jrd_nod* node, impure
} }
UserFunction* FUN_lookup_function(thread_db* tdbb, const QualifiedName& name)
{
/**************************************
*
* F U N _ l o o k u p _ f u n c t i o n
*
**************************************
*
* Functional description
* Lookup function by name.
*
**************************************/
SET_TDBB(tdbb);
Database* dbb = tdbb->getDatabase();
UserFunction* function = NULL;
if (dbb->dbb_functions.get(name, function))
return function;
fun_repeat temp[MAX_UDF_ARGUMENTS + 1];
jrd_req* request_fun = CMP_find_request(tdbb, irq_l_functions, IRQ_REQUESTS);
jrd_req* request_arg = CMP_find_request(tdbb, irq_l_args, IRQ_REQUESTS);
FOR(REQUEST_HANDLE request_fun)
X IN RDB$FUNCTIONS
WITH X.RDB$FUNCTION_NAME EQ name.identifier.c_str() AND
X.RDB$PACKAGE_NAME EQUIV NULLIF(name.qualifier.c_str(), '')
if (!REQUEST(irq_l_functions))
REQUEST(irq_l_functions) = request_fun;
USHORT count = 0;
USHORT args = 0;
MOVE_CLEAR(temp, (SLONG) sizeof(temp));
ULONG length = 0;
FOR(REQUEST_HANDLE request_arg)
Y IN RDB$FUNCTION_ARGUMENTS
WITH Y.RDB$FUNCTION_NAME EQ X.RDB$FUNCTION_NAME AND
Y.RDB$PACKAGE_NAME EQUIV NULLIF(name.qualifier.c_str(), '')
SORTED BY Y.RDB$ARGUMENT_POSITION
if (!REQUEST(irq_l_args))
REQUEST(irq_l_args) = request_arg;
fun_repeat* tail = temp + Y.RDB$ARGUMENT_POSITION;
tail->fun_mechanism = (FUN_T) Y.RDB$MECHANISM;
count = MAX(count, Y.RDB$ARGUMENT_POSITION);
DSC_make_descriptor(&tail->fun_desc, Y.RDB$FIELD_TYPE,
Y.RDB$FIELD_SCALE, Y.RDB$FIELD_LENGTH,
Y.RDB$FIELD_SUB_TYPE, Y.RDB$CHARACTER_SET_ID,
0);
if (tail->fun_desc.dsc_dtype == dtype_cstring)
tail->fun_desc.dsc_length++;
if (Y.RDB$ARGUMENT_POSITION != X.RDB$RETURN_ARGUMENT)
++args;
USHORT l = FB_ALIGN(tail->fun_desc.dsc_length, FB_DOUBLE_ALIGN);
if (tail->fun_desc.dsc_dtype == dtype_blob)
l = sizeof(udf_blob);
length += l;
END_FOR;
function = FB_NEW_RPT(*dbb->dbb_permanent, count + 1u) UserFunction(*dbb->dbb_permanent);
function->fun_name = QualifiedName(X.RDB$FUNCTION_NAME,
(X.RDB$PACKAGE_NAME.NULL ? NULL : X.RDB$PACKAGE_NAME));
function->fun_count = count;
function->fun_args = args;
function->fun_return_arg = X.RDB$RETURN_ARGUMENT;
function->fun_type = X.RDB$FUNCTION_TYPE;
function->fun_temp_length = length;
memcpy(function->fun_rpt, temp, (count + 1u) * sizeof(fun_repeat));
// Prepare the exception message to be used in case this function ever
// causes an exception. This is done at this time to save us from preparing
// (thus allocating) this message every time the function is called.
function->fun_exception_message.printf(EXCEPTION_MESSAGE, name.toString().c_str(),
X.RDB$ENTRYPOINT, X.RDB$MODULE_NAME);
if (!X.RDB$ENGINE_NAME.NULL)
{
HalfStaticArray<char, 512> body;
if (!X.RDB$FUNCTION_SOURCE.NULL)
{
blb* blob = BLB_open(tdbb, dbb->dbb_sys_trans, &X.RDB$FUNCTION_SOURCE);
ULONG len = BLB_get_data(tdbb, blob,
(UCHAR*) body.getBuffer(blob->blb_length + 1), blob->blb_length + 1);
body.begin()[MIN(blob->blb_length, len)] = '\0';
}
else
body.getBuffer(1)[0] = '\0';
function->fun_entrypoint = NULL;
function->fun_external = dbb->dbb_extManager.makeFunction(
tdbb, function, X.RDB$ENGINE_NAME,
(X.RDB$ENTRYPOINT.NULL ? "" : X.RDB$ENTRYPOINT), body.begin());
}
else
{
function->fun_external = NULL;
function->fun_entrypoint =
Module::lookup(X.RDB$MODULE_NAME, X.RDB$ENTRYPOINT, dbb->dbb_modules);
// Could not find a function with given MODULE, ENTRYPOINT.
// Try the list of internally implemented functions.
if (!function->fun_entrypoint)
{
function->fun_entrypoint =
BUILTIN_entrypoint(X.RDB$MODULE_NAME, X.RDB$ENTRYPOINT);
}
}
dbb->dbb_functions.put(name, function);
END_FOR;
if (!REQUEST(irq_l_functions))
REQUEST(irq_l_functions) = request_fun;
if (!REQUEST(irq_l_args))
REQUEST(irq_l_args) = request_arg;
return function;
}
static SLONG blob_lseek(blb* blob, USHORT mode, SLONG offset) static SLONG blob_lseek(blb* blob, USHORT mode, SLONG offset)
{ {
/************************************** /**************************************
@ -1005,7 +828,7 @@ static SLONG get_scalar_array(fun_repeat* arg,
// Convert array, if necessary // Convert array, if necessary
dsc to = arg->fun_desc; dsc to = arg->fun_parameter->prm_desc;
dsc from = array_desc->iad_rpt[0].iad_desc; dsc from = array_desc->iad_rpt[0].iad_desc;
if (to.dsc_dtype != from.dsc_dtype || if (to.dsc_dtype != from.dsc_dtype ||
@ -1039,7 +862,7 @@ static SLONG get_scalar_array(fun_repeat* arg,
// Fill out the scalar array descriptor // Fill out the scalar array descriptor
stack.push(data); stack.push(data);
scalar_desc->sad_desc = arg->fun_desc; scalar_desc->sad_desc = arg->fun_parameter->prm_desc;
scalar_desc->sad_desc.dsc_address = data; scalar_desc->sad_desc.dsc_address = data;
scalar_desc->sad_dimensions = dimensions; scalar_desc->sad_dimensions = dimensions;
@ -1057,7 +880,7 @@ static SLONG get_scalar_array(fun_repeat* arg,
static void invoke(thread_db* tdbb, static void invoke(thread_db* tdbb,
UserFunction* function, Function* function,
fun_repeat* return_ptr, fun_repeat* return_ptr,
impure_value* value, impure_value* value,
UDF_ARG* args, UDF_ARG* args,

View File

@ -39,7 +39,6 @@ public:
}; };
void FUN_evaluate(Jrd::thread_db*, Jrd::UserFunction*, Jrd::jrd_nod*, Jrd::impure_value*); void FUN_evaluate(Jrd::thread_db*, Jrd::Function*, Jrd::jrd_nod*, Jrd::impure_value*);
Jrd::UserFunction* FUN_lookup_function(Jrd::thread_db*, const Firebird::QualifiedName&);
#endif // JRD_FUN_PROTO_H #endif // JRD_FUN_PROTO_H

View File

@ -429,7 +429,6 @@ public:
USHORT prc_inputs; USHORT prc_inputs;
USHORT prc_defaults; USHORT prc_defaults;
USHORT prc_outputs; USHORT prc_outputs;
//jrd_nod* prc_input_msg; // It's set once by met.epp and never used.
jrd_nod* prc_output_msg; jrd_nod* prc_output_msg;
Format* prc_input_fmt; Format* prc_input_fmt;
Format* prc_output_fmt; Format* prc_output_fmt;
@ -458,17 +457,14 @@ public:
// prc_flags // prc_flags
const USHORT PRC_scanned = 1; // Field expressions scanned const USHORT PRC_scanned = 1; // Field expressions scanned
const USHORT PRC_system = 2; // Set in met.epp, never tested. const USHORT PRC_obsolete = 2; // Procedure known gonzo
const USHORT PRC_obsolete = 4; // Procedure known gonzo const USHORT PRC_being_scanned = 4; // New procedure needs dependencies during scan
const USHORT PRC_being_scanned = 8; // New procedure needs dependencies during scan const USHORT PRC_being_altered = 8; // Procedure is getting altered
//const USHORT PRC_blocking = 16; // Blocking someone from dropping procedure
const USHORT PRC_create = 32; // Newly created. Set in met.epp, never tested or disabled.
const USHORT PRC_being_altered = 64; // Procedure is getting altered
// This flag is used to make sure that MET_remove_procedure // This flag is used to make sure that MET_remove_procedure
// does not delete and remove procedure block from cache // does not delete and remove procedure block from cache
// so dfw.epp:modify_procedure() can flip procedure body without // so dfw.epp:modify_procedure() can flip procedure body without
// invalidating procedure pointers from other parts of metadata cache // invalidating procedure pointers from other parts of metadata cache
const USHORT PRC_check_existence = 128; // Existence lock released const USHORT PRC_check_existence = 16; // Existence lock released
const USHORT MAX_PROC_ALTER = 64; // No. of times an in-cache procedure can be altered const USHORT MAX_PROC_ALTER = 64; // No. of times an in-cache procedure can be altered

View File

@ -92,6 +92,7 @@
#include "../jrd/PreparedStatement.h" #include "../jrd/PreparedStatement.h"
#include "../jrd/DebugInterface.h" #include "../jrd/DebugInterface.h"
#include "../common/classes/MsgPrint.h" #include "../common/classes/MsgPrint.h"
#include "../jrd/Function.h"
#ifdef HAVE_CTYPE_H #ifdef HAVE_CTYPE_H
@ -118,7 +119,7 @@ static void lookup_view_contexts(thread_db*, jrd_rel*);
static void make_relation_scope_name(const TEXT*, const USHORT, Firebird::string& str); static void make_relation_scope_name(const TEXT*, const USHORT, Firebird::string& str);
static jrd_nod* parse_field_blr(thread_db* tdbb, bid* blob_id, const Firebird::MetaName name = Firebird::MetaName()); static jrd_nod* parse_field_blr(thread_db* tdbb, bid* blob_id, const Firebird::MetaName name = Firebird::MetaName());
static jrd_nod* parse_param_blr(thread_db*, jrd_prc*, bid*, CompilerScratch*); static jrd_nod* parse_param_blr(thread_db*, jrd_prc*, bid*, CompilerScratch*);
static jrd_nod* parse_procedure_blr(thread_db*, jrd_prc*, bid*, CompilerScratch*, bool); static void parse_procedure_blr(thread_db*, jrd_prc*, bid*, CompilerScratch*, bool);
static void par_messages(thread_db*, const UCHAR* const, USHORT, jrd_prc*, CompilerScratch*); static void par_messages(thread_db*, const UCHAR* const, USHORT, jrd_prc*, CompilerScratch*);
static bool resolve_charset_and_collation(thread_db*, USHORT*, const UCHAR*, const UCHAR*); static bool resolve_charset_and_collation(thread_db*, USHORT*, const UCHAR*, const UCHAR*);
static void save_trigger_data(thread_db*, trig_vec**, jrd_rel*, jrd_req*, blb*, bid*, static void save_trigger_data(thread_db*, trig_vec**, jrd_rel*, jrd_req*, blb*, bid*,
@ -3153,14 +3154,6 @@ jrd_prc* MET_procedure(thread_db* tdbb, int id, bool noscan, USHORT flags)
END_FOR END_FOR
} }
if (!P.RDB$SYSTEM_FLAG)
{
procedure->prc_flags &= ~PRC_system;
}
else
{
procedure->prc_flags |= PRC_system;
}
if ( (procedure->prc_inputs = P.RDB$PROCEDURE_INPUTS) ) if ( (procedure->prc_inputs = P.RDB$PROCEDURE_INPUTS) )
{ {
procedure->prc_input_fields = procedure->prc_input_fields =
@ -3330,14 +3323,6 @@ jrd_prc* MET_procedure(thread_db* tdbb, int id, bool noscan, USHORT flags)
jrd_nod* node = csb->csb_rpt[i].csb_message; jrd_nod* node = csb->csb_rpt[i].csb_message;
if (node) if (node)
{ {
/*
if ((int) (IPTR) node->nod_arg[e_msg_number] == 0)
{
// Never used.
procedure->prc_input_msg = node;
}
else
*/
if ((int) (IPTR) node->nod_arg[e_msg_number] == 1) if ((int) (IPTR) node->nod_arg[e_msg_number] == 1)
{ {
procedure->prc_output_msg = node; procedure->prc_output_msg = node;
@ -4629,7 +4614,9 @@ static void gen_ext_message(Firebird::UCharBuffer& blr, UCHAR message,
blr.add(blr_not_nullable); blr.add(blr_not_nullable);
if (parameter->prm_mechanism == prm_mech_type_of) if (parameter->prm_mechanism == prm_mech_type_of)
{
PreparedStatement::generateBlr(&parameter->prm_desc, blr); PreparedStatement::generateBlr(&parameter->prm_desc, blr);
}
else else
{ {
fb_assert(parameter->prm_mechanism == prm_mech_normal); fb_assert(parameter->prm_mechanism == prm_mech_normal);
@ -4662,11 +4649,11 @@ static void gen_ext_message(Firebird::UCharBuffer& blr, UCHAR message,
} }
static jrd_nod* parse_procedure_blr(thread_db* tdbb, static void parse_procedure_blr(thread_db* tdbb,
jrd_prc* procedure, jrd_prc* procedure,
bid* blob_id, bid* blob_id,
CompilerScratch* csb, CompilerScratch* csb,
bool external) bool external)
{ {
/************************************** /**************************************
* *
@ -4675,7 +4662,7 @@ static jrd_nod* parse_procedure_blr(thread_db* tdbb,
************************************** **************************************
* *
* Functional description * Functional description
* Parse blr, returning a compiler scratch block with the results. * Parse procedure BLR.
* *
**************************************/ **************************************/
SET_TDBB(tdbb); SET_TDBB(tdbb);
@ -4746,8 +4733,8 @@ static jrd_nod* parse_procedure_blr(thread_db* tdbb,
par_messages(tdbb, tmp.begin(), (ULONG) tmp.getCount(), procedure, csb); par_messages(tdbb, tmp.begin(), (ULONG) tmp.getCount(), procedure, csb);
return PAR_blr(tdbb, NULL, tmp.begin(), (ULONG) tmp.getCount(), NULL, &csb, PAR_blr(tdbb, NULL, tmp.begin(), (ULONG) tmp.getCount(), NULL, &csb,
&procedure->prc_request, false, 0); &procedure->prc_request, false, 0);
} }
@ -4826,8 +4813,7 @@ static void par_messages(thread_db* tdbb,
if (offset > MAX_FORMAT_SIZE) if (offset > MAX_FORMAT_SIZE)
{ {
ERR_post(Arg::Gds(isc_imp_exc) << ERR_post(Arg::Gds(isc_imp_exc) << Arg::Gds(isc_blktoobig));
Arg::Gds(isc_blktoobig));
} }
format->fmt_length = (USHORT) offset; format->fmt_length = (USHORT) offset;
@ -5245,7 +5231,7 @@ static void store_dependencies(thread_db* tdbb,
break; break;
case obj_udf: case obj_udf:
{ {
UserFunction* udf = (UserFunction*) node->nod_arg[e_dep_object]; Function* const udf = (Function*) node->nod_arg[e_dep_object];
dpdo_name = &udf->fun_name.identifier; dpdo_name = &udf->fun_name.identifier;
packageName = udf->fun_name.qualifier; packageName = udf->fun_name.qualifier;
} }

View File

@ -64,6 +64,7 @@
#include "../common/utils_proto.h" #include "../common/utils_proto.h"
#include "../jrd/SysFunction.h" #include "../jrd/SysFunction.h"
#include "../jrd/BlrReader.h" #include "../jrd/BlrReader.h"
#include "../jrd/Function.h"
using namespace Jrd; using namespace Jrd;
using namespace Firebird; using namespace Firebird;
@ -1463,9 +1464,8 @@ static jrd_nod* par_function(thread_db* tdbb, CompilerScratch* csb, SSHORT blr_o
return node; return node;
} }
// Isn't it strange that gbak presence means nothing to this function now? Function* const function = Function::lookup(tdbb, name, false);
UserFunction* function =
FUN_lookup_function(tdbb, name); //, !(tdbb->getAttachment()->att_flags & ATT_gbak_attachment));
if (!function) if (!function)
{ {
if (tdbb->tdbb_flags & TDBB_prc_being_dropped) if (tdbb->tdbb_flags & TDBB_prc_being_dropped)
@ -1481,7 +1481,7 @@ static jrd_nod* par_function(thread_db* tdbb, CompilerScratch* csb, SSHORT blr_o
error(csb, Arg::Gds(isc_funnotdef) << Arg::Str(name.toString())); error(csb, Arg::Gds(isc_funnotdef) << Arg::Str(name.toString()));
} }
if (!function->fun_entrypoint && !function->fun_external) if (!function->fun_entrypoint && !function->fun_external && !function->fun_request)
{ {
if (tdbb->getAttachment()->att_flags & ATT_gbak_attachment) if (tdbb->getAttachment()->att_flags & ATT_gbak_attachment)
{ {
@ -1503,15 +1503,15 @@ static jrd_nod* par_function(thread_db* tdbb, CompilerScratch* csb, SSHORT blr_o
node->nod_arg[e_fun_args] = par_args(tdbb, csb, VALUE); node->nod_arg[e_fun_args] = par_args(tdbb, csb, VALUE);
// Check to see if the argument count matches // Check to see if the argument count matches
if (node->nod_arg[e_fun_args]->nod_count != function->fun_args) if (node->nod_arg[e_fun_args]->nod_count != function->fun_inputs)
{ {
error(csb, Arg::Gds(isc_funmismat) << Arg::Str(function->fun_name.toString())); error(csb, Arg::Gds(isc_funmismat) << Arg::Str(function->fun_name.toString()));
} }
// CVC: I will track ufds only if a proc is not being dropped. // CVC: I will track ufds only if a proc is not being dropped.
if (csb->csb_g_flags & csb_get_dependencies) if (csb->csb_g_flags & csb_get_dependencies)
{ {
jrd_nod* dep_node = PAR_make_node (tdbb, e_dep_length); jrd_nod* dep_node = PAR_make_node(tdbb, e_dep_length);
dep_node->nod_type = nod_dependency; dep_node->nod_type = nod_dependency;
dep_node->nod_arg [e_dep_object] = (jrd_nod*) function; dep_node->nod_arg [e_dep_object] = (jrd_nod*) function;
dep_node->nod_arg [e_dep_object_type] = (jrd_nod*)(IPTR) obj_udf; dep_node->nod_arg [e_dep_object_type] = (jrd_nod*)(IPTR) obj_udf;

View File

@ -231,6 +231,7 @@ public:
ResourceList req_resources; // Resources (relations and indices) ResourceList req_resources; // Resources (relations and indices)
jrd_nod* req_message; // Current message for send/receive jrd_nod* req_message; // Current message for send/receive
jrd_prc* req_procedure; // procedure, if any jrd_prc* req_procedure; // procedure, if any
Function* req_function; // function, if any
Firebird::MetaName req_trg_name; // name of request (trigger), if any Firebird::MetaName req_trg_name; // name of request (trigger), if any
ULONG req_records_selected; // count of records selected by request (meeting selection criteria) ULONG req_records_selected; // count of records selected by request (meeting selection criteria)

View File

@ -73,9 +73,9 @@ static bool check_number(const UCHAR*, USHORT);
static bool check_user_group(thread_db* tdbb, const UCHAR*, USHORT); static bool check_user_group(thread_db* tdbb, const UCHAR*, USHORT);
static bool check_string(const UCHAR*, const Firebird::MetaName&); static bool check_string(const UCHAR*, const Firebird::MetaName&);
static SecurityClass::flags_t compute_access(thread_db* tdbb, const SecurityClass*, static SecurityClass::flags_t compute_access(thread_db* tdbb, const SecurityClass*,
const jrd_rel*, const Firebird::MetaName&, const Firebird::MetaName&, const Firebird::MetaName&); const jrd_rel*, SLONG, const Firebird::MetaName&);
static SecurityClass::flags_t walk_acl(thread_db* tdbb, const Acl&, const jrd_rel*, static SecurityClass::flags_t walk_acl(thread_db* tdbb, const Acl&, const jrd_rel*,
const Firebird::MetaName&, const Firebird::MetaName&, const Firebird::MetaName&); SLONG, const Firebird::MetaName&);
static inline void check_and_move(UCHAR from, Acl& to) static inline void check_and_move(UCHAR from, Acl& to)
{ {
@ -109,9 +109,8 @@ static const P_NAMES p_names[] =
void SCL_check_access(thread_db* tdbb, void SCL_check_access(thread_db* tdbb,
const SecurityClass* s_class, const SecurityClass* s_class,
SLONG view_id, SLONG view_id,
const Firebird::MetaName& trg_name, SLONG obj_type,
const Firebird::MetaName& prc_name, const Firebird::MetaName& obj_name,
const Firebird::MetaName& pkg_name,
SecurityClass::flags_t mask, SecurityClass::flags_t mask,
const TEXT* type, const TEXT* type,
const char* name) const char* name)
@ -170,8 +169,8 @@ void SCL_check_access(thread_db* tdbb,
if (view_id) { if (view_id) {
view = MET_lookup_relation_id(tdbb, view_id, false); view = MET_lookup_relation_id(tdbb, view_id, false);
} }
if ((view || trg_name.hasData() || prc_name.hasData() || pkg_name.hasData()) && if ((view || obj_name.hasData()) &&
(compute_access(tdbb, s_class, view, trg_name, prc_name, pkg_name) & mask)) (compute_access(tdbb, s_class, view, obj_type, obj_name) & mask))
{ {
return; return;
} }
@ -204,9 +203,8 @@ void SCL_check_access(thread_db* tdbb,
void SCL_check_access(thread_db* tdbb, void SCL_check_access(thread_db* tdbb,
const SecurityClass* s_class, const SecurityClass* s_class,
SLONG view_id, SLONG view_id,
const Firebird::MetaName& trg_name, SLONG obj_type,
const Firebird::MetaName& prc_name, const Firebird::MetaName& obj_name,
const Firebird::MetaName& pkg_name,
SecurityClass::flags_t mask, SecurityClass::flags_t mask,
const TEXT* type, const TEXT* type,
const Firebird::MetaName& name, const Firebird::MetaName& name,
@ -234,8 +232,8 @@ void SCL_check_access(thread_db* tdbb,
fullFieldName += name.c_str(); fullFieldName += name.c_str();
} }
SCL_check_access(tdbb, s_class, view_id, trg_name, prc_name, pkg_name, mask, type, SCL_check_access(tdbb, s_class, view_id, obj_type, obj_name, mask, type,
fullFieldName.c_str()); fullFieldName.c_str());
} }
@ -322,7 +320,7 @@ void SCL_check_index(thread_db* tdbb, const Firebird::MetaName& index_name, UCHA
return; return;
} }
SCL_check_access(tdbb, s_class, 0, NULL, NULL, NULL, mask, object_table, reln_name); SCL_check_access(tdbb, s_class, 0, 0, NULL, mask, object_table, reln_name);
request = NULL; request = NULL;
@ -352,12 +350,12 @@ void SCL_check_index(thread_db* tdbb, const Firebird::MetaName& index_name, UCHA
if (!RF.RDB$SECURITY_CLASS.NULL) if (!RF.RDB$SECURITY_CLASS.NULL)
{ {
s_class = SCL_get_class(tdbb, RF.RDB$SECURITY_CLASS); s_class = SCL_get_class(tdbb, RF.RDB$SECURITY_CLASS);
SCL_check_access(tdbb, s_class, 0, NULL, NULL, NULL, mask, object_column, fullFieldName); SCL_check_access(tdbb, s_class, 0, 0, NULL, mask, object_column, fullFieldName);
} }
else else
{ {
SCL_check_access(tdbb, default_s_class, 0, NULL, NULL, NULL, mask, object_column, SCL_check_access(tdbb, default_s_class, 0, 0, NULL, mask, object_column,
fullFieldName); fullFieldName);
} }
END_FOR; END_FOR;
@ -414,7 +412,7 @@ void SCL_check_package(thread_db* tdbb, const dsc* dsc_name, SecurityClass::flag
if (!REQUEST(irq_pkg_security)) if (!REQUEST(irq_pkg_security))
REQUEST(irq_pkg_security) = request; REQUEST(irq_pkg_security) = request;
SCL_check_access(tdbb, s_class, 0, NULL, NULL, name, mask, object_package, name); SCL_check_access(tdbb, s_class, 0, id_package, name, mask, object_package, name);
} }
@ -459,7 +457,52 @@ void SCL_check_procedure(thread_db* tdbb, const dsc* dsc_name, SecurityClass::fl
if (!REQUEST(irq_p_security)) if (!REQUEST(irq_p_security))
REQUEST(irq_p_security) = request; REQUEST(irq_p_security) = request;
SCL_check_access(tdbb, s_class, 0, NULL, name, NULL, mask, object_procedure, name); SCL_check_access(tdbb, s_class, 0, id_procedure, name, mask, object_procedure, name);
}
void SCL_check_function(thread_db* tdbb, const dsc* dsc_name, SecurityClass::flags_t mask)
{
/**************************************
*
* S C L _ c h e c k _ f u n c t i o n
*
**************************************
*
* Functional description
* Given a function name, check for a set of privileges. The
* function in question may or may not have been created, let alone
* scanned. This is used exclusively for meta-data operations.
*
**************************************/
SET_TDBB(tdbb);
// Get the name in CSTRING format, ending on NULL or SPACE
fb_assert(dsc_name->dsc_dtype == dtype_text);
const Firebird::MetaName name(reinterpret_cast<TEXT*>(dsc_name->dsc_address),
dsc_name->dsc_length);
Database* dbb = tdbb->getDatabase();
const SecurityClass* s_class = NULL;
jrd_req* request = CMP_find_request(tdbb, irq_f_security, IRQ_REQUESTS);
FOR (REQUEST_HANDLE request)
SFUN IN RDB$FUNCTIONS
WITH SFUN.RDB$FUNCTION_NAME EQ name.c_str() AND
SFUN.RDB$PACKAGE_NAME MISSING
if (!REQUEST(irq_f_security))
REQUEST(irq_f_security) = request;
if (!SFUN.RDB$SECURITY_CLASS.NULL)
s_class = SCL_get_class(tdbb, SFUN.RDB$SECURITY_CLASS);
END_FOR;
if (!REQUEST(irq_f_security))
REQUEST(irq_f_security) = request;
SCL_check_access(tdbb, s_class, 0, id_function, name, mask, object_procedure, name);
} }
@ -503,7 +546,7 @@ void SCL_check_relation(thread_db* tdbb, const dsc* dsc_name, SecurityClass::fla
if (!REQUEST(irq_v_security)) if (!REQUEST(irq_v_security))
REQUEST(irq_v_security) = request; REQUEST(irq_v_security) = request;
SCL_check_access(tdbb, s_class, 0, NULL, NULL, NULL, mask, object_table, name); SCL_check_access(tdbb, s_class, 0, 0, NULL, mask, object_table, name);
} }
@ -551,7 +594,7 @@ SecurityClass* SCL_get_class(thread_db* tdbb, const TEXT* par_string)
MemoryPool& pool = *attachment->att_pool; MemoryPool& pool = *attachment->att_pool;
SecurityClass* const s_class = FB_NEW(pool) SecurityClass(pool, string); SecurityClass* const s_class = FB_NEW(pool) SecurityClass(pool, string);
s_class->scl_flags = compute_access(tdbb, s_class, NULL, NULL, NULL, NULL); s_class->scl_flags = compute_access(tdbb, s_class, NULL, 0, NULL);
if (s_class->scl_flags & SCL_exists) if (s_class->scl_flags & SCL_exists)
{ {
@ -844,7 +887,7 @@ SecurityClass* SCL_recompute_class(thread_db* tdbb, const TEXT* string)
return NULL; return NULL;
} }
s_class->scl_flags = compute_access(tdbb, s_class, NULL, NULL, NULL, NULL); s_class->scl_flags = compute_access(tdbb, s_class, NULL, 0, NULL);
if (s_class->scl_flags & SCL_exists) { if (s_class->scl_flags & SCL_exists) {
return s_class; return s_class;
@ -1034,9 +1077,8 @@ static bool check_string(const UCHAR* acl, const Firebird::MetaName& string)
static SecurityClass::flags_t compute_access(thread_db* tdbb, static SecurityClass::flags_t compute_access(thread_db* tdbb,
const SecurityClass* s_class, const SecurityClass* s_class,
const jrd_rel* view, const jrd_rel* view,
const Firebird::MetaName& trg_name, SLONG obj_type,
const Firebird::MetaName& prc_name, const Firebird::MetaName& obj_name)
const Firebird::MetaName& pkg_name)
{ {
/************************************** /**************************************
* *
@ -1090,7 +1132,7 @@ static SecurityClass::flags_t compute_access(thread_db* tdbb,
if (acl.getCount() > 0) if (acl.getCount() > 0)
{ {
privileges |= walk_acl(tdbb, acl, view, trg_name, prc_name, pkg_name); privileges |= walk_acl(tdbb, acl, view, obj_type, obj_name);
} }
END_FOR; END_FOR;
@ -1104,9 +1146,8 @@ static SecurityClass::flags_t compute_access(thread_db* tdbb,
static SecurityClass::flags_t walk_acl(thread_db* tdbb, static SecurityClass::flags_t walk_acl(thread_db* tdbb,
const Acl& acl, const Acl& acl,
const jrd_rel* view, const jrd_rel* view,
const Firebird::MetaName& trg_name, SLONG obj_type,
const Firebird::MetaName& prc_name, const Firebird::MetaName& obj_name)
const Firebird::MetaName& pkg_name)
{ {
/************************************** /**************************************
* *
@ -1228,17 +1269,10 @@ static SecurityClass::flags_t walk_acl(thread_db* tdbb,
break; break;
case id_package: case id_package:
if (check_string(a, pkg_name))
hit = false;
break;
case id_procedure: case id_procedure:
if (check_string(a, prc_name))
hit = false;
break;
case id_trigger: case id_trigger:
if (check_string(a, trg_name)) case id_function:
if (c == obj_type && check_string(a, obj_name))
{ {
hit = false; hit = false;
} }

View File

@ -33,41 +33,38 @@
struct dsc; struct dsc;
void SCL_check_access(Jrd::thread_db*, const Jrd::SecurityClass*, SLONG, const Firebird::MetaName&, void SCL_check_access(Jrd::thread_db*, const Jrd::SecurityClass*, SLONG, SLONG, const Firebird::MetaName&,
const Firebird::MetaName&, const Firebird::MetaName&,
Jrd::SecurityClass::flags_t, const TEXT*, const char*); Jrd::SecurityClass::flags_t, const TEXT*, const char*);
void SCL_check_access(Jrd::thread_db*, const Jrd::SecurityClass*, SLONG, const Firebird::MetaName&, void SCL_check_access(Jrd::thread_db*, const Jrd::SecurityClass*, SLONG, SLONG, const Firebird::MetaName&,
const Firebird::MetaName&, const Firebird::MetaName&,
Jrd::SecurityClass::flags_t, const TEXT*, const Firebird::MetaName&, Jrd::SecurityClass::flags_t, const TEXT*, const Firebird::MetaName&,
const Firebird::MetaName&); const Firebird::MetaName&);
inline void SCL_check_access(Jrd::thread_db* tdbb, inline void SCL_check_access(Jrd::thread_db* tdbb,
const Jrd::SecurityClass* s_class, const Jrd::SecurityClass* s_class,
SLONG view_id, SLONG view_id,
const Firebird::MetaName& trg_name, SLONG obj_type,
const Firebird::MetaName& prc_name, const Firebird::MetaName& obj_name,
const Firebird::MetaName& pkg_name,
Jrd::SecurityClass::flags_t mask, Jrd::SecurityClass::flags_t mask,
const TEXT* type, const TEXT* type,
const Firebird::string& name) const Firebird::string& name)
{ {
SCL_check_access(tdbb, s_class, view_id, trg_name, prc_name, pkg_name, mask, type, name.c_str()); SCL_check_access(tdbb, s_class, view_id, obj_type, obj_name, mask, type, name.c_str());
} }
inline void SCL_check_access(Jrd::thread_db* tdbb, inline void SCL_check_access(Jrd::thread_db* tdbb,
const Jrd::SecurityClass* s_class, const Jrd::SecurityClass* s_class,
SLONG view_id, SLONG view_id,
const Firebird::MetaName& trg_name, SLONG obj_type,
const Firebird::MetaName& prc_name, const Firebird::MetaName& obj_name,
const Firebird::MetaName& pkg_name,
Jrd::SecurityClass::flags_t mask, Jrd::SecurityClass::flags_t mask,
const TEXT* type, const TEXT* type,
const Firebird::MetaName& name) const Firebird::MetaName& name)
{ {
SCL_check_access(tdbb, s_class, view_id, trg_name, prc_name, pkg_name, mask, type, name.c_str()); SCL_check_access(tdbb, s_class, view_id, obj_type, obj_name, mask, type, name.c_str());
} }
void SCL_check_index(Jrd::thread_db*, const Firebird::MetaName&, UCHAR, Jrd::SecurityClass::flags_t); void SCL_check_index(Jrd::thread_db*, const Firebird::MetaName&, UCHAR, Jrd::SecurityClass::flags_t);
void SCL_check_package(Jrd::thread_db* tdbb, const dsc*, Jrd::SecurityClass::flags_t); void SCL_check_package(Jrd::thread_db* tdbb, const dsc*, Jrd::SecurityClass::flags_t);
void SCL_check_procedure(Jrd::thread_db* tdbb, const dsc*, Jrd::SecurityClass::flags_t); void SCL_check_procedure(Jrd::thread_db* tdbb, const dsc*, Jrd::SecurityClass::flags_t);
void SCL_check_function(Jrd::thread_db* tdbb, const dsc*, Jrd::SecurityClass::flags_t);
void SCL_check_relation(Jrd::thread_db* tdbb, const dsc*, Jrd::SecurityClass::flags_t); void SCL_check_relation(Jrd::thread_db* tdbb, const dsc*, Jrd::SecurityClass::flags_t);
Jrd::SecurityClass* SCL_get_class(Jrd::thread_db*, const TEXT*); Jrd::SecurityClass* SCL_get_class(Jrd::thread_db*, const TEXT*);
Jrd::SecurityClass::flags_t SCL_get_mask(Jrd::thread_db* tdbb, const TEXT*, const TEXT*); Jrd::SecurityClass::flags_t SCL_get_mask(Jrd::thread_db* tdbb, const TEXT*, const TEXT*);

View File

@ -74,6 +74,7 @@
#include "../common/StatusArg.h" #include "../common/StatusArg.h"
#include "../jrd/trace/TraceManager.h" #include "../jrd/trace/TraceManager.h"
#include "../jrd/trace/TraceJrdHelpers.h" #include "../jrd/trace/TraceJrdHelpers.h"
#include "../jrd/Function.h"
const int DYN_MSG_FAC = 8; const int DYN_MSG_FAC = 8;
@ -1149,6 +1150,9 @@ void TRA_release_transaction(thread_db* tdbb, jrd_tra* transaction)
case Resource::rsc_collation: case Resource::rsc_collation:
rsc->rsc_coll->decUseCount(tdbb); rsc->rsc_coll->decUseCount(tdbb);
break; break;
case Resource::rsc_function:
rsc->rsc_fun->release(tdbb);
break;
default: default:
fb_assert(false); fb_assert(false);
} }

View File

@ -171,53 +171,6 @@ public:
}; };
// Parameter passing mechanism. Also used for returning values, except for scalar_array.
enum FUN_T {
FUN_value,
FUN_reference,
FUN_descriptor,
FUN_blob_struct,
FUN_scalar_array,
FUN_ref_with_null
};
// Function definition block
struct fun_repeat
{
DSC fun_desc; // Datatype info
FUN_T fun_mechanism; // Passing mechanism
};
class UserFunction : public pool_alloc_rpt<fun_repeat, type_fun>
{
public:
Firebird::QualifiedName fun_name; // Function name
Firebird::string fun_exception_message; // message containing the exception error message
int (*fun_entrypoint) (); // Function entrypoint
USHORT fun_count; // Number of arguments (including return)
USHORT fun_args; // Number of input arguments
USHORT fun_return_arg; // Return argument
USHORT fun_type; // Type of function
ULONG fun_temp_length; // Temporary space required
Jrd::ExtEngineManager::Function* fun_external;
fun_repeat fun_rpt[1];
public:
explicit UserFunction(MemoryPool& p)
: fun_name(p),
fun_exception_message(p)
{
}
};
// Those two defines seems an intention to do something that wasn't completed.
// UDfs that return values like now or boolean Udfs. See rdb$functions.rdb$function_type.
//#define FUN_value 0
//#define FUN_boolean 1
// Blob passing structure // Blob passing structure
// CVC: Moved to fun.epp where it belongs. // CVC: Moved to fun.epp where it belongs.
@ -257,6 +210,32 @@ public:
Ods::InternalArrayDesc arr_desc; // Array descriptor. ! Ods::InternalArrayDesc arr_desc; // Array descriptor. !
}; };
// Parameter passing mechanism for UDFs.
// Also used for returning values, except for scalar_array.
enum FUN_T
{
FUN_value,
FUN_reference,
FUN_descriptor,
FUN_blob_struct,
FUN_scalar_array,
FUN_ref_with_null
};
// Blob passing structure
struct udf_blob
{
SSHORT (*blob_get_segment) (blb*, UCHAR*, USHORT, USHORT*);
void* blob_handle;
SLONG blob_number_segments;
SLONG blob_max_segment;
SLONG blob_total_length;
void (*blob_put_segment) (blb*, const UCHAR*, USHORT);
SLONG (*blob_seek) (blb*, USHORT, SLONG);
};
} //namespace Jrd } //namespace Jrd
#endif // JRD_VAL_H #endif // JRD_VAL_H

View File

@ -1284,7 +1284,19 @@ void VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
break; break;
case rel_funs: case rel_funs:
EVL_field (0, rpb->rpb_record, f_fun_name, &desc); EVL_field(0, rpb->rpb_record, f_fun_name, &desc);
if (EVL_field(0, rpb->rpb_record, f_fun_pkg_name, &desc2))
{
MOV_get_metadata_str(&desc2, package_name, sizeof(package_name));
SCL_check_package(tdbb, &desc2, SCL_delete);
}
else
{
package_name[0] = '\0';
SCL_check_function(tdbb, &desc, SCL_delete);
}
DFW_post_work(transaction, dfw_delete_udf, &desc, 0); DFW_post_work(transaction, dfw_delete_udf, &desc, 0);
break; break;
@ -1358,6 +1370,20 @@ void VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
DFW_post_work(transaction, dfw_delete_global, &desc2, 0); DFW_post_work(transaction, dfw_delete_global, &desc2, 0);
break; break;
case rel_args:
if (EVL_field(0, rpb->rpb_record, f_arg_pkg_name, &desc2))
{
MOV_get_metadata_str(&desc2, package_name, sizeof(package_name));
SCL_check_package(tdbb, &desc2, SCL_control);
}
else
{
EVL_field(0, rpb->rpb_record, f_arg_fun_name, &desc);
package_name[0] = '\0';
SCL_check_function(tdbb, &desc, SCL_control);
}
break;
case rel_prc_prms: case rel_prc_prms:
EVL_field(0, rpb->rpb_record, f_prm_procedure, &desc); EVL_field(0, rpb->rpb_record, f_prm_procedure, &desc);
@ -2250,6 +2276,30 @@ void VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j
} // scope } // scope
break; break;
case rel_funs:
EVL_field(0, org_rpb->rpb_record, f_fun_name, &desc1);
{ // scope
SqlIdentifier package_name;
if (EVL_field(0, org_rpb->rpb_record, f_fun_pkg_name, &desc2))
{
MOV_get_metadata_str(&desc2, package_name, sizeof(package_name));
SCL_check_package(tdbb, &desc2, SCL_protect);
}
else
{
package_name[0] = '\0';
SCL_check_function(tdbb, &desc1, SCL_protect);
}
check_class(tdbb, transaction, org_rpb, new_rpb, f_fun_class);
EVL_field(0, org_rpb->rpb_record, f_prc_id, &desc2);
const USHORT id = MOV_get_long(&desc2, 0);
DFW_post_work(transaction, dfw_modify_procedure, &desc1, id, package_name);
} // scope
break;
case rel_gens: case rel_gens:
{ {
EVL_field (0, org_rpb->rpb_record, f_gen_name, &desc1); EVL_field (0, org_rpb->rpb_record, f_gen_name, &desc1);
@ -3373,7 +3423,7 @@ static void check_rel_field_class(thread_db* tdbb,
// he may have access to relation as whole. // he may have access to relation as whole.
try try
{ {
SCL_check_access(tdbb, s_class, 0, NULL, NULL, NULL, flags, "", ""); SCL_check_access(tdbb, s_class, 0, 0, NULL, flags, "", "");
} }
catch (const Firebird::Exception&) catch (const Firebird::Exception&)
{ {
@ -3415,7 +3465,7 @@ static void check_class(thread_db* tdbb,
Jrd::Attachment* attachment = tdbb->getAttachment(); Jrd::Attachment* attachment = tdbb->getAttachment();
SCL_check_access(tdbb, attachment->att_security_class, 0, NULL, NULL, NULL, SCL_protect, SCL_check_access(tdbb, attachment->att_security_class, 0, 0, NULL, SCL_protect,
"DATABASE", NULL); "DATABASE", NULL);
DFW_post_work(transaction, dfw_compute_security, &desc2, 0); DFW_post_work(transaction, dfw_compute_security, &desc2, 0);
} }
@ -3438,7 +3488,7 @@ static void check_control(thread_db* tdbb)
Jrd::Attachment* attachment = tdbb->getAttachment(); Jrd::Attachment* attachment = tdbb->getAttachment();
SCL_check_access(tdbb, attachment->att_security_class, 0, NULL, NULL, NULL, SCL_control, SCL_check_access(tdbb, attachment->att_security_class, 0, 0, NULL, SCL_control,
"DATABASE", NULL); "DATABASE", NULL);
} }