mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-02-01 02:43:02 +01:00
e956e2e6c0
2) Opened the gates to implement the standard USAGE privilege (CORE-2884). SQL support and validation logic are still to be developed. 3) Added the grant option to the owner permissions for packages, procedures and functions. 4) Misc cleanup and refactoring.
1140 lines
31 KiB
Plaintext
1140 lines
31 KiB
Plaintext
/*
|
|
* The contents of this file are subject to the Initial
|
|
* Developer's Public License Version 1.0 (the "License");
|
|
* you may not use this file except in compliance with the
|
|
* License. You may obtain a copy of the License at
|
|
* http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
|
|
*
|
|
* Software distributed under the License is distributed AS IS,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing rights
|
|
* and limitations under the License.
|
|
*
|
|
* The Original Code was created by Adriano dos Santos Fernandes
|
|
* for the Firebird Open Source RDBMS project.
|
|
*
|
|
* Copyright (c) 2009 Adriano dos Santos Fernandes <adrianosf@uol.com.br>
|
|
* and all contributors signed below.
|
|
*
|
|
* All Rights Reserved.
|
|
* Contributor(s): ______________________________________.
|
|
*/
|
|
|
|
#include "firebird.h"
|
|
#include "../common/common.h"
|
|
#include "../dsql/PackageNodes.h"
|
|
#include "../jrd/dyn.h"
|
|
#include "../jrd/intl.h"
|
|
#include "../jrd/jrd.h"
|
|
#include "../jrd/tra.h"
|
|
#include "../jrd/dfw_proto.h"
|
|
#include "../jrd/exe_proto.h"
|
|
#include "../jrd/met_proto.h"
|
|
#include "../jrd/vio_proto.h"
|
|
#include "../dsql/make_proto.h"
|
|
#include "../dsql/pass1_proto.h"
|
|
#include "../common/StatusArg.h"
|
|
#include "../jrd/Attachment.h"
|
|
|
|
|
|
using namespace Firebird;
|
|
|
|
namespace Jrd {
|
|
|
|
using namespace Firebird;
|
|
using namespace Dsql;
|
|
|
|
DATABASE DB = STATIC "ODS.RDB";
|
|
|
|
|
|
//----------------------
|
|
|
|
|
|
namespace
|
|
{
|
|
struct ParameterInfo
|
|
{
|
|
explicit ParameterInfo(MemoryPool& p)
|
|
: type(0),
|
|
number(0),
|
|
name(p),
|
|
fieldSource(p),
|
|
fieldName(p),
|
|
relationName(p),
|
|
mechanism(0)
|
|
{
|
|
defaultSource.clear();
|
|
defaultValue.clear();
|
|
}
|
|
|
|
ParameterInfo(MemoryPool& p, const ParameterInfo& o)
|
|
: type(o.type),
|
|
number(o.number),
|
|
name(p, o.name),
|
|
fieldSource(p, o.fieldSource),
|
|
fieldName(p, o.fieldName),
|
|
relationName(p, o.relationName),
|
|
collationId(o.collationId),
|
|
nullFlag(o.nullFlag),
|
|
mechanism(o.mechanism),
|
|
fieldLength(o.fieldLength),
|
|
fieldScale(o.fieldScale),
|
|
fieldType(o.fieldType),
|
|
fieldSubType(o.fieldSubType),
|
|
fieldSegmentLength(o.fieldSegmentLength),
|
|
fieldNullFlag(o.fieldNullFlag),
|
|
fieldCharLength(o.fieldCharLength),
|
|
fieldCollationId(o.fieldCollationId),
|
|
fieldCharSetId(o.fieldCharSetId),
|
|
fieldPrecision(o.fieldPrecision),
|
|
defaultSource(o.defaultSource),
|
|
defaultValue(o.defaultValue)
|
|
{
|
|
}
|
|
|
|
SSHORT type;
|
|
SSHORT number;
|
|
MetaName name;
|
|
MetaName fieldSource;
|
|
MetaName fieldName;
|
|
MetaName relationName;
|
|
Nullable<SSHORT> collationId;
|
|
Nullable<SSHORT> nullFlag;
|
|
SSHORT mechanism;
|
|
Nullable<SSHORT> fieldLength;
|
|
Nullable<SSHORT> fieldScale;
|
|
Nullable<SSHORT> fieldType;
|
|
Nullable<SSHORT> fieldSubType;
|
|
Nullable<SSHORT> fieldSegmentLength;
|
|
Nullable<SSHORT> fieldNullFlag;
|
|
Nullable<SSHORT> fieldCharLength;
|
|
Nullable<SSHORT> fieldCollationId;
|
|
Nullable<SSHORT> fieldCharSetId;
|
|
Nullable<SSHORT> fieldPrecision;
|
|
|
|
// Not compared
|
|
bid defaultSource;
|
|
bid defaultValue;
|
|
|
|
bool operator >(const ParameterInfo& o) const
|
|
{
|
|
return type > o.type || (type == o.type && number > o.number);
|
|
}
|
|
|
|
bool operator ==(const ParameterInfo& o) const
|
|
{
|
|
return type == o.type && number == o.number && name == o.name &&
|
|
(fieldSource == o.fieldSource ||
|
|
(fb_utils::implicit_domain(fieldSource.c_str()) &&
|
|
fb_utils::implicit_domain(o.fieldSource.c_str()))) &&
|
|
fieldName == o.fieldName && relationName == o.relationName &&
|
|
collationId == o.collationId && nullFlag == o.nullFlag &&
|
|
mechanism == o.mechanism && fieldLength == o.fieldLength &&
|
|
fieldScale == o.fieldScale && fieldType == o.fieldType &&
|
|
fieldSubType == o.fieldSubType && fieldSegmentLength == o.fieldSegmentLength &&
|
|
fieldNullFlag == o.fieldNullFlag && fieldCharLength == o.fieldCharLength &&
|
|
fieldCollationId == o.fieldCollationId && fieldCharSetId == o.fieldCharSetId &&
|
|
fieldPrecision == o.fieldPrecision;
|
|
}
|
|
|
|
bool operator !=(const ParameterInfo& o) const
|
|
{
|
|
return !(*this == o);
|
|
}
|
|
};
|
|
|
|
struct Signature
|
|
{
|
|
Signature(MemoryPool& p, const MetaName& aName)
|
|
: name(p, aName),
|
|
parameters(p),
|
|
defined(false)
|
|
{
|
|
}
|
|
|
|
explicit Signature(const MetaName& aName)
|
|
: name(aName),
|
|
parameters(*getDefaultMemoryPool()),
|
|
defined(false)
|
|
{
|
|
}
|
|
|
|
explicit Signature(MemoryPool& p)
|
|
: name(p),
|
|
parameters(p),
|
|
defined(false)
|
|
{
|
|
}
|
|
|
|
Signature(MemoryPool& p, const Signature& o)
|
|
: name(p, o.name),
|
|
parameters(p),
|
|
defined(o.defined)
|
|
{
|
|
for (SortedObjectsArray<ParameterInfo>::const_iterator i = o.parameters.begin();
|
|
i != o.parameters.end(); ++i)
|
|
{
|
|
parameters.add(*i);
|
|
}
|
|
}
|
|
|
|
bool operator >(const Signature& o) const
|
|
{
|
|
return name > o.name;
|
|
}
|
|
|
|
bool operator ==(const Signature& o) const
|
|
{
|
|
if (name != o.name || parameters.getCount() != o.parameters.getCount())
|
|
return false;
|
|
|
|
for (SortedObjectsArray<ParameterInfo>::const_iterator i = parameters.begin(),
|
|
j = o.parameters.begin();
|
|
i != parameters.end(); ++i, ++j)
|
|
{
|
|
if (*i != *j)
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool operator !=(const Signature& o) const
|
|
{
|
|
return !(*this == o);
|
|
}
|
|
|
|
MetaName name;
|
|
SortedObjectsArray<ParameterInfo> parameters;
|
|
bool defined;
|
|
};
|
|
|
|
|
|
// Return function and procedure names (in the user charset) and optionally its details for a
|
|
// given package.
|
|
void collectPackagedItems(thread_db* tdbb, jrd_tra* transaction, const MetaName& metaName,
|
|
SortedObjectsArray<Signature>& functions,
|
|
SortedObjectsArray<Signature>& procedures, bool details)
|
|
{
|
|
AutoCacheRequest requestHandle(tdbb, drq_l_pkg_funcs, DYN_REQUESTS);
|
|
AutoCacheRequest requestHandle2(tdbb, drq_l_pkg_func_args, DYN_REQUESTS);
|
|
|
|
FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction)
|
|
FUN IN RDB$FUNCTIONS
|
|
WITH FUN.RDB$PACKAGE_NAME EQ metaName.c_str()
|
|
{
|
|
Signature function(FUN.RDB$FUNCTION_NAME);
|
|
function.defined = !FUN.RDB$FUNCTION_BLR.NULL || !FUN.RDB$ENTRYPOINT.NULL;
|
|
|
|
if (details)
|
|
{
|
|
FOR (REQUEST_HANDLE requestHandle2 TRANSACTION_HANDLE transaction)
|
|
ARG IN RDB$FUNCTION_ARGUMENTS CROSS
|
|
FLD IN RDB$FIELDS
|
|
WITH ARG.RDB$PACKAGE_NAME EQ metaName.c_str() AND
|
|
ARG.RDB$FUNCTION_NAME EQ FUN.RDB$FUNCTION_NAME AND
|
|
FLD.RDB$FIELD_NAME EQ ARG.RDB$FIELD_SOURCE
|
|
{
|
|
ParameterInfo parameter(*getDefaultMemoryPool());
|
|
|
|
parameter.number = ARG.RDB$ARGUMENT_POSITION;
|
|
parameter.name = ARG.RDB$ARGUMENT_NAME;
|
|
parameter.fieldSource = ARG.RDB$FIELD_SOURCE;
|
|
parameter.mechanism = ARG.RDB$ARGUMENT_MECHANISM;
|
|
|
|
if (!ARG.RDB$FIELD_NAME.NULL)
|
|
parameter.fieldName = ARG.RDB$FIELD_NAME;
|
|
if (!ARG.RDB$RELATION_NAME.NULL)
|
|
parameter.relationName = ARG.RDB$RELATION_NAME;
|
|
if (!ARG.RDB$COLLATION_ID.NULL)
|
|
parameter.collationId = ARG.RDB$COLLATION_ID;
|
|
if (!ARG.RDB$NULL_FLAG.NULL)
|
|
parameter.nullFlag = ARG.RDB$NULL_FLAG;
|
|
|
|
if (!FLD.RDB$FIELD_LENGTH.NULL)
|
|
parameter.fieldLength = FLD.RDB$FIELD_LENGTH;
|
|
if (!FLD.RDB$FIELD_SCALE.NULL)
|
|
parameter.fieldScale = FLD.RDB$FIELD_SCALE;
|
|
if (!FLD.RDB$FIELD_TYPE.NULL)
|
|
parameter.fieldType = FLD.RDB$FIELD_TYPE;
|
|
if (!FLD.RDB$FIELD_SUB_TYPE.NULL)
|
|
parameter.fieldSubType = FLD.RDB$FIELD_SUB_TYPE;
|
|
if (!FLD.RDB$SEGMENT_LENGTH.NULL)
|
|
parameter.fieldSegmentLength = FLD.RDB$SEGMENT_LENGTH;
|
|
if (!FLD.RDB$NULL_FLAG.NULL)
|
|
parameter.fieldNullFlag = FLD.RDB$NULL_FLAG;
|
|
if (!FLD.RDB$CHARACTER_LENGTH.NULL)
|
|
parameter.fieldCharLength = FLD.RDB$CHARACTER_LENGTH;
|
|
if (!FLD.RDB$COLLATION_ID.NULL)
|
|
parameter.fieldCollationId = FLD.RDB$COLLATION_ID;
|
|
if (!FLD.RDB$CHARACTER_SET_ID.NULL)
|
|
parameter.fieldCharSetId = FLD.RDB$CHARACTER_SET_ID;
|
|
if (!FLD.RDB$FIELD_PRECISION.NULL)
|
|
parameter.fieldPrecision = FLD.RDB$FIELD_PRECISION;
|
|
|
|
if (!ARG.RDB$DEFAULT_SOURCE.NULL)
|
|
parameter.defaultSource = ARG.RDB$DEFAULT_SOURCE;
|
|
if (!ARG.RDB$DEFAULT_VALUE.NULL)
|
|
parameter.defaultValue = ARG.RDB$DEFAULT_VALUE;
|
|
|
|
function.parameters.add(parameter);
|
|
}
|
|
END_FOR
|
|
}
|
|
|
|
functions.add(function);
|
|
}
|
|
END_FOR
|
|
|
|
requestHandle.reset(tdbb, drq_l_pkg_procs, DYN_REQUESTS);
|
|
requestHandle2.reset(tdbb, drq_l_pkg_proc_args, DYN_REQUESTS);
|
|
|
|
FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction)
|
|
PRC IN RDB$PROCEDURES
|
|
WITH PRC.RDB$PACKAGE_NAME EQ metaName.c_str()
|
|
{
|
|
Signature procedure(PRC.RDB$PROCEDURE_NAME);
|
|
procedure.defined = !PRC.RDB$PROCEDURE_BLR.NULL || !PRC.RDB$ENTRYPOINT.NULL;
|
|
|
|
if (details)
|
|
{
|
|
FOR (REQUEST_HANDLE requestHandle2 TRANSACTION_HANDLE transaction)
|
|
PRM IN RDB$PROCEDURE_PARAMETERS CROSS
|
|
FLD IN RDB$FIELDS
|
|
WITH PRM.RDB$PACKAGE_NAME EQ metaName.c_str() AND
|
|
PRM.RDB$PROCEDURE_NAME EQ PRC.RDB$PROCEDURE_NAME AND
|
|
FLD.RDB$FIELD_NAME EQ PRM.RDB$FIELD_SOURCE
|
|
{
|
|
ParameterInfo parameter(*getDefaultMemoryPool());
|
|
parameter.type = PRM.RDB$PARAMETER_TYPE;
|
|
parameter.number = PRM.RDB$PARAMETER_NUMBER;
|
|
parameter.name = PRM.RDB$PARAMETER_NAME;
|
|
parameter.fieldSource = PRM.RDB$FIELD_SOURCE;
|
|
parameter.mechanism = PRM.RDB$PARAMETER_MECHANISM;
|
|
|
|
if (!PRM.RDB$FIELD_NAME.NULL)
|
|
parameter.fieldName = PRM.RDB$FIELD_NAME;
|
|
if (!PRM.RDB$RELATION_NAME.NULL)
|
|
parameter.relationName = PRM.RDB$RELATION_NAME;
|
|
if (!PRM.RDB$COLLATION_ID.NULL)
|
|
parameter.collationId = PRM.RDB$COLLATION_ID;
|
|
if (!PRM.RDB$NULL_FLAG.NULL)
|
|
parameter.nullFlag = PRM.RDB$NULL_FLAG;
|
|
|
|
if (!FLD.RDB$FIELD_LENGTH.NULL)
|
|
parameter.fieldLength = FLD.RDB$FIELD_LENGTH;
|
|
if (!FLD.RDB$FIELD_SCALE.NULL)
|
|
parameter.fieldScale = FLD.RDB$FIELD_SCALE;
|
|
if (!FLD.RDB$FIELD_TYPE.NULL)
|
|
parameter.fieldType = FLD.RDB$FIELD_TYPE;
|
|
if (!FLD.RDB$FIELD_SUB_TYPE.NULL)
|
|
parameter.fieldSubType = FLD.RDB$FIELD_SUB_TYPE;
|
|
if (!FLD.RDB$SEGMENT_LENGTH.NULL)
|
|
parameter.fieldSegmentLength = FLD.RDB$SEGMENT_LENGTH;
|
|
if (!FLD.RDB$NULL_FLAG.NULL)
|
|
parameter.fieldNullFlag = FLD.RDB$NULL_FLAG;
|
|
if (!FLD.RDB$CHARACTER_LENGTH.NULL)
|
|
parameter.fieldCharLength = FLD.RDB$CHARACTER_LENGTH;
|
|
if (!FLD.RDB$COLLATION_ID.NULL)
|
|
parameter.fieldCollationId = FLD.RDB$COLLATION_ID;
|
|
if (!FLD.RDB$CHARACTER_SET_ID.NULL)
|
|
parameter.fieldCharSetId = FLD.RDB$CHARACTER_SET_ID;
|
|
if (!FLD.RDB$FIELD_PRECISION.NULL)
|
|
parameter.fieldPrecision = FLD.RDB$FIELD_PRECISION;
|
|
|
|
if (!PRM.RDB$DEFAULT_SOURCE.NULL)
|
|
parameter.defaultSource = PRM.RDB$DEFAULT_SOURCE;
|
|
if (!PRM.RDB$DEFAULT_VALUE.NULL)
|
|
parameter.defaultValue = PRM.RDB$DEFAULT_VALUE;
|
|
|
|
procedure.parameters.add(parameter);
|
|
}
|
|
END_FOR
|
|
}
|
|
|
|
procedures.add(procedure);
|
|
}
|
|
END_FOR
|
|
}
|
|
} // namespace
|
|
|
|
|
|
//----------------------
|
|
|
|
|
|
void CreateAlterPackageNode::print(string& text, Array<dsql_nod*>& /*nodes*/) const
|
|
{
|
|
fb_assert(items);
|
|
|
|
text.printf(
|
|
"CreateAlterPackageNode\n"
|
|
" name: '%s' create: %d alter: %d\n"
|
|
" Items:\n"
|
|
"--------\n",
|
|
name.c_str(), create, alter);
|
|
|
|
for (unsigned i = 0; i < items->getCount(); ++i)
|
|
{
|
|
string item;
|
|
Array<dsql_nod*> tempNodes;
|
|
|
|
switch ((*items)[i].type)
|
|
{
|
|
case Item::FUNCTION:
|
|
(*items)[i].function->print(item, tempNodes);
|
|
break;
|
|
|
|
case Item::PROCEDURE:
|
|
(*items)[i].procedure->print(item, tempNodes);
|
|
break;
|
|
}
|
|
|
|
text += item;
|
|
}
|
|
|
|
text += "--------\n";
|
|
}
|
|
|
|
|
|
DdlNode* CreateAlterPackageNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
|
|
{
|
|
source.ltrim("\n\r\t ");
|
|
|
|
// items
|
|
for (unsigned i = 0; i < items->getCount(); ++i)
|
|
{
|
|
DsqlCompiledStatement* itemStatement = FB_NEW(getPool()) DsqlCompiledStatement(getPool());
|
|
|
|
DsqlCompilerScratch* itemScratch = (*items)[i].dsqlScratch =
|
|
FB_NEW(getPool()) DsqlCompilerScratch(getPool(), dsqlScratch->getAttachment(),
|
|
dsqlScratch->getTransaction(), itemStatement);
|
|
|
|
itemScratch->clientDialect = dsqlScratch->clientDialect;
|
|
itemScratch->package = name;
|
|
itemStatement->setDdlNode(MAKE_node(nod_class_stmtnode, 1));
|
|
|
|
switch ((*items)[i].type)
|
|
{
|
|
case CreateAlterPackageNode::Item::FUNCTION:
|
|
{
|
|
CreateAlterFunctionNode* const fun = (*items)[i].function;
|
|
functionNames.add(fun->name);
|
|
fun->alter = true;
|
|
fun->package = name;
|
|
itemStatement->getDdlNode()->nod_arg[0] = (dsql_nod*) fun;
|
|
fun->dsqlPass(itemScratch);
|
|
}
|
|
break;
|
|
|
|
case CreateAlterPackageNode::Item::PROCEDURE:
|
|
{
|
|
CreateAlterProcedureNode* const proc = (*items)[i].procedure;
|
|
procedureNames.add(proc->name);
|
|
proc->alter = true;
|
|
proc->package = name;
|
|
itemStatement->getDdlNode()->nod_arg[0] = (dsql_nod*) proc;
|
|
proc->dsqlPass(itemScratch);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
return DdlNode::dsqlPass(dsqlScratch);
|
|
}
|
|
|
|
|
|
void CreateAlterPackageNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch,
|
|
jrd_tra* transaction)
|
|
{
|
|
fb_assert(create || alter);
|
|
|
|
//Database* dbb = tdbb->getDatabase();
|
|
|
|
//dbb->checkOdsForDsql(ODS_12_0);
|
|
|
|
// run all statements under savepoint control
|
|
AutoSavePoint savePoint(tdbb, transaction);
|
|
|
|
if (alter)
|
|
{
|
|
if (!executeAlter(tdbb, dsqlScratch, transaction))
|
|
{
|
|
if (create) // create or alter
|
|
executeCreate(tdbb, dsqlScratch, transaction);
|
|
else
|
|
{
|
|
status_exception::raise(
|
|
Arg::Gds(isc_no_meta_update) <<
|
|
Arg::Gds(isc_dyn_package_not_found) << Arg::Str(name));
|
|
}
|
|
}
|
|
}
|
|
else
|
|
executeCreate(tdbb, dsqlScratch, transaction);
|
|
|
|
// items
|
|
for (unsigned i = 0; i < items->getCount(); ++i)
|
|
{
|
|
switch ((*items)[i].type)
|
|
{
|
|
case Item::FUNCTION:
|
|
(*items)[i].function->packageOwner = owner;
|
|
(*items)[i].function->executeDdl(tdbb, (*items)[i].dsqlScratch, transaction);
|
|
break;
|
|
|
|
case Item::PROCEDURE:
|
|
(*items)[i].procedure->packageOwner = owner;
|
|
(*items)[i].procedure->executeDdl(tdbb, (*items)[i].dsqlScratch, transaction);
|
|
break;
|
|
}
|
|
}
|
|
|
|
savePoint.release(); // everything is ok
|
|
}
|
|
|
|
|
|
void CreateAlterPackageNode::executeCreate(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch,
|
|
jrd_tra* transaction)
|
|
{
|
|
Attachment* attachment = transaction->getAttachment();
|
|
const string& user_name = attachment->att_user->usr_user_name;
|
|
|
|
executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE,
|
|
DDL_TRIGGER_CREATE_PACKAGE, name);
|
|
|
|
AutoCacheRequest requestHandle(tdbb, drq_s_pkg, DYN_REQUESTS);
|
|
|
|
STORE (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction)
|
|
PKG IN RDB$PACKAGES USING
|
|
{
|
|
PKG.RDB$PACKAGE_NAME.NULL = FALSE;
|
|
strcpy(PKG.RDB$PACKAGE_NAME, name.c_str());
|
|
|
|
PKG.RDB$SYSTEM_FLAG.NULL = FALSE;
|
|
PKG.RDB$SYSTEM_FLAG = 0;
|
|
|
|
PKG.RDB$OWNER_NAME.NULL = FALSE;
|
|
strcpy(PKG.RDB$OWNER_NAME, user_name.c_str());
|
|
|
|
PKG.RDB$PACKAGE_HEADER_SOURCE.NULL = FALSE;
|
|
attachment->storeMetaDataBlob(tdbb, transaction, &PKG.RDB$PACKAGE_HEADER_SOURCE, source);
|
|
}
|
|
END_STORE
|
|
|
|
requestHandle.reset(tdbb, drq_s_pkg_usr_prvs, DYN_REQUESTS);
|
|
|
|
STORE (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction)
|
|
X IN RDB$USER_PRIVILEGES
|
|
{
|
|
strcpy(X.RDB$RELATION_NAME, name.c_str());
|
|
strcpy(X.RDB$USER, user_name.c_str());
|
|
X.RDB$USER_TYPE = obj_user;
|
|
X.RDB$OBJECT_TYPE = obj_package_header;
|
|
X.RDB$PRIVILEGE[0] = EXEC_PRIVILEGE;
|
|
X.RDB$PRIVILEGE[1] = 0;
|
|
X.RDB$GRANT_OPTION = 1;
|
|
}
|
|
END_STORE;
|
|
|
|
owner = attachment->att_user->usr_user_name;
|
|
|
|
executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_CREATE_PACKAGE, name);
|
|
}
|
|
|
|
|
|
bool CreateAlterPackageNode::executeAlter(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch,
|
|
jrd_tra* transaction)
|
|
{
|
|
Attachment* attachment = transaction->getAttachment();
|
|
AutoCacheRequest requestHandle(tdbb, drq_m_pkg, DYN_REQUESTS);
|
|
bool modified = false;
|
|
|
|
FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction)
|
|
PKG IN RDB$PACKAGES
|
|
WITH PKG.RDB$PACKAGE_NAME EQ name.c_str()
|
|
{
|
|
modified = true;
|
|
|
|
executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE,
|
|
DDL_TRIGGER_ALTER_PACKAGE, name);
|
|
|
|
SortedObjectsArray<Signature> existingFuncs(getPool());
|
|
SortedObjectsArray<Signature> existingProcs(getPool());
|
|
collectPackagedItems(tdbb, transaction, name, existingFuncs, existingProcs, false);
|
|
|
|
for (SortedObjectsArray<Signature>::iterator i = existingFuncs.begin();
|
|
i != existingFuncs.end(); ++i)
|
|
{
|
|
if (!functionNames.exist(i->name))
|
|
{
|
|
DropFunctionNode dropNode(getPool(), i->name);
|
|
dropNode.package = name;
|
|
dropNode.dsqlPass(dsqlScratch);
|
|
dropNode.executeDdl(tdbb, dsqlScratch, transaction);
|
|
}
|
|
}
|
|
|
|
for (SortedObjectsArray<Signature>::iterator i = existingProcs.begin();
|
|
i != existingProcs.end(); ++i)
|
|
{
|
|
if (!procedureNames.exist(i->name))
|
|
{
|
|
DropProcedureNode dropNode(getPool(), i->name);
|
|
dropNode.package = name;
|
|
dropNode.dsqlPass(dsqlScratch);
|
|
dropNode.executeDdl(tdbb, dsqlScratch, transaction);
|
|
}
|
|
}
|
|
|
|
MODIFY PKG
|
|
PKG.RDB$PACKAGE_HEADER_SOURCE.NULL = FALSE;
|
|
attachment->storeMetaDataBlob(tdbb, transaction, &PKG.RDB$PACKAGE_HEADER_SOURCE,
|
|
source);
|
|
|
|
PKG.RDB$PACKAGE_BODY_SOURCE.NULL = TRUE;
|
|
END_MODIFY
|
|
|
|
owner = PKG.RDB$OWNER_NAME;
|
|
}
|
|
END_FOR
|
|
|
|
if (modified)
|
|
executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_ALTER_PACKAGE, name);
|
|
|
|
return modified;
|
|
}
|
|
|
|
|
|
//----------------------
|
|
|
|
|
|
void DropPackageNode::print(string& text, Array<dsql_nod*>& /*nodes*/) const
|
|
{
|
|
text.printf(
|
|
"DropPackageNode\n"
|
|
" name: '%s'\n",
|
|
name.c_str());
|
|
}
|
|
|
|
|
|
void DropPackageNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch,
|
|
jrd_tra* transaction)
|
|
{
|
|
// run all statements under savepoint control
|
|
AutoSavePoint savePoint(tdbb, transaction);
|
|
|
|
bool found = false;
|
|
AutoCacheRequest requestHandle(tdbb, drq_e_pkg, DYN_REQUESTS);
|
|
|
|
FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction)
|
|
PKG IN RDB$PACKAGES
|
|
WITH PKG.RDB$PACKAGE_NAME EQ name.c_str()
|
|
{
|
|
found = true;
|
|
|
|
executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE,
|
|
DDL_TRIGGER_DROP_PACKAGE, name);
|
|
|
|
ERASE PKG;
|
|
|
|
if (!PKG.RDB$SECURITY_CLASS.NULL)
|
|
deleteSecurityClass(tdbb, transaction, PKG.RDB$SECURITY_CLASS);
|
|
|
|
dsc desc;
|
|
desc.makeText(name.length(), ttype_metadata,
|
|
(UCHAR*) const_cast<char*>(name.c_str())); // safe const_cast
|
|
DFW_post_work(transaction, dfw_drop_package_header, &desc, 0);
|
|
}
|
|
END_FOR
|
|
|
|
if (!found && !silent)
|
|
{
|
|
status_exception::raise(
|
|
Arg::Gds(isc_no_meta_update) <<
|
|
Arg::Gds(isc_dyn_package_not_found) << Arg::Str(name));
|
|
}
|
|
|
|
SortedObjectsArray<Signature> existingFuncs(getPool());
|
|
SortedObjectsArray<Signature> existingProcs(getPool());
|
|
collectPackagedItems(tdbb, transaction, name, existingFuncs, existingProcs, false);
|
|
|
|
for (SortedObjectsArray<Signature>::iterator i = existingFuncs.begin();
|
|
i != existingFuncs.end(); ++i)
|
|
{
|
|
DropFunctionNode dropNode(getPool(), i->name);
|
|
dropNode.package = name;
|
|
dropNode.dsqlPass(dsqlScratch);
|
|
dropNode.executeDdl(tdbb, dsqlScratch, transaction);
|
|
}
|
|
|
|
for (SortedObjectsArray<Signature>::iterator i = existingProcs.begin();
|
|
i != existingProcs.end(); ++i)
|
|
{
|
|
DropProcedureNode dropNode(getPool(), i->name);
|
|
dropNode.package = name;
|
|
dropNode.dsqlPass(dsqlScratch);
|
|
dropNode.executeDdl(tdbb, dsqlScratch, transaction);
|
|
}
|
|
|
|
requestHandle.reset(tdbb, drq_e_pkg_prv, DYN_REQUESTS);
|
|
|
|
FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction)
|
|
PRIV IN RDB$USER_PRIVILEGES
|
|
WITH (PRIV.RDB$RELATION_NAME EQ name.c_str() AND
|
|
PRIV.RDB$OBJECT_TYPE = obj_package_header) OR
|
|
(PRIV.RDB$USER EQ name.c_str() AND PRIV.RDB$USER_TYPE = obj_package_header)
|
|
{
|
|
ERASE PRIV;
|
|
}
|
|
END_FOR
|
|
|
|
if (found)
|
|
executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_DROP_PACKAGE, name);
|
|
|
|
savePoint.release(); // everything is ok
|
|
}
|
|
|
|
|
|
//----------------------
|
|
|
|
|
|
void CreatePackageBodyNode::print(string& text, Array<dsql_nod*>& /*nodes*/) const
|
|
{
|
|
fb_assert(items);
|
|
|
|
text.printf(
|
|
"CreatePackageBodyNode\n"
|
|
" name: '%s'\n"
|
|
" declaredItems:\n"
|
|
"--------\n",
|
|
name.c_str());
|
|
|
|
if (declaredItems)
|
|
{
|
|
for (unsigned i = 0; i < declaredItems->getCount(); ++i)
|
|
{
|
|
string item;
|
|
Array<dsql_nod*> tempNodes;
|
|
|
|
switch ((*declaredItems)[i].type)
|
|
{
|
|
case CreateAlterPackageNode::Item::FUNCTION:
|
|
(*declaredItems)[i].function->print(item, tempNodes);
|
|
break;
|
|
|
|
case CreateAlterPackageNode::Item::PROCEDURE:
|
|
(*declaredItems)[i].procedure->print(item, tempNodes);
|
|
break;
|
|
}
|
|
|
|
text += item;
|
|
}
|
|
}
|
|
|
|
text +=
|
|
"--------\n"
|
|
" items:\n"
|
|
"--------\n";
|
|
|
|
for (unsigned i = 0; i < items->getCount(); ++i)
|
|
{
|
|
string item;
|
|
Array<dsql_nod*> tempNodes;
|
|
|
|
switch ((*items)[i].type)
|
|
{
|
|
case CreateAlterPackageNode::Item::FUNCTION:
|
|
(*items)[i].function->print(item, tempNodes);
|
|
break;
|
|
|
|
case CreateAlterPackageNode::Item::PROCEDURE:
|
|
(*items)[i].procedure->print(item, tempNodes);
|
|
break;
|
|
}
|
|
|
|
text += item;
|
|
}
|
|
|
|
text += "--------\n";
|
|
}
|
|
|
|
|
|
DdlNode* CreatePackageBodyNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
|
|
{
|
|
source.ltrim("\n\r\t ");
|
|
|
|
// process declaredItems and items
|
|
Array<CreateAlterPackageNode::Item>* arrays[] = {declaredItems, items};
|
|
|
|
for (unsigned i = 0; i < FB_NELEM(arrays); ++i)
|
|
{
|
|
if (!arrays[i])
|
|
continue;
|
|
|
|
for (unsigned j = 0; j < arrays[i]->getCount(); ++j)
|
|
{
|
|
DsqlCompiledStatement* itemStatement = FB_NEW(getPool()) DsqlCompiledStatement(getPool());
|
|
|
|
DsqlCompilerScratch* itemScratch = (*arrays[i])[j].dsqlScratch =
|
|
FB_NEW(getPool()) DsqlCompilerScratch(getPool(), dsqlScratch->getAttachment(),
|
|
dsqlScratch->getTransaction(), itemStatement);
|
|
|
|
itemScratch->clientDialect = dsqlScratch->clientDialect;
|
|
itemScratch->package = name;
|
|
itemStatement->setDdlNode(MAKE_node(nod_class_stmtnode, 1));
|
|
|
|
switch ((*arrays[i])[j].type)
|
|
{
|
|
case CreateAlterPackageNode::Item::FUNCTION:
|
|
{
|
|
CreateAlterFunctionNode* const fun = (*arrays[i])[j].function;
|
|
fun->package = name;
|
|
fun->create = true;
|
|
if (arrays[i] == items)
|
|
fun->alter = true;
|
|
itemStatement->getDdlNode()->nod_arg[0] = (dsql_nod*) fun;
|
|
fun->dsqlPass(itemScratch);
|
|
}
|
|
break;
|
|
|
|
case CreateAlterPackageNode::Item::PROCEDURE:
|
|
{
|
|
CreateAlterProcedureNode* const proc = (*arrays[i])[j].procedure;
|
|
proc->package = name;
|
|
proc->create = true;
|
|
if (arrays[i] == items)
|
|
proc->alter = true;
|
|
itemStatement->getDdlNode()->nod_arg[0] = (dsql_nod*) proc;
|
|
proc->dsqlPass(itemScratch);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return DdlNode::dsqlPass(dsqlScratch);
|
|
}
|
|
|
|
|
|
void CreatePackageBodyNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch,
|
|
jrd_tra* transaction)
|
|
{
|
|
Attachment* attachment = transaction->getAttachment();
|
|
|
|
// run all statements under savepoint control
|
|
AutoSavePoint savePoint(tdbb, transaction);
|
|
|
|
AutoCacheRequest requestHandle(tdbb, drq_m_pkg_body, DYN_REQUESTS);
|
|
bool modified = false;
|
|
|
|
FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction)
|
|
PKG IN RDB$PACKAGES
|
|
WITH PKG.RDB$PACKAGE_NAME EQ name.c_str()
|
|
{
|
|
if (!PKG.RDB$PACKAGE_BODY_SOURCE.NULL)
|
|
{
|
|
status_exception::raise(
|
|
Arg::Gds(isc_no_meta_update) <<
|
|
Arg::Gds(isc_dyn_package_body_exists) << Arg::Str(name));
|
|
}
|
|
|
|
executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE,
|
|
DDL_TRIGGER_CREATE_PACKAGE_BODY, name);
|
|
|
|
MODIFY PKG
|
|
PKG.RDB$PACKAGE_BODY_SOURCE.NULL = FALSE;
|
|
attachment->storeMetaDataBlob(tdbb, transaction, &PKG.RDB$PACKAGE_BODY_SOURCE, source);
|
|
END_MODIFY
|
|
|
|
modified = true;
|
|
|
|
owner = PKG.RDB$OWNER_NAME;
|
|
}
|
|
END_FOR
|
|
|
|
if (!modified)
|
|
{
|
|
status_exception::raise(
|
|
Arg::Gds(isc_no_meta_update) <<
|
|
Arg::Gds(isc_dyn_package_not_found) << Arg::Str(name));
|
|
}
|
|
|
|
SortedObjectsArray<Signature> headerFuncs(getPool());
|
|
SortedObjectsArray<Signature> headerProcs(getPool());
|
|
collectPackagedItems(tdbb, transaction, name, headerFuncs, headerProcs, false);
|
|
|
|
SortedObjectsArray<Signature> existingFuncs(getPool());
|
|
SortedObjectsArray<Signature> existingProcs(getPool());
|
|
|
|
// process declaredItems and items
|
|
Array<CreateAlterPackageNode::Item>* arrays[] = {declaredItems, items};
|
|
|
|
for (unsigned i = 0; i < FB_NELEM(arrays); ++i)
|
|
{
|
|
if (!arrays[i])
|
|
continue;
|
|
|
|
if (arrays[i] == items)
|
|
collectPackagedItems(tdbb, transaction, name, existingFuncs, existingProcs, true);
|
|
|
|
for (unsigned j = 0; j < arrays[i]->getCount(); ++j)
|
|
{
|
|
switch ((*arrays[i])[j].type)
|
|
{
|
|
case CreateAlterPackageNode::Item::FUNCTION:
|
|
{
|
|
CreateAlterFunctionNode* func = (*arrays[i])[j].function;
|
|
|
|
if (arrays[i] == items)
|
|
func->privateScope = !headerFuncs.exist(Signature(func->name));
|
|
|
|
func->packageOwner = owner;
|
|
func->executeDdl(tdbb, (*arrays[i])[j].dsqlScratch, transaction);
|
|
}
|
|
break;
|
|
|
|
case CreateAlterPackageNode::Item::PROCEDURE:
|
|
{
|
|
CreateAlterProcedureNode* proc = (*arrays[i])[j].procedure;
|
|
|
|
if (arrays[i] == items)
|
|
proc->privateScope = !headerProcs.exist(Signature(proc->name));
|
|
|
|
proc->packageOwner = owner;
|
|
proc->executeDdl(tdbb, (*arrays[i])[j].dsqlScratch, transaction);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
SortedObjectsArray<Signature> newFuncs(getPool());
|
|
SortedObjectsArray<Signature> newProcs(getPool());
|
|
collectPackagedItems(tdbb, transaction, name, newFuncs, newProcs, true);
|
|
|
|
for (SortedObjectsArray<Signature>::iterator i = existingFuncs.begin();
|
|
i != existingFuncs.end(); ++i)
|
|
{
|
|
size_t pos;
|
|
bool found = newFuncs.find(Signature(getPool(), i->name), pos);
|
|
|
|
if (!found || !newFuncs[pos].defined)
|
|
{
|
|
status_exception::raise(
|
|
Arg::Gds(isc_dyn_funcnotdef_package) << i->name.c_str() << name.c_str());
|
|
}
|
|
else if (newFuncs[pos] != *i)
|
|
{
|
|
status_exception::raise(
|
|
Arg::Gds(isc_dyn_funcsignat_package) << i->name.c_str() << name.c_str());
|
|
}
|
|
}
|
|
|
|
for (SortedObjectsArray<Signature>::iterator i = existingProcs.begin();
|
|
i != existingProcs.end(); ++i)
|
|
{
|
|
size_t pos;
|
|
bool found = newProcs.find(Signature(getPool(), i->name), pos);
|
|
|
|
if (!found || !newProcs[pos].defined)
|
|
{
|
|
status_exception::raise(
|
|
Arg::Gds(isc_dyn_procnotdef_package) << i->name.c_str() << name.c_str());
|
|
}
|
|
else if (newProcs[pos] != *i)
|
|
{
|
|
status_exception::raise(
|
|
Arg::Gds(isc_dyn_procsignat_package) << i->name.c_str() << name.c_str());
|
|
}
|
|
|
|
for (SortedObjectsArray<ParameterInfo>::iterator j = newProcs[pos].parameters.begin();
|
|
j != newProcs[pos].parameters.end(); ++j)
|
|
{
|
|
if (!j->defaultSource.isEmpty() || !j->defaultValue.isEmpty())
|
|
{
|
|
status_exception::raise(
|
|
Arg::Gds(isc_dyn_defvaldecl_package) << name.c_str() << i->name.c_str());
|
|
}
|
|
}
|
|
}
|
|
|
|
// Lets recreate default of public procedure/function parameters
|
|
|
|
requestHandle.reset(tdbb, drq_m_pkg_prm_defs, DYN_REQUESTS);
|
|
|
|
FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction)
|
|
PRM IN RDB$PROCEDURE_PARAMETERS
|
|
WITH PRM.RDB$PACKAGE_NAME EQ name.c_str()
|
|
{
|
|
size_t pos;
|
|
if (existingProcs.find(Signature(getPool(), MetaName(PRM.RDB$PROCEDURE_NAME)), pos))
|
|
{
|
|
const Signature& proc = existingProcs[pos];
|
|
|
|
ParameterInfo paramKey(getPool());
|
|
paramKey.type = PRM.RDB$PARAMETER_TYPE;
|
|
paramKey.number = PRM.RDB$PARAMETER_NUMBER;
|
|
|
|
if (proc.parameters.find(paramKey, pos))
|
|
{
|
|
const ParameterInfo& param = proc.parameters[pos];
|
|
|
|
MODIFY PRM
|
|
PRM.RDB$DEFAULT_SOURCE = param.defaultSource;
|
|
PRM.RDB$DEFAULT_SOURCE.NULL = param.defaultSource.isEmpty();
|
|
|
|
PRM.RDB$DEFAULT_VALUE = param.defaultValue;
|
|
PRM.RDB$DEFAULT_VALUE.NULL = param.defaultValue.isEmpty();
|
|
END_MODIFY
|
|
}
|
|
}
|
|
}
|
|
END_FOR
|
|
|
|
requestHandle.reset(tdbb, drq_m_pkg_arg_defs, DYN_REQUESTS);
|
|
|
|
FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction)
|
|
ARG IN RDB$FUNCTION_ARGUMENTS
|
|
WITH ARG.RDB$PACKAGE_NAME EQ name.c_str()
|
|
{
|
|
size_t pos;
|
|
if (existingFuncs.find(Signature(getPool(), MetaName(ARG.RDB$FUNCTION_NAME)), pos))
|
|
{
|
|
const Signature& func = existingFuncs[pos];
|
|
|
|
ParameterInfo paramKey(getPool());
|
|
paramKey.number = ARG.RDB$ARGUMENT_POSITION;
|
|
|
|
if (func.parameters.find(paramKey, pos))
|
|
{
|
|
const ParameterInfo& param = func.parameters[pos];
|
|
|
|
MODIFY ARG
|
|
ARG.RDB$DEFAULT_SOURCE = param.defaultSource;
|
|
ARG.RDB$DEFAULT_SOURCE.NULL = param.defaultSource.isEmpty();
|
|
|
|
ARG.RDB$DEFAULT_VALUE = param.defaultValue;
|
|
ARG.RDB$DEFAULT_VALUE.NULL = param.defaultValue.isEmpty();
|
|
END_MODIFY
|
|
}
|
|
}
|
|
}
|
|
END_FOR
|
|
|
|
executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER,
|
|
DDL_TRIGGER_CREATE_PACKAGE_BODY, name);
|
|
|
|
savePoint.release(); // everything is ok
|
|
}
|
|
|
|
|
|
//----------------------
|
|
|
|
|
|
void DropPackageBodyNode::print(string& text, Array<dsql_nod*>& /*nodes*/) const
|
|
{
|
|
text.printf(
|
|
"DropPackageBodyNode\n"
|
|
" name: '%s'\n",
|
|
name.c_str());
|
|
}
|
|
|
|
|
|
void DropPackageBodyNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch,
|
|
jrd_tra* transaction)
|
|
{
|
|
// run all statements under savepoint control
|
|
AutoSavePoint savePoint(tdbb, transaction);
|
|
|
|
bool found = false;
|
|
AutoCacheRequest requestHandle(tdbb, drq_m_pkg_body2, DYN_REQUESTS);
|
|
|
|
FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction)
|
|
PKG IN RDB$PACKAGES
|
|
WITH PKG.RDB$PACKAGE_NAME EQ name.c_str()
|
|
{
|
|
found = true;
|
|
|
|
executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE,
|
|
DDL_TRIGGER_DROP_PACKAGE_BODY, name);
|
|
|
|
MODIFY PKG
|
|
PKG.RDB$PACKAGE_BODY_SOURCE.NULL = TRUE;
|
|
|
|
dsc desc;
|
|
desc.makeText(name.length(), ttype_metadata,
|
|
(UCHAR*) const_cast<char*>(name.c_str())); // safe const_cast
|
|
DFW_post_work(transaction, dfw_drop_package_body, &desc, 0);
|
|
END_MODIFY
|
|
}
|
|
END_FOR
|
|
|
|
if (!found)
|
|
{
|
|
status_exception::raise(
|
|
Arg::Gds(isc_no_meta_update) <<
|
|
Arg::Gds(isc_dyn_package_not_found) << Arg::Str(name));
|
|
}
|
|
|
|
requestHandle.reset(tdbb, drq_m_pkg_fun, DYN_REQUESTS);
|
|
|
|
FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction)
|
|
FUN IN RDB$FUNCTIONS
|
|
WITH FUN.RDB$PACKAGE_NAME EQ name.c_str()
|
|
{
|
|
if (!FUN.RDB$PRIVATE_FLAG.NULL && FUN.RDB$PRIVATE_FLAG != 0)
|
|
{
|
|
DropFunctionNode dropNode(getPool(), FUN.RDB$FUNCTION_NAME);
|
|
dropNode.package = name;
|
|
dropNode.dsqlPass(dsqlScratch);
|
|
dropNode.executeDdl(tdbb, dsqlScratch, transaction);
|
|
}
|
|
else
|
|
{
|
|
MODIFY FUN
|
|
FUN.RDB$FUNCTION_TYPE.NULL = TRUE;
|
|
FUN.RDB$FUNCTION_BLR.NULL = TRUE;
|
|
FUN.RDB$DEBUG_INFO.NULL = TRUE;
|
|
FUN.RDB$MODULE_NAME.NULL = TRUE;
|
|
FUN.RDB$ENGINE_NAME.NULL = TRUE;
|
|
FUN.RDB$ENTRYPOINT.NULL = TRUE;
|
|
END_MODIFY
|
|
}
|
|
}
|
|
END_FOR
|
|
|
|
requestHandle.reset(tdbb, drq_m_pkg_prc, DYN_REQUESTS);
|
|
|
|
FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction)
|
|
PRC IN RDB$PROCEDURES
|
|
WITH PRC.RDB$PACKAGE_NAME EQ name.c_str()
|
|
{
|
|
if (!PRC.RDB$PRIVATE_FLAG.NULL && PRC.RDB$PRIVATE_FLAG != 0)
|
|
{
|
|
DropProcedureNode dropNode(getPool(), PRC.RDB$PROCEDURE_NAME);
|
|
dropNode.package = name;
|
|
dropNode.dsqlPass(dsqlScratch);
|
|
dropNode.executeDdl(tdbb, dsqlScratch, transaction);
|
|
}
|
|
else
|
|
{
|
|
MODIFY PRC
|
|
PRC.RDB$PROCEDURE_TYPE.NULL = TRUE;
|
|
PRC.RDB$PROCEDURE_BLR.NULL = TRUE;
|
|
PRC.RDB$DEBUG_INFO.NULL = TRUE;
|
|
PRC.RDB$ENGINE_NAME.NULL = TRUE;
|
|
PRC.RDB$ENTRYPOINT.NULL = TRUE;
|
|
END_MODIFY
|
|
}
|
|
}
|
|
END_FOR
|
|
|
|
executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER,
|
|
DDL_TRIGGER_DROP_PACKAGE_BODY, name);
|
|
|
|
savePoint.release(); // everything is ok
|
|
}
|
|
|
|
|
|
} // namespace Jrd
|