mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-22 16:43:03 +01:00
Corrections and documentation improvements to #4203 - DROP [IF EXISTS].
This commit is contained in:
parent
ac5c7ae0c6
commit
d29e9cecb8
@ -636,7 +636,15 @@ DDL enhancements in Firebird v6.
|
|||||||
|
|
||||||
1) DROP [IF EXISTS]
|
1) DROP [IF EXISTS]
|
||||||
|
|
||||||
Using subclause IF EXISTS, it's now possible to try to drop objects and do not get errors when they di not exists.
|
Using subclause IF EXISTS, it's now possible to try to drop objects and do not get errors when they did not exist.
|
||||||
|
|
||||||
|
For ALTER TABLE ... DROP subclause, DDL triggers are not fired if there are only DROP IF EXISTS subclauses and all
|
||||||
|
of them are related to non existing columns or constraints.
|
||||||
|
|
||||||
|
For others commands where IF EXISTS is part of the main command, DDL triggers are not fired when the object
|
||||||
|
did not exist.
|
||||||
|
|
||||||
|
The following statements are supported:
|
||||||
|
|
||||||
DROP EXCEPTION [IF EXISTS] <exception>
|
DROP EXCEPTION [IF EXISTS] <exception>
|
||||||
DROP INDEX [IF EXISTS] <index>
|
DROP INDEX [IF EXISTS] <index>
|
||||||
|
@ -6235,11 +6235,21 @@ void RelationNode::FieldDefinition::store(thread_db* tdbb, jrd_tra* transaction)
|
|||||||
// triggers and the RI enforcement for dropping foreign key column is
|
// triggers and the RI enforcement for dropping foreign key column is
|
||||||
// done by code and system triggers. See the functional description of
|
// done by code and system triggers. See the functional description of
|
||||||
// deleteKeyConstraint function for detail.
|
// deleteKeyConstraint function for detail.
|
||||||
void RelationNode::deleteLocalField(thread_db* tdbb, jrd_tra* transaction,
|
bool RelationNode::deleteLocalField(thread_db* tdbb, jrd_tra* transaction,
|
||||||
const MetaName& relationName, const MetaName& fieldName, bool silent)
|
const MetaName& relationName, const MetaName& fieldName, bool silent, std::function<void()> preChangeHandler)
|
||||||
{
|
{
|
||||||
|
bool preChangeHandlerWasExecuted = false;
|
||||||
|
|
||||||
|
const auto executePreChangeHandler = [&]()
|
||||||
|
{
|
||||||
|
if (!preChangeHandlerWasExecuted)
|
||||||
|
{
|
||||||
|
preChangeHandlerWasExecuted = true;
|
||||||
|
preChangeHandler();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
AutoCacheRequest request(tdbb, drq_l_dep_flds, DYN_REQUESTS);
|
AutoCacheRequest request(tdbb, drq_l_dep_flds, DYN_REQUESTS);
|
||||||
bool found = false;
|
|
||||||
|
|
||||||
// Make sure that column is not referenced in any views.
|
// Make sure that column is not referenced in any views.
|
||||||
|
|
||||||
@ -6255,6 +6265,8 @@ void RelationNode::deleteLocalField(thread_db* tdbb, jrd_tra* transaction,
|
|||||||
X.RDB$RELATION_NAME EQ Z.RDB$RELATION_NAME AND
|
X.RDB$RELATION_NAME EQ Z.RDB$RELATION_NAME AND
|
||||||
Y.RDB$VIEW_CONTEXT EQ Z.RDB$VIEW_CONTEXT
|
Y.RDB$VIEW_CONTEXT EQ Z.RDB$VIEW_CONTEXT
|
||||||
{
|
{
|
||||||
|
executePreChangeHandler();
|
||||||
|
|
||||||
// msg 52: "field %s from relation %s is referenced in view %s"
|
// msg 52: "field %s from relation %s is referenced in view %s"
|
||||||
status_exception::raise(
|
status_exception::raise(
|
||||||
Arg::PrivateDyn(52) << fieldName << relationName << Y.RDB$RELATION_NAME);
|
Arg::PrivateDyn(52) << fieldName << relationName << Y.RDB$RELATION_NAME);
|
||||||
@ -6279,6 +6291,8 @@ void RelationNode::deleteLocalField(thread_db* tdbb, jrd_tra* transaction,
|
|||||||
IDX.RDB$INDEX_NAME EQ REL_CONST.RDB$INDEX_NAME AND
|
IDX.RDB$INDEX_NAME EQ REL_CONST.RDB$INDEX_NAME AND
|
||||||
REL_CONST.RDB$CONSTRAINT_TYPE EQ FOREIGN_KEY
|
REL_CONST.RDB$CONSTRAINT_TYPE EQ FOREIGN_KEY
|
||||||
{
|
{
|
||||||
|
executePreChangeHandler();
|
||||||
|
|
||||||
if (IDX.RDB$SEGMENT_COUNT == 1)
|
if (IDX.RDB$SEGMENT_COUNT == 1)
|
||||||
{
|
{
|
||||||
deleteKeyConstraint(tdbb, transaction, relationName,
|
deleteKeyConstraint(tdbb, transaction, relationName,
|
||||||
@ -6311,6 +6325,8 @@ void RelationNode::deleteLocalField(thread_db* tdbb, jrd_tra* transaction,
|
|||||||
WITH REL_CONST.RDB$RELATION_NAME EQ IDX.RDB$RELATION_NAME AND
|
WITH REL_CONST.RDB$RELATION_NAME EQ IDX.RDB$RELATION_NAME AND
|
||||||
REL_CONST.RDB$INDEX_NAME EQ IDX.RDB$INDEX_NAME
|
REL_CONST.RDB$INDEX_NAME EQ IDX.RDB$INDEX_NAME
|
||||||
{
|
{
|
||||||
|
executePreChangeHandler();
|
||||||
|
|
||||||
// msg 187: "field %s from relation %s is referenced in index %s"
|
// msg 187: "field %s from relation %s is referenced in index %s"
|
||||||
status_exception::raise(
|
status_exception::raise(
|
||||||
Arg::PrivateDyn(187) <<
|
Arg::PrivateDyn(187) <<
|
||||||
@ -6323,12 +6339,15 @@ void RelationNode::deleteLocalField(thread_db* tdbb, jrd_tra* transaction,
|
|||||||
|
|
||||||
request.reset(tdbb, drq_e_lfield, DYN_REQUESTS);
|
request.reset(tdbb, drq_e_lfield, DYN_REQUESTS);
|
||||||
|
|
||||||
found = false;
|
bool found = false;
|
||||||
|
|
||||||
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
|
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
|
||||||
RFR IN RDB$RELATION_FIELDS
|
RFR IN RDB$RELATION_FIELDS
|
||||||
WITH RFR.RDB$FIELD_NAME EQ fieldName.c_str() AND
|
WITH RFR.RDB$FIELD_NAME EQ fieldName.c_str() AND
|
||||||
RFR.RDB$RELATION_NAME EQ relationName.c_str()
|
RFR.RDB$RELATION_NAME EQ relationName.c_str()
|
||||||
{
|
{
|
||||||
|
executePreChangeHandler();
|
||||||
|
|
||||||
if (!RFR.RDB$GENERATOR_NAME.NULL)
|
if (!RFR.RDB$GENERATOR_NAME.NULL)
|
||||||
DropSequenceNode::deleteIdentity(tdbb, transaction, RFR.RDB$GENERATOR_NAME);
|
DropSequenceNode::deleteIdentity(tdbb, transaction, RFR.RDB$GENERATOR_NAME);
|
||||||
|
|
||||||
@ -6354,6 +6373,8 @@ void RelationNode::deleteLocalField(thread_db* tdbb, jrd_tra* transaction,
|
|||||||
PRIV.RDB$OBJECT_TYPE = obj_relation AND
|
PRIV.RDB$OBJECT_TYPE = obj_relation AND
|
||||||
PRIV.RDB$GRANTOR NOT MISSING
|
PRIV.RDB$GRANTOR NOT MISSING
|
||||||
{
|
{
|
||||||
|
executePreChangeHandler();
|
||||||
|
|
||||||
ERASE PRIV;
|
ERASE PRIV;
|
||||||
}
|
}
|
||||||
END_FOR
|
END_FOR
|
||||||
@ -6363,6 +6384,8 @@ void RelationNode::deleteLocalField(thread_db* tdbb, jrd_tra* transaction,
|
|||||||
// msg 176: "column %s does not exist in table/view %s"
|
// msg 176: "column %s does not exist in table/view %s"
|
||||||
status_exception::raise(Arg::PrivateDyn(176) << fieldName << relationName);
|
status_exception::raise(Arg::PrivateDyn(176) << fieldName << relationName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RelationNode::defineField(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch,
|
void RelationNode::defineField(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch,
|
||||||
@ -7640,6 +7663,17 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc
|
|||||||
Arg::Gds(isc_random) << linecol***/);
|
Arg::Gds(isc_random) << linecol***/);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool beforeTriggerWasExecuted = false;
|
||||||
|
|
||||||
|
const auto executeBeforeTrigger = [&]()
|
||||||
|
{
|
||||||
|
if (!beforeTriggerWasExecuted)
|
||||||
|
{
|
||||||
|
beforeTriggerWasExecuted = true;
|
||||||
|
executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_ALTER_TABLE, name, nullptr);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// If there is an error, get rid of the cached data.
|
// If there is an error, get rid of the cached data.
|
||||||
|
|
||||||
try
|
try
|
||||||
@ -7647,9 +7681,6 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc
|
|||||||
// run all statements under savepoint control
|
// run all statements under savepoint control
|
||||||
AutoSavePoint savePoint(tdbb, transaction);
|
AutoSavePoint savePoint(tdbb, transaction);
|
||||||
|
|
||||||
executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_ALTER_TABLE,
|
|
||||||
name, NULL);
|
|
||||||
|
|
||||||
ObjectsArray<CreateDropConstraint> constraints;
|
ObjectsArray<CreateDropConstraint> constraints;
|
||||||
|
|
||||||
for (NestConst<Clause>* i = clauses.begin(); i != clauses.end(); ++i)
|
for (NestConst<Clause>* i = clauses.begin(); i != clauses.end(); ++i)
|
||||||
@ -7657,17 +7688,20 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc
|
|||||||
switch ((*i)->type)
|
switch ((*i)->type)
|
||||||
{
|
{
|
||||||
case Clause::TYPE_ADD_COLUMN:
|
case Clause::TYPE_ADD_COLUMN:
|
||||||
|
executeBeforeTrigger();
|
||||||
defineField(tdbb, dsqlScratch, transaction,
|
defineField(tdbb, dsqlScratch, transaction,
|
||||||
static_cast<AddColumnClause*>(i->getObject()), -1, NULL);
|
static_cast<AddColumnClause*>(i->getObject()), -1, NULL);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Clause::TYPE_ALTER_COL_TYPE:
|
case Clause::TYPE_ALTER_COL_TYPE:
|
||||||
modifyField(tdbb, dsqlScratch, transaction,
|
executeBeforeTrigger();
|
||||||
static_cast<AlterColTypeClause*>(i->getObject()));
|
modifyField(tdbb, dsqlScratch, transaction, static_cast<AlterColTypeClause*>(i->getObject()));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Clause::TYPE_ALTER_COL_NAME:
|
case Clause::TYPE_ALTER_COL_NAME:
|
||||||
{
|
{
|
||||||
|
executeBeforeTrigger();
|
||||||
|
|
||||||
const AlterColNameClause* clause =
|
const AlterColNameClause* clause =
|
||||||
static_cast<const AlterColNameClause*>(i->getObject());
|
static_cast<const AlterColNameClause*>(i->getObject());
|
||||||
AutoRequest request;
|
AutoRequest request;
|
||||||
@ -7728,6 +7762,8 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc
|
|||||||
|
|
||||||
case Clause::TYPE_ALTER_COL_NULL:
|
case Clause::TYPE_ALTER_COL_NULL:
|
||||||
{
|
{
|
||||||
|
executeBeforeTrigger();
|
||||||
|
|
||||||
const AlterColNullClause* clause =
|
const AlterColNullClause* clause =
|
||||||
static_cast<const AlterColNullClause*>(i->getObject());
|
static_cast<const AlterColNullClause*>(i->getObject());
|
||||||
|
|
||||||
@ -7797,6 +7833,8 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc
|
|||||||
|
|
||||||
case Clause::TYPE_ALTER_COL_POS:
|
case Clause::TYPE_ALTER_COL_POS:
|
||||||
{
|
{
|
||||||
|
executeBeforeTrigger();
|
||||||
|
|
||||||
const AlterColPosClause* clause =
|
const AlterColPosClause* clause =
|
||||||
static_cast<const AlterColPosClause*>(i->getObject());
|
static_cast<const AlterColPosClause*>(i->getObject());
|
||||||
// CVC: Since now the parser accepts pos=1..N, let's subtract one here.
|
// CVC: Since now the parser accepts pos=1..N, let's subtract one here.
|
||||||
@ -7828,11 +7866,12 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc
|
|||||||
Arg::Gds(isc_dsql_construct_err));
|
Arg::Gds(isc_dsql_construct_err));
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteLocalField(tdbb, transaction, name, clause->name, clause->silent);
|
deleteLocalField(tdbb, transaction, name, clause->name, clause->silent, executeBeforeTrigger);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case Clause::TYPE_ADD_CONSTRAINT:
|
case Clause::TYPE_ADD_CONSTRAINT:
|
||||||
|
executeBeforeTrigger();
|
||||||
makeConstraint(tdbb, dsqlScratch, transaction,
|
makeConstraint(tdbb, dsqlScratch, transaction,
|
||||||
static_cast<AddConstraintClause*>(i->getObject()), constraints);
|
static_cast<AddConstraintClause*>(i->getObject()), constraints);
|
||||||
break;
|
break;
|
||||||
@ -7847,6 +7886,8 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc
|
|||||||
|
|
||||||
case Clause::TYPE_ALTER_SQL_SECURITY:
|
case Clause::TYPE_ALTER_SQL_SECURITY:
|
||||||
{
|
{
|
||||||
|
executeBeforeTrigger();
|
||||||
|
|
||||||
AutoRequest request;
|
AutoRequest request;
|
||||||
|
|
||||||
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
|
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
|
||||||
@ -7874,6 +7915,8 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc
|
|||||||
{
|
{
|
||||||
fb_assert(replicationState.isAssigned());
|
fb_assert(replicationState.isAssigned());
|
||||||
|
|
||||||
|
executeBeforeTrigger();
|
||||||
|
|
||||||
if (replicationState.asBool())
|
if (replicationState.asBool())
|
||||||
{
|
{
|
||||||
// Add table to the publication
|
// Add table to the publication
|
||||||
@ -7929,10 +7972,14 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc
|
|||||||
RC.RDB$RELATION_NAME EQ name.c_str()
|
RC.RDB$RELATION_NAME EQ name.c_str()
|
||||||
{
|
{
|
||||||
found = true;
|
found = true;
|
||||||
|
executeBeforeTrigger();
|
||||||
ERASE RC;
|
ERASE RC;
|
||||||
}
|
}
|
||||||
END_FOR
|
END_FOR
|
||||||
|
|
||||||
|
if (!constraint->silent && !found)
|
||||||
|
executeBeforeTrigger();
|
||||||
|
|
||||||
if (!found && !constraint->silent)
|
if (!found && !constraint->silent)
|
||||||
{
|
{
|
||||||
// msg 130: "CONSTRAINT %s does not exist."
|
// msg 130: "CONSTRAINT %s does not exist."
|
||||||
@ -7941,8 +7988,8 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_ALTER_TABLE,
|
if (beforeTriggerWasExecuted)
|
||||||
name, NULL);
|
executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_ALTER_TABLE, name, nullptr);
|
||||||
|
|
||||||
savePoint.release(); // everything is ok
|
savePoint.release(); // everything is ok
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#ifndef DSQL_DDL_NODES_H
|
#ifndef DSQL_DDL_NODES_H
|
||||||
#define DSQL_DDL_NODES_H
|
#define DSQL_DDL_NODES_H
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include "firebird/impl/blr.h"
|
#include "firebird/impl/blr.h"
|
||||||
#include "../jrd/dyn.h"
|
#include "../jrd/dyn.h"
|
||||||
@ -1510,8 +1511,9 @@ public:
|
|||||||
|
|
||||||
RelationNode(MemoryPool& p, RelationSourceNode* aDsqlNode);
|
RelationNode(MemoryPool& p, RelationSourceNode* aDsqlNode);
|
||||||
|
|
||||||
static void deleteLocalField(thread_db* tdbb, jrd_tra* transaction,
|
static bool deleteLocalField(thread_db* tdbb, jrd_tra* transaction,
|
||||||
const MetaName& relationName, const MetaName& fieldName, bool silent);
|
const MetaName& relationName, const MetaName& fieldName, bool silent,
|
||||||
|
std::function<void()> preChangeHandler = {});
|
||||||
|
|
||||||
static void addToPublication(thread_db* tdbb, jrd_tra* transaction,
|
static void addToPublication(thread_db* tdbb, jrd_tra* transaction,
|
||||||
const MetaName& tableName, const MetaName& pubTame);
|
const MetaName& tableName, const MetaName& pubTame);
|
||||||
|
Loading…
Reference in New Issue
Block a user