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
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

View File

@ -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);

View File

@ -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)
{

View File

@ -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,

View File

@ -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);

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 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};

View File

@ -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;
}

View File

@ -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:
{

View File

@ -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())
{

View File

@ -499,7 +499,8 @@ struct Resource
rsc_relation,
rsc_procedure,
rsc_index,
rsc_collation
rsc_collation,
rsc_function
};
enum rsc_s rsc_type;
@ -507,6 +508,7 @@ struct 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)

View File

@ -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();
}

View File

@ -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,11 +320,7 @@ 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
@ -348,37 +328,12 @@ void FUN_evaluate(thread_db* tdbb, UserFunction* function, jrd_nod* node, impure
// 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);
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,

View File

@ -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

View File

@ -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

View File

@ -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(&parameter->prm_desc, blr);
}
else
{
fb_assert(parameter->prm_mechanism == prm_mech_normal);
@ -4662,7 +4649,7 @@ 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,
bid* blob_id,
CompilerScratch* csb,
@ -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,7 +4733,7 @@ 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,
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;
}

View File

@ -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,7 +1503,7 @@ 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()));
}
@ -1511,7 +1511,7 @@ static jrd_nod* par_function(thread_db* tdbb, CompilerScratch* csb, SSHORT blr_o
// 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;

View File

@ -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)

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_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,7 +232,7 @@ 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,
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,11 +350,11 @@ 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,
SCL_check_access(tdbb, default_s_class, 0, 0, NULL, mask, object_column,
fullFieldName);
}
@ -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;
}

View File

@ -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*);

View File

@ -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);
}

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
// 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

View File

@ -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);
}