mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-23 19:23:03 +01:00
Support for PSQL functions (other JRD changes). Still work in progress.
This commit is contained in:
parent
34d21655d1
commit
debe65bcfb
@ -455,8 +455,7 @@ public:
|
||||
vcl* dbb_pc_transactions; // active precommitted transactions
|
||||
BackupManager* dbb_backup_manager; // physical backup manager
|
||||
Firebird::TimeStamp dbb_creation_date; // creation date
|
||||
Firebird::GenericMap<Firebird::Pair<Firebird::Left<
|
||||
Firebird::QualifiedName, UserFunction*> > > dbb_functions; // User defined functions
|
||||
Firebird::Array<Function*> dbb_functions; // User defined functions
|
||||
Firebird::GenericMap<Firebird::Pair<Firebird::Left<
|
||||
Firebird::MetaName, USHORT> > > dbb_charset_ids; // Character set ids
|
||||
|
||||
|
@ -49,6 +49,7 @@
|
||||
#include "../jrd/Relation.h"
|
||||
#include "../jrd/RecordBuffer.h"
|
||||
#include "../jrd/DatabaseSnapshot.h"
|
||||
#include "../jrd/Function.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.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())
|
||||
{
|
||||
record.storeString(f_mon_call_name, request->req_trg_name);
|
||||
|
@ -44,6 +44,7 @@
|
||||
#include "../jrd/met_proto.h"
|
||||
#include "../jrd/mov_proto.h"
|
||||
#include "../jrd/thread_proto.h"
|
||||
#include "../jrd/Function.h"
|
||||
#include "../common/classes/auto.h"
|
||||
#include "../common/classes/fb_string.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,
|
||||
ExternalEngine* aEngine, Firebird::ExternalFunction* aFunction,
|
||||
const UserFunction* aUdf)
|
||||
const Jrd::Function* aUdf)
|
||||
: extManager(aExtManager),
|
||||
engine(aEngine),
|
||||
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)
|
||||
{
|
||||
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())
|
||||
{
|
||||
@ -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::string& body)
|
||||
{
|
||||
|
@ -44,7 +44,7 @@ class Attachment;
|
||||
class Database;
|
||||
class Format;
|
||||
class Trigger;
|
||||
class UserFunction;
|
||||
class Function;
|
||||
class ValueImpl;
|
||||
class ValuesImpl;
|
||||
struct impure_value;
|
||||
@ -127,7 +127,7 @@ public:
|
||||
Function(thread_db* tdbb, ExtEngineManager* aExtManager,
|
||||
Firebird::ExternalEngine* aEngine,
|
||||
Firebird::ExternalFunction* aFunction,
|
||||
const UserFunction* aUdf);
|
||||
const Jrd::Function* aUdf);
|
||||
~Function();
|
||||
|
||||
void execute(thread_db* tdbb, jrd_nod* args, impure_value* impure);
|
||||
@ -136,7 +136,7 @@ public:
|
||||
ExtEngineManager* extManager;
|
||||
Firebird::ExternalEngine* engine;
|
||||
Firebird::ExternalFunction* function;
|
||||
const UserFunction* udf;
|
||||
const Jrd::Function* udf;
|
||||
Database* database;
|
||||
};
|
||||
|
||||
@ -221,7 +221,7 @@ public:
|
||||
public:
|
||||
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::string& body);
|
||||
Procedure* makeProcedure(thread_db* tdbb, const jrd_prc* prc,
|
||||
|
206
src/jrd/cmp.cpp
206
src/jrd/cmp.cpp
@ -59,6 +59,7 @@
|
||||
#include "../jrd/intl.h"
|
||||
#include "../jrd/btr.h"
|
||||
#include "../jrd/sort.h"
|
||||
#include "../jrd/acl.h"
|
||||
#include "../jrd/gdsassert.h"
|
||||
#include "../jrd/cmp_proto.h"
|
||||
#include "../jrd/dsc_proto.h"
|
||||
@ -94,6 +95,7 @@
|
||||
#include "../jrd/ValuesImpl.h"
|
||||
#include "../jrd/recsrc/RecordSource.h"
|
||||
#include "../jrd/recsrc/Cursor.h"
|
||||
#include "../jrd/Function.h"
|
||||
|
||||
using Firebird::AutoSetRestore;
|
||||
|
||||
@ -299,9 +301,15 @@ static void build_external_access(thread_db* tdbb, ExternalAccessList& list, jrd
|
||||
// Add externals recursively
|
||||
if (item->exa_action == ExternalAccess::exa_procedure)
|
||||
{
|
||||
jrd_prc* prc = MET_lookup_procedure_id(tdbb, item->exa_prc_id, false, false, 0);
|
||||
if (prc && prc->prc_request)
|
||||
build_external_access(tdbb, list, prc->prc_request);
|
||||
jrd_prc* const procedure = MET_lookup_procedure_id(tdbb, item->exa_prc_id, false, false, 0);
|
||||
if (procedure && procedure->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
|
||||
{
|
||||
@ -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());
|
||||
SCL_check_access(tdbb, sec_class,
|
||||
(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);
|
||||
}
|
||||
}
|
||||
@ -425,26 +433,56 @@ void CMP_verify_access(thread_db* tdbb, jrd_req* request)
|
||||
{
|
||||
if (item->exa_action == ExternalAccess::exa_procedure)
|
||||
{
|
||||
jrd_prc* prc = MET_lookup_procedure_id(tdbb, item->exa_prc_id, false, false, 0);
|
||||
if (!prc->prc_request)
|
||||
jrd_prc* const procedure = MET_lookup_procedure_id(tdbb, item->exa_prc_id, false, false, 0);
|
||||
if (!procedure->prc_request)
|
||||
continue;
|
||||
|
||||
for (const AccessItem* access = prc->prc_request->req_access.begin();
|
||||
access < prc->prc_request->req_access.end();
|
||||
for (const AccessItem* access = procedure->prc_request->req_access.begin();
|
||||
access < procedure->prc_request->req_access.end();
|
||||
access++)
|
||||
{
|
||||
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,
|
||||
prc->prc_name.identifier, NULL, access->acc_mask, access->acc_type,
|
||||
SCL_check_access(tdbb, sec_class, access->acc_view_id,
|
||||
id_procedure, procedure->prc_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, NULL,
|
||||
NULL, prc->prc_name.qualifier, access->acc_mask, access->acc_type,
|
||||
SCL_check_access(tdbb, sec_class, access->acc_view_id,
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -474,7 +512,7 @@ void CMP_verify_access(thread_db* tdbb, jrd_req* request)
|
||||
verify_trigger_access(tdbb, relation, relation->rel_post_erase, view);
|
||||
break;
|
||||
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());
|
||||
|
||||
Firebird::MetaName trgName(
|
||||
useCallerPrivs && transaction->tra_caller_name.type == obj_trigger ?
|
||||
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);
|
||||
Firebird::MetaName objName;
|
||||
SLONG objType = 0;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -544,26 +597,48 @@ jrd_req* CMP_clone_request(thread_db* tdbb, jrd_req* request, USHORT level, bool
|
||||
return clone;
|
||||
}
|
||||
|
||||
if (validate) {
|
||||
jrd_prc* procedure = request->req_procedure;
|
||||
if (validate)
|
||||
{
|
||||
jrd_prc* const procedure = request->req_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);
|
||||
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())
|
||||
{
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
@ -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_trg_name = request->req_trg_name;
|
||||
clone->req_procedure = request->req_procedure;
|
||||
clone->req_function = request->req_function;
|
||||
clone->req_flags = request->req_flags & REQ_FLAGS_CLONE_MASK;
|
||||
clone->req_last_xcp = request->req_last_xcp;
|
||||
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:
|
||||
{
|
||||
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
|
||||
// looked up during parsing the blr. This is true if the function
|
||||
// referenced in the procedure blr was dropped before dropping the
|
||||
// looked up during parsing the BLR. This is true if the function
|
||||
// referenced in the procedure BLR was dropped before dropping the
|
||||
// procedure itself. Ignore the case because we are currently trying
|
||||
// to drop the procedure.
|
||||
// For normal requests, function would never be null. We would have
|
||||
// created a valid block while parsing in par_function/par.c.
|
||||
if (function) {
|
||||
*desc = function->fun_rpt[function->fun_return_arg].fun_desc;
|
||||
if (function)
|
||||
{
|
||||
*desc = function->fun_args[function->fun_return_arg].fun_parameter->prm_desc;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -2266,6 +2343,9 @@ jrd_req* CMP_make_request(thread_db* tdbb, CompilerScratch* csb, bool internal_f
|
||||
coll->incUseCount(tdbb);
|
||||
break;
|
||||
}
|
||||
case Resource::rsc_function:
|
||||
resource->rsc_fun->addRef();
|
||||
break;
|
||||
default:
|
||||
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:
|
||||
resource.rsc_coll = (Collation*) obj;
|
||||
break;
|
||||
case Resource::rsc_function:
|
||||
resource.rsc_fun = (Function*) obj;
|
||||
break;
|
||||
default:
|
||||
BUGCHECK(220); // msg 220 unknown resource
|
||||
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
|
||||
// floating copy, i.e. an old copy or a deleted procedure.
|
||||
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)
|
||||
{
|
||||
@ -2521,6 +2604,9 @@ void CMP_release(thread_db* tdbb, jrd_req* request)
|
||||
coll->decUseCount(tdbb);
|
||||
break;
|
||||
}
|
||||
case Resource::rsc_function:
|
||||
resource->rsc_fun->release(tdbb);
|
||||
break;
|
||||
default:
|
||||
BUGCHECK(220); // msg 220 release of unknown resource
|
||||
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
|
||||
|
||||
dbb->releaseIntlObjects();
|
||||
@ -4096,6 +4195,39 @@ jrd_nod* CMP_pass1(thread_db* tdbb, CompilerScratch* csb, jrd_nod* node)
|
||||
Resource::rsc_procedure, procedure->prc_id);
|
||||
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:
|
||||
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
|
||||
ExternalAccess temp(procedure->prc_id);
|
||||
ExternalAccess temp(ExternalAccess::exa_procedure, procedure->prc_id);
|
||||
size_t idx;
|
||||
if (!csb->csb_external.find(temp, idx))
|
||||
csb->csb_external.insert(idx, temp);
|
||||
|
@ -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 UserId[] = { "USER IDENTIFICATION 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 AccessItem[] = { "ACCESS", 0};
|
||||
static TEXT_PTR Resource[] = { "RESOURCE", 0};
|
||||
|
@ -2650,8 +2650,6 @@ static bool create_procedure(thread_db* tdbb, SSHORT phase, DeferredWork* work,
|
||||
if (!procedure) {
|
||||
return false;
|
||||
}
|
||||
// Never used.
|
||||
procedure->prc_flags |= PRC_create;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -115,6 +115,7 @@
|
||||
#include "../jrd/recsrc/RecordSource.h"
|
||||
#include "../jrd/recsrc/Cursor.h"
|
||||
#include "../common/classes/Aligner.h"
|
||||
#include "../jrd/Function.h"
|
||||
|
||||
const int TEMP_LENGTH = 128;
|
||||
|
||||
@ -930,9 +931,10 @@ dsc* EVL_expr(thread_db* tdbb, jrd_nod* const node)
|
||||
}
|
||||
|
||||
case nod_function:
|
||||
FUN_evaluate(tdbb, reinterpret_cast<UserFunction*>(node->nod_arg[e_fun_function]),
|
||||
node->nod_arg[e_fun_args], impure);
|
||||
return &impure->vlu_desc;
|
||||
{
|
||||
Function* const function = reinterpret_cast<Function*>(node->nod_arg[e_fun_function]);
|
||||
return function->execute(tdbb, node->nod_arg[e_fun_args], impure);
|
||||
}
|
||||
|
||||
case nod_sys_function:
|
||||
{
|
||||
|
@ -110,6 +110,7 @@
|
||||
#include "../jrd/ValuesImpl.h"
|
||||
#include "../jrd/recsrc/RecordSource.h"
|
||||
#include "../jrd/recsrc/Cursor.h"
|
||||
#include "../jrd/Function.h"
|
||||
|
||||
|
||||
using namespace Jrd;
|
||||
@ -751,7 +752,9 @@ void EXE_receive(thread_db* tdbb,
|
||||
const bool external = request->req_procedure && request->req_procedure->prc_external;
|
||||
|
||||
if (external)
|
||||
{
|
||||
execute_looper(tdbb, request, transaction, jrd_req::req_sync);
|
||||
}
|
||||
else
|
||||
{
|
||||
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 += 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())
|
||||
{
|
||||
|
@ -499,14 +499,16 @@ struct Resource
|
||||
rsc_relation,
|
||||
rsc_procedure,
|
||||
rsc_index,
|
||||
rsc_collation
|
||||
rsc_collation,
|
||||
rsc_function
|
||||
};
|
||||
|
||||
enum rsc_s rsc_type;
|
||||
USHORT rsc_id; // Id of the resource
|
||||
jrd_rel* rsc_rel; // Relation block
|
||||
jrd_prc* rsc_prc; // Procedure block
|
||||
Collation* rsc_coll; // Collation block
|
||||
USHORT rsc_id; // Id of the resource
|
||||
jrd_rel* rsc_rel; // Relation block
|
||||
jrd_prc* rsc_prc; // Procedure block
|
||||
Collation* rsc_coll; // Collation block
|
||||
Function* rsc_fun; // Function block
|
||||
|
||||
static bool greaterThan(const Resource& i1, const Resource& i2)
|
||||
{
|
||||
@ -586,23 +588,29 @@ struct ExternalAccess
|
||||
enum exa_act
|
||||
{
|
||||
exa_procedure,
|
||||
exa_function,
|
||||
exa_insert,
|
||||
exa_update,
|
||||
exa_delete
|
||||
};
|
||||
exa_act exa_action;
|
||||
USHORT exa_prc_id;
|
||||
USHORT exa_fun_id;
|
||||
USHORT exa_rel_id;
|
||||
USHORT exa_view_id;
|
||||
|
||||
// Procedure
|
||||
ExternalAccess(USHORT prc_id) :
|
||||
exa_action(exa_procedure), exa_prc_id(prc_id), exa_rel_id(0), exa_view_id(0)
|
||||
ExternalAccess(exa_act action, USHORT id) :
|
||||
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
|
||||
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)
|
||||
@ -611,6 +619,8 @@ struct ExternalAccess
|
||||
return i1.exa_action > i2.exa_action;
|
||||
if (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)
|
||||
return i1.exa_rel_id > i2.exa_rel_id;
|
||||
if (i1.exa_view_id != i2.exa_view_id)
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include "../mov_proto.h"
|
||||
#include "../mov_proto.h"
|
||||
#include "../PreparedStatement.h"
|
||||
#include "../Function.h"
|
||||
|
||||
#include "InternalDS.h"
|
||||
|
||||
@ -363,6 +364,14 @@ void InternalStatement::doPrepare(thread_db* tdbb, const string& sql)
|
||||
else
|
||||
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
|
||||
tran->tra_caller_name = CallerName();
|
||||
}
|
||||
|
215
src/jrd/fun.epp
215
src/jrd/fun.epp
@ -64,6 +64,7 @@
|
||||
#include "../common/classes/auto.h"
|
||||
#include "../common/utils_proto.h"
|
||||
#include "../common/classes/FpeControl.h"
|
||||
#include "../jrd/Function.h"
|
||||
|
||||
#ifdef WIN_NT
|
||||
#define LIBNAME "ib_util"
|
||||
@ -211,23 +212,6 @@ T CALL_UDF(Database* dbb, int (*entrypoint)(), UDF_ARG* args)
|
||||
|
||||
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*>
|
||||
{
|
||||
public:
|
||||
@ -304,7 +288,7 @@ static void blob_put_segment(blb*, const UCHAR*, USHORT);
|
||||
static SLONG blob_lseek(blb*, USHORT, SLONG);
|
||||
static SLONG get_scalar_array(fun_repeat*, DSC*, scalar_array_desc*, UCharStack&);
|
||||
static void invoke(thread_db* tdbb,
|
||||
UserFunction* function,
|
||||
Function* function,
|
||||
fun_repeat* return_ptr,
|
||||
impure_value* value,
|
||||
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);
|
||||
|
||||
|
||||
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);
|
||||
|
||||
fun_repeat* return_ptr = function->fun_rpt + function->fun_return_arg;
|
||||
value->vlu_desc = return_ptr->fun_desc;
|
||||
value->vlu_desc.dsc_address = (UCHAR *) & value->vlu_misc;
|
||||
|
||||
UCharStack array_stack;
|
||||
fun_repeat* return_ptr = &function->fun_args[function->fun_return_arg];
|
||||
|
||||
jrd_req* request = tdbb->getRequest();
|
||||
// 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
|
||||
// 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
|
||||
|
||||
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];
|
||||
HalfStaticArray<UCHAR, 800> temp;
|
||||
|
||||
@ -403,8 +358,8 @@ void FUN_evaluate(thread_db* tdbb, UserFunction* function, jrd_nod* node, impure
|
||||
double d;
|
||||
|
||||
// Process arguments
|
||||
const fun_repeat* const end = function->fun_rpt + 1 + function->fun_count;
|
||||
for (fun_repeat* tail = function->fun_rpt + 1; tail < end; ++tail)
|
||||
const fun_repeat* const end = function->fun_args.end();
|
||||
for (fun_repeat* tail = function->fun_args.begin() + 1; tail < end; ++tail)
|
||||
{
|
||||
DSC* input;
|
||||
if (tail == return_ptr)
|
||||
@ -441,7 +396,7 @@ void FUN_evaluate(thread_db* tdbb, UserFunction* function, jrd_nod* node, impure
|
||||
continue;
|
||||
}
|
||||
|
||||
temp_desc = tail->fun_desc;
|
||||
temp_desc = tail->fun_parameter->prm_desc;
|
||||
temp_desc.dsc_address = temp_ptr;
|
||||
// CVC: There's a theoretical possibility of overflowing "length" here.
|
||||
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;
|
||||
}
|
||||
|
||||
if (tail->fun_desc.dsc_dtype == dtype_blob)
|
||||
if (tail->fun_parameter->prm_desc.dsc_dtype == dtype_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
|
||||
// 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_array:
|
||||
@ -491,11 +446,11 @@ void FUN_evaluate(thread_db* tdbb, UserFunction* function, jrd_nod* node, impure
|
||||
{
|
||||
SLONG l;
|
||||
SLONG* lp;
|
||||
switch (tail->fun_desc.dsc_dtype)
|
||||
switch (tail->fun_parameter->prm_desc.dsc_dtype)
|
||||
{
|
||||
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)
|
||||
{
|
||||
// For (apparent) portability reasons, SHORT by value
|
||||
@ -514,7 +469,7 @@ void FUN_evaluate(thread_db* tdbb, UserFunction* function, jrd_nod* node, impure
|
||||
break;
|
||||
|
||||
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)
|
||||
{
|
||||
*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:
|
||||
{
|
||||
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)
|
||||
{
|
||||
@ -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)
|
||||
{
|
||||
/**************************************
|
||||
@ -1005,7 +828,7 @@ static SLONG get_scalar_array(fun_repeat* arg,
|
||||
|
||||
// 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;
|
||||
|
||||
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
|
||||
|
||||
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_dimensions = dimensions;
|
||||
|
||||
@ -1057,7 +880,7 @@ static SLONG get_scalar_array(fun_repeat* arg,
|
||||
|
||||
|
||||
static void invoke(thread_db* tdbb,
|
||||
UserFunction* function,
|
||||
Function* function,
|
||||
fun_repeat* return_ptr,
|
||||
impure_value* value,
|
||||
UDF_ARG* args,
|
||||
|
@ -39,7 +39,6 @@ public:
|
||||
};
|
||||
|
||||
|
||||
void FUN_evaluate(Jrd::thread_db*, Jrd::UserFunction*, Jrd::jrd_nod*, Jrd::impure_value*);
|
||||
Jrd::UserFunction* FUN_lookup_function(Jrd::thread_db*, const Firebird::QualifiedName&);
|
||||
void FUN_evaluate(Jrd::thread_db*, Jrd::Function*, Jrd::jrd_nod*, Jrd::impure_value*);
|
||||
|
||||
#endif // JRD_FUN_PROTO_H
|
||||
|
@ -429,7 +429,6 @@ public:
|
||||
USHORT prc_inputs;
|
||||
USHORT prc_defaults;
|
||||
USHORT prc_outputs;
|
||||
//jrd_nod* prc_input_msg; // It's set once by met.epp and never used.
|
||||
jrd_nod* prc_output_msg;
|
||||
Format* prc_input_fmt;
|
||||
Format* prc_output_fmt;
|
||||
@ -458,17 +457,14 @@ public:
|
||||
// prc_flags
|
||||
|
||||
const USHORT PRC_scanned = 1; // Field expressions scanned
|
||||
const USHORT PRC_system = 2; // Set in met.epp, never tested.
|
||||
const USHORT PRC_obsolete = 4; // Procedure known gonzo
|
||||
const USHORT PRC_being_scanned = 8; // New procedure needs dependencies during scan
|
||||
//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
|
||||
const USHORT PRC_obsolete = 2; // Procedure known gonzo
|
||||
const USHORT PRC_being_scanned = 4; // New procedure needs dependencies during scan
|
||||
const USHORT PRC_being_altered = 8; // Procedure is getting altered
|
||||
// This flag is used to make sure that MET_remove_procedure
|
||||
// does not delete and remove procedure block from cache
|
||||
// so dfw.epp:modify_procedure() can flip procedure body without
|
||||
// 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
|
||||
|
||||
|
@ -92,6 +92,7 @@
|
||||
#include "../jrd/PreparedStatement.h"
|
||||
#include "../jrd/DebugInterface.h"
|
||||
#include "../common/classes/MsgPrint.h"
|
||||
#include "../jrd/Function.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 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_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 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*,
|
||||
@ -3153,14 +3154,6 @@ jrd_prc* MET_procedure(thread_db* tdbb, int id, bool noscan, USHORT flags)
|
||||
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) )
|
||||
{
|
||||
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;
|
||||
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)
|
||||
{
|
||||
procedure->prc_output_msg = node;
|
||||
@ -4629,7 +4614,9 @@ static void gen_ext_message(Firebird::UCharBuffer& blr, UCHAR message,
|
||||
blr.add(blr_not_nullable);
|
||||
|
||||
if (parameter->prm_mechanism == prm_mech_type_of)
|
||||
{
|
||||
PreparedStatement::generateBlr(¶meter->prm_desc, blr);
|
||||
}
|
||||
else
|
||||
{
|
||||
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,
|
||||
jrd_prc* procedure,
|
||||
bid* blob_id,
|
||||
CompilerScratch* csb,
|
||||
bool external)
|
||||
static void parse_procedure_blr(thread_db* tdbb,
|
||||
jrd_prc* procedure,
|
||||
bid* blob_id,
|
||||
CompilerScratch* csb,
|
||||
bool external)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
@ -4675,7 +4662,7 @@ static jrd_nod* parse_procedure_blr(thread_db* tdbb,
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Parse blr, returning a compiler scratch block with the results.
|
||||
* Parse procedure BLR.
|
||||
*
|
||||
**************************************/
|
||||
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);
|
||||
|
||||
return PAR_blr(tdbb, NULL, tmp.begin(), (ULONG) tmp.getCount(), NULL, &csb,
|
||||
&procedure->prc_request, false, 0);
|
||||
PAR_blr(tdbb, NULL, tmp.begin(), (ULONG) tmp.getCount(), NULL, &csb,
|
||||
&procedure->prc_request, false, 0);
|
||||
}
|
||||
|
||||
|
||||
@ -4826,8 +4813,7 @@ static void par_messages(thread_db* tdbb,
|
||||
|
||||
if (offset > MAX_FORMAT_SIZE)
|
||||
{
|
||||
ERR_post(Arg::Gds(isc_imp_exc) <<
|
||||
Arg::Gds(isc_blktoobig));
|
||||
ERR_post(Arg::Gds(isc_imp_exc) << Arg::Gds(isc_blktoobig));
|
||||
}
|
||||
|
||||
format->fmt_length = (USHORT) offset;
|
||||
@ -5245,7 +5231,7 @@ static void store_dependencies(thread_db* tdbb,
|
||||
break;
|
||||
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;
|
||||
packageName = udf->fun_name.qualifier;
|
||||
}
|
||||
|
@ -64,6 +64,7 @@
|
||||
#include "../common/utils_proto.h"
|
||||
#include "../jrd/SysFunction.h"
|
||||
#include "../jrd/BlrReader.h"
|
||||
#include "../jrd/Function.h"
|
||||
|
||||
using namespace Jrd;
|
||||
using namespace Firebird;
|
||||
@ -1463,9 +1464,8 @@ static jrd_nod* par_function(thread_db* tdbb, CompilerScratch* csb, SSHORT blr_o
|
||||
return node;
|
||||
}
|
||||
|
||||
// Isn't it strange that gbak presence means nothing to this function now?
|
||||
UserFunction* function =
|
||||
FUN_lookup_function(tdbb, name); //, !(tdbb->getAttachment()->att_flags & ATT_gbak_attachment));
|
||||
Function* const function = Function::lookup(tdbb, name, false);
|
||||
|
||||
if (!function)
|
||||
{
|
||||
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()));
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
@ -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);
|
||||
|
||||
// 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()));
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
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_arg [e_dep_object] = (jrd_nod*) function;
|
||||
dep_node->nod_arg [e_dep_object_type] = (jrd_nod*)(IPTR) obj_udf;
|
||||
|
@ -231,6 +231,7 @@ public:
|
||||
ResourceList req_resources; // Resources (relations and indices)
|
||||
jrd_nod* req_message; // Current message for send/receive
|
||||
jrd_prc* req_procedure; // procedure, if any
|
||||
Function* req_function; // function, 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)
|
||||
|
108
src/jrd/scl.epp
108
src/jrd/scl.epp
@ -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_string(const UCHAR*, const Firebird::MetaName&);
|
||||
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*,
|
||||
const Firebird::MetaName&, const Firebird::MetaName&, const Firebird::MetaName&);
|
||||
SLONG, const Firebird::MetaName&);
|
||||
|
||||
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,
|
||||
const SecurityClass* s_class,
|
||||
SLONG view_id,
|
||||
const Firebird::MetaName& trg_name,
|
||||
const Firebird::MetaName& prc_name,
|
||||
const Firebird::MetaName& pkg_name,
|
||||
SLONG obj_type,
|
||||
const Firebird::MetaName& obj_name,
|
||||
SecurityClass::flags_t mask,
|
||||
const TEXT* type,
|
||||
const char* name)
|
||||
@ -170,8 +169,8 @@ void SCL_check_access(thread_db* tdbb,
|
||||
if (view_id) {
|
||||
view = MET_lookup_relation_id(tdbb, view_id, false);
|
||||
}
|
||||
if ((view || trg_name.hasData() || prc_name.hasData() || pkg_name.hasData()) &&
|
||||
(compute_access(tdbb, s_class, view, trg_name, prc_name, pkg_name) & mask))
|
||||
if ((view || obj_name.hasData()) &&
|
||||
(compute_access(tdbb, s_class, view, obj_type, obj_name) & mask))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -204,9 +203,8 @@ void SCL_check_access(thread_db* tdbb,
|
||||
void SCL_check_access(thread_db* tdbb,
|
||||
const SecurityClass* s_class,
|
||||
SLONG view_id,
|
||||
const Firebird::MetaName& trg_name,
|
||||
const Firebird::MetaName& prc_name,
|
||||
const Firebird::MetaName& pkg_name,
|
||||
SLONG obj_type,
|
||||
const Firebird::MetaName& obj_name,
|
||||
SecurityClass::flags_t mask,
|
||||
const TEXT* type,
|
||||
const Firebird::MetaName& name,
|
||||
@ -234,8 +232,8 @@ void SCL_check_access(thread_db* tdbb,
|
||||
fullFieldName += name.c_str();
|
||||
}
|
||||
|
||||
SCL_check_access(tdbb, s_class, view_id, trg_name, prc_name, pkg_name, mask, type,
|
||||
fullFieldName.c_str());
|
||||
SCL_check_access(tdbb, s_class, view_id, obj_type, obj_name, mask, type,
|
||||
fullFieldName.c_str());
|
||||
}
|
||||
|
||||
|
||||
@ -322,7 +320,7 @@ void SCL_check_index(thread_db* tdbb, const Firebird::MetaName& index_name, UCHA
|
||||
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;
|
||||
|
||||
@ -352,12 +350,12 @@ void SCL_check_index(thread_db* tdbb, const Firebird::MetaName& index_name, UCHA
|
||||
if (!RF.RDB$SECURITY_CLASS.NULL)
|
||||
{
|
||||
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
|
||||
{
|
||||
SCL_check_access(tdbb, default_s_class, 0, NULL, NULL, NULL, mask, object_column,
|
||||
fullFieldName);
|
||||
SCL_check_access(tdbb, default_s_class, 0, 0, NULL, mask, object_column,
|
||||
fullFieldName);
|
||||
}
|
||||
|
||||
END_FOR;
|
||||
@ -414,7 +412,7 @@ void SCL_check_package(thread_db* tdbb, const dsc* dsc_name, SecurityClass::flag
|
||||
if (!REQUEST(irq_pkg_security))
|
||||
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))
|
||||
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))
|
||||
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;
|
||||
|
||||
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)
|
||||
{
|
||||
@ -844,7 +887,7 @@ SecurityClass* SCL_recompute_class(thread_db* tdbb, const TEXT* string)
|
||||
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) {
|
||||
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,
|
||||
const SecurityClass* s_class,
|
||||
const jrd_rel* view,
|
||||
const Firebird::MetaName& trg_name,
|
||||
const Firebird::MetaName& prc_name,
|
||||
const Firebird::MetaName& pkg_name)
|
||||
SLONG obj_type,
|
||||
const Firebird::MetaName& obj_name)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
@ -1090,7 +1132,7 @@ static SecurityClass::flags_t compute_access(thread_db* tdbb,
|
||||
|
||||
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;
|
||||
|
||||
@ -1104,9 +1146,8 @@ static SecurityClass::flags_t compute_access(thread_db* tdbb,
|
||||
static SecurityClass::flags_t walk_acl(thread_db* tdbb,
|
||||
const Acl& acl,
|
||||
const jrd_rel* view,
|
||||
const Firebird::MetaName& trg_name,
|
||||
const Firebird::MetaName& prc_name,
|
||||
const Firebird::MetaName& pkg_name)
|
||||
SLONG obj_type,
|
||||
const Firebird::MetaName& obj_name)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
@ -1228,17 +1269,10 @@ static SecurityClass::flags_t walk_acl(thread_db* tdbb,
|
||||
break;
|
||||
|
||||
case id_package:
|
||||
if (check_string(a, pkg_name))
|
||||
hit = false;
|
||||
break;
|
||||
|
||||
case id_procedure:
|
||||
if (check_string(a, prc_name))
|
||||
hit = false;
|
||||
break;
|
||||
|
||||
case id_trigger:
|
||||
if (check_string(a, trg_name))
|
||||
case id_function:
|
||||
if (c == obj_type && check_string(a, obj_name))
|
||||
{
|
||||
hit = false;
|
||||
}
|
||||
|
@ -33,41 +33,38 @@
|
||||
|
||||
struct dsc;
|
||||
|
||||
void SCL_check_access(Jrd::thread_db*, const Jrd::SecurityClass*, SLONG, const Firebird::MetaName&,
|
||||
const Firebird::MetaName&, const Firebird::MetaName&,
|
||||
void SCL_check_access(Jrd::thread_db*, const Jrd::SecurityClass*, SLONG, SLONG, const Firebird::MetaName&,
|
||||
Jrd::SecurityClass::flags_t, const TEXT*, const char*);
|
||||
void SCL_check_access(Jrd::thread_db*, const Jrd::SecurityClass*, SLONG, const Firebird::MetaName&,
|
||||
const Firebird::MetaName&, const Firebird::MetaName&,
|
||||
void SCL_check_access(Jrd::thread_db*, const Jrd::SecurityClass*, SLONG, SLONG, const Firebird::MetaName&,
|
||||
Jrd::SecurityClass::flags_t, const TEXT*, const Firebird::MetaName&,
|
||||
const Firebird::MetaName&);
|
||||
inline void SCL_check_access(Jrd::thread_db* tdbb,
|
||||
const Jrd::SecurityClass* s_class,
|
||||
SLONG view_id,
|
||||
const Firebird::MetaName& trg_name,
|
||||
const Firebird::MetaName& prc_name,
|
||||
const Firebird::MetaName& pkg_name,
|
||||
SLONG obj_type,
|
||||
const Firebird::MetaName& obj_name,
|
||||
Jrd::SecurityClass::flags_t mask,
|
||||
const TEXT* type,
|
||||
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,
|
||||
const Jrd::SecurityClass* s_class,
|
||||
SLONG view_id,
|
||||
const Firebird::MetaName& trg_name,
|
||||
const Firebird::MetaName& prc_name,
|
||||
const Firebird::MetaName& pkg_name,
|
||||
SLONG obj_type,
|
||||
const Firebird::MetaName& obj_name,
|
||||
Jrd::SecurityClass::flags_t mask,
|
||||
const TEXT* type,
|
||||
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_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_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);
|
||||
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*);
|
||||
|
@ -74,6 +74,7 @@
|
||||
#include "../common/StatusArg.h"
|
||||
#include "../jrd/trace/TraceManager.h"
|
||||
#include "../jrd/trace/TraceJrdHelpers.h"
|
||||
#include "../jrd/Function.h"
|
||||
|
||||
|
||||
const int DYN_MSG_FAC = 8;
|
||||
@ -1149,6 +1150,9 @@ void TRA_release_transaction(thread_db* tdbb, jrd_tra* transaction)
|
||||
case Resource::rsc_collation:
|
||||
rsc->rsc_coll->decUseCount(tdbb);
|
||||
break;
|
||||
case Resource::rsc_function:
|
||||
rsc->rsc_fun->release(tdbb);
|
||||
break;
|
||||
default:
|
||||
fb_assert(false);
|
||||
}
|
||||
|
@ -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
|
||||
// CVC: Moved to fun.epp where it belongs.
|
||||
|
||||
@ -257,6 +210,32 @@ public:
|
||||
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
|
||||
|
||||
#endif // JRD_VAL_H
|
||||
|
@ -1284,7 +1284,19 @@ void VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
|
||||
break;
|
||||
|
||||
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);
|
||||
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);
|
||||
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:
|
||||
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
|
||||
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:
|
||||
{
|
||||
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.
|
||||
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&)
|
||||
{
|
||||
@ -3415,7 +3465,7 @@ static void check_class(thread_db* tdbb,
|
||||
|
||||
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);
|
||||
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();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user