| 
      
      
      From: <asf...@us...> - 2010-07-26 02:38:13
      
     | 
| Revision: 51368
          http://firebird.svn.sourceforge.net/firebird/?rev=51368&view=rev
Author:   asfernandes
Date:     2010-07-26 02:37:57 +0000 (Mon, 26 Jul 2010)
Log Message:
-----------
Refactor CREATE/ALTER/DROP/RECREATE TABLE and DROP VIEW commands
Modified Paths:
--------------
    firebird/trunk/lang_helpers/gds_codes.ftn
    firebird/trunk/lang_helpers/gds_codes.pas
    firebird/trunk/src/common/classes/ByteChunk.h
    firebird/trunk/src/common/classes/objects_array.h
    firebird/trunk/src/dsql/BlrWriter.h
    firebird/trunk/src/dsql/DdlNodes.epp
    firebird/trunk/src/dsql/DdlNodes.h
    firebird/trunk/src/dsql/Nodes.h
    firebird/trunk/src/dsql/PackageNodes.epp
    firebird/trunk/src/dsql/PackageNodes.h
    firebird/trunk/src/dsql/ddl.cpp
    firebird/trunk/src/dsql/ddl_proto.h
    firebird/trunk/src/dsql/dsql.h
    firebird/trunk/src/dsql/node.h
    firebird/trunk/src/dsql/parse.y
    firebird/trunk/src/dsql/pass1.cpp
    firebird/trunk/src/gpre/gpre.h
    firebird/trunk/src/include/gen/codetext.h
    firebird/trunk/src/include/gen/iberror.h
    firebird/trunk/src/include/gen/msgs.h
    firebird/trunk/src/include/gen/sql_code.h
    firebird/trunk/src/include/gen/sql_state.h
    firebird/trunk/src/jrd/constants.h
    firebird/trunk/src/jrd/drq.h
    firebird/trunk/src/jrd/dyn.epp
    firebird/trunk/src/jrd/dyn_def.epp
    firebird/trunk/src/jrd/dyn_del.epp
    firebird/trunk/src/jrd/dyn_df_proto.h
    firebird/trunk/src/jrd/dyn_dl_proto.h
    firebird/trunk/src/jrd/dyn_md_proto.h
    firebird/trunk/src/jrd/dyn_mod.epp
    firebird/trunk/src/jrd/dyn_ut_proto.h
    firebird/trunk/src/jrd/dyn_util.epp
    firebird/trunk/src/msgs/facilities2.sql
    firebird/trunk/src/msgs/messages2.sql
    firebird/trunk/src/msgs/system_errors2.sql
Modified: firebird/trunk/lang_helpers/gds_codes.ftn
===================================================================
--- firebird/trunk/lang_helpers/gds_codes.ftn	2010-07-26 02:14:48 UTC (rev 51367)
+++ firebird/trunk/lang_helpers/gds_codes.ftn	2010-07-26 02:37:57 UTC (rev 51368)
@@ -1996,6 +1996,86 @@
       PARAMETER (GDS__dsql_invalid_type_neg            = 336397256)
       INTEGER*4 GDS__dsql_max_distinct_items         
       PARAMETER (GDS__dsql_max_distinct_items          = 336397257)
+      INTEGER*4 GDS__dsql_alter_charset_failed       
+      PARAMETER (GDS__dsql_alter_charset_failed        = 336397258)
+      INTEGER*4 GDS__dsql_comment_on_failed          
+      PARAMETER (GDS__dsql_comment_on_failed           = 336397259)
+      INTEGER*4 GDS__dsql_create_func_failed         
+      PARAMETER (GDS__dsql_create_func_failed          = 336397260)
+      INTEGER*4 GDS__dsql_alter_func_failed          
+      PARAMETER (GDS__dsql_alter_func_failed           = 336397261)
+      INTEGER*4 GDS__dsql_create_alter_func_failed   
+      PARAMETER (GDS__dsql_create_alter_func_failed    = 336397262)
+      INTEGER*4 GDS__dsql_drop_func_failed           
+      PARAMETER (GDS__dsql_drop_func_failed            = 336397263)
+      INTEGER*4 GDS__dsql_recreate_func_failed       
+      PARAMETER (GDS__dsql_recreate_func_failed        = 336397264)
+      INTEGER*4 GDS__dsql_create_proc_failed         
+      PARAMETER (GDS__dsql_create_proc_failed          = 336397265)
+      INTEGER*4 GDS__dsql_alter_proc_failed          
+      PARAMETER (GDS__dsql_alter_proc_failed           = 336397266)
+      INTEGER*4 GDS__dsql_create_alter_proc_failed   
+      PARAMETER (GDS__dsql_create_alter_proc_failed    = 336397267)
+      INTEGER*4 GDS__dsql_drop_proc_failed           
+      PARAMETER (GDS__dsql_drop_proc_failed            = 336397268)
+      INTEGER*4 GDS__dsql_recreate_proc_failed       
+      PARAMETER (GDS__dsql_recreate_proc_failed        = 336397269)
+      INTEGER*4 GDS__dsql_create_trigger_failed      
+      PARAMETER (GDS__dsql_create_trigger_failed       = 336397270)
+      INTEGER*4 GDS__dsql_alter_trigger_failed       
+      PARAMETER (GDS__dsql_alter_trigger_failed        = 336397271)
+      INTEGER*4 GDS__dsql_create_alter_trigger_failed
+      PARAMETER (GDS__dsql_create_alter_trigger_failed = 336397272)
+      INTEGER*4 GDS__dsql_drop_trigger_failed        
+      PARAMETER (GDS__dsql_drop_trigger_failed         = 336397273)
+      INTEGER*4 GDS__dsql_recreate_trigger_failed    
+      PARAMETER (GDS__dsql_recreate_trigger_failed     = 336397274)
+      INTEGER*4 GDS__dsql_create_collation_failed    
+      PARAMETER (GDS__dsql_create_collation_failed     = 336397275)
+      INTEGER*4 GDS__dsql_drop_collation_failed      
+      PARAMETER (GDS__dsql_drop_collation_failed       = 336397276)
+      INTEGER*4 GDS__dsql_create_domain_failed       
+      PARAMETER (GDS__dsql_create_domain_failed        = 336397277)
+      INTEGER*4 GDS__dsql_alter_domain_failed        
+      PARAMETER (GDS__dsql_alter_domain_failed         = 336397278)
+      INTEGER*4 GDS__dsql_drop_domain_failed         
+      PARAMETER (GDS__dsql_drop_domain_failed          = 336397279)
+      INTEGER*4 GDS__dsql_create_except_failed       
+      PARAMETER (GDS__dsql_create_except_failed        = 336397280)
+      INTEGER*4 GDS__dsql_alter_except_failed        
+      PARAMETER (GDS__dsql_alter_except_failed         = 336397281)
+      INTEGER*4 GDS__dsql_create_alter_except_failed 
+      PARAMETER (GDS__dsql_create_alter_except_failed  = 336397282)
+      INTEGER*4 GDS__dsql_recreate_except_failed     
+      PARAMETER (GDS__dsql_recreate_except_failed      = 336397283)
+      INTEGER*4 GDS__dsql_drop_except_failed         
+      PARAMETER (GDS__dsql_drop_except_failed          = 336397284)
+      INTEGER*4 GDS__dsql_create_sequence_failed     
+      PARAMETER (GDS__dsql_create_sequence_failed      = 336397285)
+      INTEGER*4 GDS__dsql_create_table_failed        
+      PARAMETER (GDS__dsql_create_table_failed         = 336397286)
+      INTEGER*4 GDS__dsql_alter_table_failed         
+      PARAMETER (GDS__dsql_alter_table_failed          = 336397287)
+      INTEGER*4 GDS__dsql_drop_table_failed          
+      PARAMETER (GDS__dsql_drop_table_failed           = 336397288)
+      INTEGER*4 GDS__dsql_recreate_table_failed      
+      PARAMETER (GDS__dsql_recreate_table_failed       = 336397289)
+      INTEGER*4 GDS__dsql_create_pack_failed         
+      PARAMETER (GDS__dsql_create_pack_failed          = 336397290)
+      INTEGER*4 GDS__dsql_alter_pack_failed          
+      PARAMETER (GDS__dsql_alter_pack_failed           = 336397291)
+      INTEGER*4 GDS__dsql_create_alter_pack_failed   
+      PARAMETER (GDS__dsql_create_alter_pack_failed    = 336397292)
+      INTEGER*4 GDS__dsql_drop_pack_failed           
+      PARAMETER (GDS__dsql_drop_pack_failed            = 336397293)
+      INTEGER*4 GDS__dsql_recreate_pack_failed       
+      PARAMETER (GDS__dsql_recreate_pack_failed        = 336397294)
+      INTEGER*4 GDS__dsql_create_pack_body_failed    
+      PARAMETER (GDS__dsql_create_pack_body_failed     = 336397295)
+      INTEGER*4 GDS__dsql_drop_pack_body_failed      
+      PARAMETER (GDS__dsql_drop_pack_body_failed       = 336397296)
+      INTEGER*4 GDS__dsql_recreate_pack_body_failed  
+      PARAMETER (GDS__dsql_recreate_pack_body_failed   = 336397297)
       INTEGER*4 GDS__gsec_cant_open_db               
       PARAMETER (GDS__gsec_cant_open_db                = 336723983)
       INTEGER*4 GDS__gsec_switches_error             
Modified: firebird/trunk/lang_helpers/gds_codes.pas
===================================================================
--- firebird/trunk/lang_helpers/gds_codes.pas	2010-07-26 02:14:48 UTC (rev 51367)
+++ firebird/trunk/lang_helpers/gds_codes.pas	2010-07-26 02:37:57 UTC (rev 51368)
@@ -1005,6 +1005,46 @@
 	gds_dsql_nostring_neg_dial3          = 336397255;
 	gds_dsql_invalid_type_neg            = 336397256;
 	gds_dsql_max_distinct_items          = 336397257;
+	gds_dsql_alter_charset_failed        = 336397258;
+	gds_dsql_comment_on_failed           = 336397259;
+	gds_dsql_create_func_failed          = 336397260;
+	gds_dsql_alter_func_failed           = 336397261;
+	gds_dsql_create_alter_func_failed    = 336397262;
+	gds_dsql_drop_func_failed            = 336397263;
+	gds_dsql_recreate_func_failed        = 336397264;
+	gds_dsql_create_proc_failed          = 336397265;
+	gds_dsql_alter_proc_failed           = 336397266;
+	gds_dsql_create_alter_proc_failed    = 336397267;
+	gds_dsql_drop_proc_failed            = 336397268;
+	gds_dsql_recreate_proc_failed        = 336397269;
+	gds_dsql_create_trigger_failed       = 336397270;
+	gds_dsql_alter_trigger_failed        = 336397271;
+	gds_dsql_create_alter_trigger_failed = 336397272;
+	gds_dsql_drop_trigger_failed         = 336397273;
+	gds_dsql_recreate_trigger_failed     = 336397274;
+	gds_dsql_create_collation_failed     = 336397275;
+	gds_dsql_drop_collation_failed       = 336397276;
+	gds_dsql_create_domain_failed        = 336397277;
+	gds_dsql_alter_domain_failed         = 336397278;
+	gds_dsql_drop_domain_failed          = 336397279;
+	gds_dsql_create_except_failed        = 336397280;
+	gds_dsql_alter_except_failed         = 336397281;
+	gds_dsql_create_alter_except_failed  = 336397282;
+	gds_dsql_recreate_except_failed      = 336397283;
+	gds_dsql_drop_except_failed          = 336397284;
+	gds_dsql_create_sequence_failed      = 336397285;
+	gds_dsql_create_table_failed         = 336397286;
+	gds_dsql_alter_table_failed          = 336397287;
+	gds_dsql_drop_table_failed           = 336397288;
+	gds_dsql_recreate_table_failed       = 336397289;
+	gds_dsql_create_pack_failed          = 336397290;
+	gds_dsql_alter_pack_failed           = 336397291;
+	gds_dsql_create_alter_pack_failed    = 336397292;
+	gds_dsql_drop_pack_failed            = 336397293;
+	gds_dsql_recreate_pack_failed        = 336397294;
+	gds_dsql_create_pack_body_failed     = 336397295;
+	gds_dsql_drop_pack_body_failed       = 336397296;
+	gds_dsql_recreate_pack_body_failed   = 336397297;
 	gds_gsec_cant_open_db                = 336723983;
 	gds_gsec_switches_error              = 336723984;
 	gds_gsec_no_op_spec                  = 336723985;
Modified: firebird/trunk/src/common/classes/ByteChunk.h
===================================================================
--- firebird/trunk/src/common/classes/ByteChunk.h	2010-07-26 02:14:48 UTC (rev 51367)
+++ firebird/trunk/src/common/classes/ByteChunk.h	2010-07-26 02:37:57 UTC (rev 51368)
@@ -24,6 +24,7 @@
 #define COMMON_BYTE_CHUNK_H
 
 #include "../common/classes/array.h"
+#include "../common/classes/fb_string.h"
 
 namespace Firebird {
 
@@ -46,8 +47,22 @@
 	{
 	}
 
-	const UCHAR* const data;
-	const size_t length;
+	// String buffer.
+	ByteChunk(string& str)
+		: data((UCHAR*) str.c_str()),
+		  length(str.length())
+	{
+	}
+
+	// Empty.
+	ByteChunk()
+		: data(NULL),
+		  length(0)
+	{
+	}
+
+	const UCHAR* data;
+	size_t length;
 };
 
 }	// namespace Firebird
Modified: firebird/trunk/src/common/classes/objects_array.h
===================================================================
--- firebird/trunk/src/common/classes/objects_array.h	2010-07-26 02:14:48 UTC (rev 51367)
+++ firebird/trunk/src/common/classes/objects_array.h	2010-07-26 02:37:57 UTC (rev 51368)
@@ -279,6 +279,11 @@
 		size_t getCount() const {return inherited::getCount();}
 		size_t getCapacity() const {return inherited::getCapacity();}
 
+		bool hasData() const
+		{
+			return getCount() != 0;
+		}
+
 		bool isEmpty() const
 		{
 			return getCount() == 0;
Modified: firebird/trunk/src/dsql/BlrWriter.h
===================================================================
--- firebird/trunk/src/dsql/BlrWriter.h	2010-07-26 02:14:48 UTC (rev 51367)
+++ firebird/trunk/src/dsql/BlrWriter.h	2010-07-26 02:37:57 UTC (rev 51368)
@@ -36,6 +36,9 @@
 class BlrWriter : public Firebird::PermanentStorage
 {
 public:
+	typedef Firebird::HalfStaticArray<UCHAR, 1024> BlrData;
+	typedef Firebird::HalfStaticArray<UCHAR, 128> DebugData;
+
 	explicit BlrWriter(MemoryPool& p)
 		: PermanentStorage(p),
 		  blrData(p),
@@ -44,6 +47,10 @@
 	{
 	}
 
+	virtual ~BlrWriter()
+	{
+	}
+
 	void appendUChar(const UCHAR byte)
 	{
 		blrData.add(byte);
@@ -126,8 +133,8 @@
 	void putDebugArgument(UCHAR, USHORT, const TEXT*);
 	void appendDebugInfo();
 
-	Firebird::HalfStaticArray<UCHAR, 1024>& getBlrData() { return blrData; }
-	Firebird::HalfStaticArray<UCHAR, 128>& getDebugData() { return debugData; }
+	BlrData& getBlrData() { return blrData; }
+	DebugData& getDebugData() { return debugData; }
 
 	ULONG getBaseOffset() const { return baseOffset; }
 	void setBaseOffset(ULONG value) { baseOffset = value; }
@@ -138,8 +145,8 @@
 	virtual bool isDdlDyn() = 0;
 
 private:
-	Firebird::HalfStaticArray<UCHAR, 1024> blrData;
-	Firebird::HalfStaticArray<UCHAR, 128> debugData;
+	BlrData blrData;
+	DebugData debugData;
 	ULONG baseOffset;					// place to go back and stuff in blr length
 };
 
Modified: firebird/trunk/src/dsql/DdlNodes.epp
===================================================================
--- firebird/trunk/src/dsql/DdlNodes.epp	2010-07-26 02:14:48 UTC (rev 51367)
+++ firebird/trunk/src/dsql/DdlNodes.epp	2010-07-26 02:37:57 UTC (rev 51368)
@@ -19,10 +19,12 @@
  */
 
 #include "firebird.h"
+#include "dyn_consts.h"
 #include "../jrd/common.h"
 #include "../dsql/DdlNodes.h"
 #include "../dsql/node.h"
 #include "../jrd/blr.h"
+#include "../jrd/btr.h"
 #include "../jrd/dyn.h"
 #include "../jrd/flags.h"
 #include "../jrd/intl.h"
@@ -30,6 +32,7 @@
 #include "../jrd/msg_encode.h"
 #include "../jrd/obj.h"
 #include "../jrd/tra.h"
+#include "../jrd/os/path_utils.h"
 #include "../jrd/IntlManager.h"
 #include "../jrd/PreparedStatement.h"
 #include "../jrd/blb_proto.h"
@@ -39,7 +42,9 @@
 #include "../jrd/dyn_ut_proto.h"
 #include "../jrd/exe_proto.h"
 #include "../jrd/intl_proto.h"
+#include "../jrd/isc_f_proto.h"
 #include "../jrd/met_proto.h"
+#include "../jrd/scl_proto.h"
 #include "../jrd/vio_proto.h"
 #include "../dsql/ddl_proto.h"
 #include "../dsql/errd_proto.h"
@@ -49,14 +54,39 @@
 #include "../dsql/pass1_proto.h"
 #include "../common/StatusArg.h"
 
-using namespace Firebird;
-
 namespace Jrd {
 
 using namespace Firebird;
 using namespace Dsql;
 
-static void rethrowMetaException(const status_exception& ex, ISC_STATUS code, bool metaDataException);
+static void checkForeignKeyTempScope(thread_db* tdbb, jrd_tra* transaction,
+	const MetaName&	childRelName, const MetaName& masterIndexName);
+static void checkSpTrigDependency(thread_db* tdbb, jrd_tra* transaction,
+	const MetaName& relationName, const MetaName& fieldName);
+static void checkViewDependency(thread_db* tdbb, jrd_tra* transaction,
+	const MetaName& relationName, const MetaName& fieldName);
+static void clearPermanentField(dsql_rel* relation, bool permanent);
+static void deleteKeyConstraint(thread_db* tdbb, jrd_tra* transaction,
+	const MetaName& relationName, const MetaName& constraintName, const MetaName& indexName);
+static bool fieldExists(thread_db* tdbb, jrd_tra* transaction, const MetaName& relationName,
+	const MetaName& fieldName);
+static void makeRelationScopeName(const MetaName& name, const rel_t type, string& message);
+static void modifyLocalFieldPosition(thread_db* tdbb, jrd_tra* transaction,
+	const MetaName& relationName, const MetaName& fieldName, USHORT newPosition,
+	USHORT existingPosition);
+static rel_t relationType(SSHORT relationTypeNull, SSHORT relationType);
+static void saveRelation(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch,
+	const dsql_str* relationName, bool creating);
+static void updateRdbFields(const TypeClause& type,
+	SSHORT& fieldType,
+	SSHORT& fieldLength,
+	SSHORT& fieldSubTypeNull, SSHORT& fieldSubType,
+	SSHORT& fieldScaleNull, SSHORT& fieldScale,
+	SSHORT& characterSetIdNull, SSHORT& characterSetId,
+	SSHORT& characterLengthNull, SSHORT& characterLength,
+	SSHORT& fieldPrecisionNull, SSHORT& fieldPrecision,
+	SSHORT& collationIdNull, SSHORT& collationId,
+	SSHORT& segmentLengthNull, SSHORT& segmentLength);
 
 DATABASE DB = STATIC "ODS.RDB";
 
@@ -64,25 +94,376 @@
 //----------------------
 
 
-// Rethrow an exception with isc_no_meta_update and code prefix when necessary.
-static void rethrowMetaException(const status_exception& ex, ISC_STATUS code, bool metaDataException)
+// Check temporary table reference rules between given child relation and master
+// relation (owner of given PK/UK index).
+static void checkForeignKeyTempScope(thread_db* tdbb, jrd_tra* transaction,
+	const MetaName&	childRelName, const MetaName& masterIndexName)
 {
-	Arg::StatusVector newVector;
-	const ISC_STATUS* status = ex.value();
+	AutoCacheRequest request(tdbb, drq_l_rel_info, DYN_REQUESTS);
+	bool error = false;
+	string master, child;
 
-	if (metaDataException)
+	FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
+		RLC_M IN RDB$RELATION_CONSTRAINTS CROSS
+		REL_C IN RDB$RELATIONS CROSS
+		REL_M IN RDB$RELATIONS
+		WITH (RLC_M.RDB$CONSTRAINT_TYPE EQ UNIQUE_CNSTRT OR
+			  RLC_M.RDB$CONSTRAINT_TYPE EQ PRIMARY_KEY) AND
+			 RLC_M.RDB$INDEX_NAME EQ masterIndexName.c_str() AND
+			 REL_C.RDB$RELATION_NAME EQ childRelName.c_str() AND
+			 REL_M.RDB$RELATION_NAME EQ RLC_M.RDB$RELATION_NAME
 	{
-		if (status[1] != isc_no_meta_update)
-			newVector << Arg::Gds(isc_no_meta_update);
+		const rel_t masterType = relationType(REL_M.RDB$RELATION_TYPE.NULL, REL_M.RDB$RELATION_TYPE);
+		fb_assert(masterType == rel_persistent ||
+				  masterType == rel_global_temp_preserve ||
+				  masterType == rel_global_temp_delete);
 
-		if (code != 0)
-			newVector << Arg::Gds(code);
+		const rel_t childType = relationType(REL_C.RDB$RELATION_TYPE.NULL, REL_C.RDB$RELATION_TYPE);
+		fb_assert(childType == rel_persistent ||
+				  childType == rel_global_temp_preserve ||
+				  childType == rel_global_temp_delete);
+
+		error = masterType != childType &&
+			!(masterType == rel_global_temp_preserve && childType == rel_global_temp_delete);
+
+		if (error)
+		{
+			makeRelationScopeName(masterIndexName, masterType, master);
+			makeRelationScopeName(childRelName, childType, child);
+		}
 	}
+	END_FOR
 
-	newVector.append(Arg::StatusVector(status));
-	status_exception::raise(newVector);
+	if (error)
+	{
+		// Msg 232 : "%s can't reference %s"
+		status_exception::raise(Arg::Gds(ENCODE_ISC_MSG(232, DYN_MSG_FAC)) << child << master);
+	}
 }
 
+// Check temporary table reference rules between just created child relation and all
+// its master relations.
+static void checkRelationTempScope(thread_db* tdbb, jrd_tra* transaction,
+	const MetaName&	childRelName, const rel_t childType)
+{
+	if (childType != rel_persistent &&
+		childType != rel_global_temp_preserve &&
+		childType != rel_global_temp_delete)
+	{
+		return;
+	}
+
+	AutoCacheRequest request(tdbb, drq_l_rel_info2, DYN_REQUESTS);
+	bool error = false;
+	string master, child;
+
+	FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
+		RLC_C IN RDB$RELATION_CONSTRAINTS CROSS
+		IND_C IN RDB$INDICES CROSS
+		IND_M IN RDB$INDICES CROSS
+		REL_M IN RDB$RELATIONS
+		WITH RLC_C.RDB$CONSTRAINT_TYPE EQ FOREIGN_KEY AND
+			 RLC_C.RDB$RELATION_NAME EQ childRelName.c_str() AND
+			 IND_C.RDB$INDEX_NAME EQ RLC_C.RDB$INDEX_NAME AND
+			 IND_M.RDB$INDEX_NAME EQ IND_C.RDB$FOREIGN_KEY AND
+			 IND_M.RDB$RELATION_NAME EQ REL_M.RDB$RELATION_NAME
+	{
+		const rel_t masterType = relationType(REL_M.RDB$RELATION_TYPE.NULL, REL_M.RDB$RELATION_TYPE);
+		fb_assert(masterType == rel_persistent ||
+				  masterType == rel_global_temp_preserve ||
+				  masterType == rel_global_temp_delete);
+
+		error = masterType != childType &&
+			!(masterType == rel_global_temp_preserve && childType == rel_global_temp_delete);
+
+		if (error)
+		{
+			makeRelationScopeName(REL_M.RDB$RELATION_NAME, masterType, master);
+			makeRelationScopeName(childRelName, childType, child);
+		}
+	}
+	END_FOR
+
+	if (error)
+	{
+		// Msg 232 : "%s can't reference %s"
+		status_exception::raise(Arg::Gds(ENCODE_ISC_MSG(232, DYN_MSG_FAC)) << child << master);
+	}
+}
+
+// Checks to see if the given field is referenced in a stored procedure or trigger.
+// If the field is referenced, throw.
+static void checkSpTrigDependency(thread_db* tdbb, jrd_tra* transaction,
+	const MetaName& relationName, const MetaName& fieldName)
+{
+	AutoRequest request;
+
+	FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
+		FIRST 1
+		DEP IN RDB$DEPENDENCIES
+		WITH DEP.RDB$DEPENDED_ON_NAME EQ relationName.c_str() AND
+			 DEP.RDB$FIELD_NAME EQ fieldName.c_str()
+	{
+		MetaName depName(DEP.RDB$DEPENDENT_NAME);
+
+		// msg 206: Column %s from table %s is referenced in %s.
+		status_exception::raise(
+			Arg::Gds(ENCODE_ISC_MSG(206, DYN_MSG_FAC)) << fieldName << relationName << depName);
+	}
+	END_FOR
+}
+
+// Checks to see if the given field is referenced in a view. If it is, throw.
+static void checkViewDependency(thread_db* tdbb, jrd_tra* transaction,
+	const MetaName& relationName, const MetaName& fieldName)
+{
+	AutoRequest request;
+
+	FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
+		FIRST 1
+		X IN RDB$RELATION_FIELDS CROSS
+		Y IN RDB$RELATION_FIELDS CROSS
+		Z IN RDB$VIEW_RELATIONS
+		WITH X.RDB$RELATION_NAME EQ relationName.c_str() AND
+			 X.RDB$FIELD_NAME EQ fieldName.c_str() AND
+			 X.RDB$FIELD_NAME EQ Y.RDB$BASE_FIELD AND
+			 X.RDB$FIELD_SOURCE EQ Y.RDB$FIELD_SOURCE AND
+			 Y.RDB$RELATION_NAME EQ Z.RDB$VIEW_NAME AND
+			 X.RDB$RELATION_NAME EQ Z.RDB$RELATION_NAME AND
+			 Y.RDB$VIEW_CONTEXT EQ Z.RDB$VIEW_CONTEXT
+	{
+		MetaName viewName(Z.RDB$VIEW_NAME);
+
+		// msg 206: Column %s from table %s is referenced in  %s.
+		status_exception::raise(
+			Arg::Gds(ENCODE_ISC_MSG(206, DYN_MSG_FAC)) << fieldName << relationName << viewName);
+	}
+	END_FOR
+}
+
+// Removes temporary pool pointers from field, stored in permanent cache.
+static void clearPermanentField(dsql_rel* relation, bool permanent)
+{
+	if (relation && relation->rel_fields && permanent)
+	{
+		relation->rel_fields->fld_procedure = NULL;
+		relation->rel_fields->fld_ranges = NULL;
+		relation->rel_fields->fld_character_set = NULL;
+		relation->rel_fields->fld_sub_type_name = NULL;
+		relation->rel_fields->fld_relation = relation;
+	}
+}
+
+// Delete a record from RDB$RELATION_CONSTRAINTS based on a constraint name.
+//
+//      On deleting from RDB$RELATION_CONSTRAINTS, 2 system triggers fire:
+//
+//      (A) pre delete trigger: pre_delete_constraint, will:
+//
+//        1. delete a record first from RDB$REF_CONSTRAINTS where
+//           RDB$REF_CONSTRAINTS.RDB$CONSTRAINT_NAME =
+//                               RDB$RELATION_CONSTRAINTS.RDB$CONSTRAINT_NAME
+//
+//      (B) post delete trigger: post_delete_constraint will:
+//
+//        1. also delete a record from RDB$INDICES where
+//           RDB$INDICES.RDB$INDEX_NAME =
+//                               RDB$RELATION_CONSTRAINTS.RDB$INDEX_NAME
+//
+//        2. also delete a record from RDB$INDEX_SEGMENTS where
+//           RDB$INDEX_SEGMENTS.RDB$INDEX_NAME =
+//                               RDB$RELATION_CONSTRAINTS.RDB$INDEX_NAME
+static void deleteKeyConstraint(thread_db* tdbb, jrd_tra* transaction,
+	const MetaName& relationName, const MetaName& constraintName, const MetaName& indexName)
+{
+	SET_TDBB(tdbb);
+
+	AutoCacheRequest request(tdbb, drq_e_rel_const, DYN_REQUESTS);
+	bool found = false;
+
+	FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
+		RC IN RDB$RELATION_CONSTRAINTS
+		WITH RC.RDB$CONSTRAINT_NAME EQ constraintName.c_str() AND
+			 RC.RDB$CONSTRAINT_TYPE EQ FOREIGN_KEY AND
+			 RC.RDB$RELATION_NAME EQ relationName.c_str() AND
+			 RC.RDB$INDEX_NAME EQ indexName.c_str()
+	{
+		found = true;
+		ERASE RC;
+	}
+	END_FOR
+
+	if (!found)
+	{
+		// msg 130: "CONSTRAINT %s does not exist."
+		status_exception::raise(
+			Arg::Gds(ENCODE_ISC_MSG(130, DYN_MSG_FAC)) << constraintName);
+	}
+}
+
+// Checks to see if the given field already exists in a relation.
+static bool fieldExists(thread_db* tdbb, jrd_tra* transaction, const MetaName& relationName,
+	const MetaName& fieldName)
+{
+	AutoRequest request;
+	bool found = false;
+
+	FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
+		FLD IN RDB$RELATION_FIELDS
+		WITH FLD.RDB$RELATION_NAME EQ relationName.c_str() AND
+			 FLD.RDB$FIELD_NAME EQ fieldName.c_str()
+	{
+		found = true;
+	}
+	END_FOR
+
+	return found;
+}
+
+// Make string with relation name and type of its temporary scope.
+static void makeRelationScopeName(const MetaName& name, const rel_t type, string& message)
+{
+	const char* scope = NULL;
+
+	if (type == rel_global_temp_preserve)
+		scope = REL_SCOPE_GTT_PRESERVE;
+	else if (type == rel_global_temp_delete)
+		scope = REL_SCOPE_GTT_DELETE;
+	else
+		scope = REL_SCOPE_PERSISTENT;
+
+	message.printf(scope, name.c_str());
+}
+
+// Alters the position of a field with respect to the
+// other fields in the relation.  This will only affect
+// the order in which the fields will be returned when either
+// viewing the relation or performing select * from the relation.
+//
+// The rules of engagement are as follows:
+//      if new_position > original position
+//         increase RDB$FIELD_POSITION for all fields with RDB$FIELD_POSITION
+//         between the new_position and existing position of the field
+//      then update the position of the field being altered.
+//         just update the position
+//
+//      if new_position < original position
+//         decrease RDB$FIELD_POSITION for all fields with RDB$FIELD_POSITION
+//         between the new_position and existing position of the field
+//      then update the position of the field being altered.
+//
+//      if new_position == original_position -- no_op
+static void modifyLocalFieldPosition(thread_db* tdbb, jrd_tra* transaction,
+	const MetaName& relationName, const MetaName& fieldName, USHORT newPosition,
+	USHORT existingPosition)
+{
+	// Make sure that there are no duplicate field positions and no gaps in the position sequence.
+	// (gaps are introduced when fields are removed)
+
+	AutoRequest request;
+	USHORT newPos = 0;
+
+	FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
+		FLD IN RDB$RELATION_FIELDS
+		WITH FLD.RDB$RELATION_NAME EQ relationName.c_str()
+		SORTED BY ASCENDING FLD.RDB$FIELD_POSITION
+	{
+		if (FLD.RDB$FIELD_POSITION != newPos)
+		{
+			MODIFY FLD USING
+				FLD.RDB$FIELD_POSITION = newPos;
+			END_MODIFY
+		}
+
+		++newPos;
+	}
+	END_FOR
+
+	// Find the position of the last field in the relation.
+	SLONG maxPosition = -1;
+	DYN_UTIL_generate_field_position(tdbb, NULL, relationName, &maxPosition);
+
+	// If the existing position of the field is less than the new position of
+	// the field, subtract 1 to move the fields to their new positions otherwise,
+	// increase the value in RDB$FIELD_POSITION by one.
+
+	bool moveDown = false;
+	if (existingPosition < newPosition)
+		moveDown = true;
+
+	// Retrieve the records for the fields which have a position between the
+	// existing field position and the new field position.
+
+	request.reset();
+
+	FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
+		FLD IN RDB$RELATION_FIELDS
+		WITH FLD.RDB$RELATION_NAME EQ relationName.c_str() AND
+				FLD.RDB$FIELD_POSITION >= MIN(newPosition, existingPosition) AND
+				FLD.RDB$FIELD_POSITION <= MAX(newPosition, existingPosition)
+	{
+		MODIFY FLD USING
+			// If the field is the one we want, change the position, otherwise
+			// increase the value of RDB$FIELD_POSITION.
+			if (fieldName == FLD.RDB$FIELD_NAME)
+			{
+				if (newPosition > maxPosition)
+				{
+					// This prevents gaps in the position sequence of the fields.
+					FLD.RDB$FIELD_POSITION = maxPosition;
+				}
+				else
+					FLD.RDB$FIELD_POSITION = newPosition;
+			}
+			else
+			{
+				if (moveDown)
+					FLD.RDB$FIELD_POSITION = FLD.RDB$FIELD_POSITION - 1;
+				else
+					FLD.RDB$FIELD_POSITION = FLD.RDB$FIELD_POSITION + 1;
+			}
+
+			FLD.RDB$FIELD_POSITION.NULL = FALSE;
+		END_MODIFY
+	}
+	END_FOR
+}
+
+// Convert RDB$RELATION_TYPE to rel_t type.
+static rel_t relationType(SSHORT relationTypeNull, SSHORT relationType)
+{
+	return relationTypeNull ? rel_persistent : rel_t(relationType);
+}
+
+// Save the name of the relation or view currently being defined. This is done to support definition
+// of triggers which will depend on the metadata created in this statement.
+static void saveRelation(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch,
+	const dsql_str* relationName, bool creating)
+{
+	//// TODO: Verify "creating" usage when using this function for views.
+
+	DsqlCompiledStatement* statement = dsqlScratch->getStatement();
+
+	if (dsqlScratch->flags & DsqlCompilerScratch::FLAG_METADATA_SAVED)
+		return;
+
+	dsqlScratch->flags |= DsqlCompilerScratch::FLAG_METADATA_SAVED;
+
+	dsql_rel* relation;
+
+	if (!creating)
+		relation = METD_get_relation(dsqlScratch->getTransaction(), dsqlScratch, relationName);
+	else
+	{
+		MemoryPool& pool = *tdbb->getDefaultPool();
+		relation = FB_NEW(pool) dsql_rel(pool);
+		relation->rel_name = relationName->str_data;
+		relation->rel_flags = REL_creating;
+	}
+
+	dsqlScratch->relation = relation;
+}
+
 // Update RDB$FIELDS received by reference.
 static void updateRdbFields(const TypeClause& type,
 	SSHORT& fieldType,
@@ -169,6 +550,25 @@
 //----------------------
 
 
+// Delete a security class.
+bool DdlNode::deleteSecurityClass(thread_db* tdbb, jrd_tra* transaction,
+	const MetaName& secClass)
+{
+	AutoCacheRequest request(tdbb, drq_e_class, DYN_REQUESTS);
+	bool found = false;
+
+	FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
+		SC IN RDB$SECURITY_CLASSES
+		WITH SC.RDB$SECURITY_CLASS EQ secClass.c_str()
+	{
+		found = true;
+		ERASE SC;
+	}
+	END_FOR
+
+	return found;
+}
+
 void DdlNode::executeDdlTrigger(thread_db* tdbb, jrd_tra* transaction, DdlTriggerWhen when,
 	int action, const MetaName& objectName, const string& sqlText)
 {
@@ -192,14 +592,12 @@
 	savePoint.release();	// everything is ok
 }
 
-
 void DdlNode::executeDdlTrigger(thread_db* tdbb, jrd_tra* transaction,
 	DdlNode::DdlTriggerWhen when, int action, const MetaName& objectName)
 {
 	executeDdlTrigger(tdbb, transaction, when, action, objectName, sqlText);
 }
 
-
 void DdlNode::putType(const TypeClause& type, bool useSubType)
 {
 #ifdef DEV_BUILD
@@ -300,51 +698,105 @@
 	}
 }
 
-
 void DdlNode::resetContextStack()
 {
 	dsqlScratch->context->clear();
 	dsqlScratch->contextNumber = 0;
 }
 
-
-void DdlNode::storeGlobalField(thread_db* tdbb, jrd_tra* transaction, const TypeClause& field,
-	MetaName& name)
+void DdlNode::storeGlobalField(thread_db* tdbb, jrd_tra* transaction, MetaName& name,
+	const TypeClause& field, const string& computedSource, const BlrWriter::BlrData& computedValue)
 {
-	bool endStore = false;
+	Attachment* attachment = transaction->tra_attachment;
 
-	try
+	const dsql_nod* elements = field.legacyField->fld_ranges;
+	const USHORT dims = elements ? elements->nod_count / 2 : 0;
+
+	if (dims > MAX_ARRAY_DIMENSIONS)
 	{
-		if (name.isEmpty())
-			DYN_UTIL_generate_field_name(tdbb, NULL, name);
+		status_exception::raise(
+			Arg::Gds(isc_sqlerr) << Arg::Num(-604) <<
+			Arg::Gds(isc_dsql_max_arr_dim_exceeded));
+	}
 
-		AutoCacheRequest requestHandle(tdbb, drq_s_fld_src, DYN_REQUESTS);
+	if (name.isEmpty())
+		DYN_UTIL_generate_field_name(tdbb, NULL, name);
 
-		STORE (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction)
-			FLD IN RDB$FIELDS
+	AutoCacheRequest requestHandle(tdbb, drq_s_fld_src, DYN_REQUESTS);
+
+	STORE (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction)
+		FLD IN RDB$FIELDS
+	{
+		FLD.RDB$SYSTEM_FLAG = 0;
+		strcpy(FLD.RDB$FIELD_NAME, name.c_str());
+
+		FLD.RDB$COMPUTED_SOURCE.NULL = TRUE;
+		FLD.RDB$COMPUTED_BLR.NULL = TRUE;
+		FLD.RDB$DIMENSIONS.NULL = TRUE;
+
+		updateRdbFields(field,
+			FLD.RDB$FIELD_TYPE,
+			FLD.RDB$FIELD_LENGTH,
+			FLD.RDB$FIELD_SUB_TYPE.NULL, FLD.RDB$FIELD_SUB_TYPE,
+			FLD.RDB$FIELD_SCALE.NULL, FLD.RDB$FIELD_SCALE,
+			FLD.RDB$CHARACTER_SET_ID.NULL, FLD.RDB$CHARACTER_SET_ID,
+			FLD.RDB$CHARACTER_LENGTH.NULL, FLD.RDB$CHARACTER_LENGTH,
+			FLD.RDB$FIELD_PRECISION.NULL, FLD.RDB$FIELD_PRECISION,
+			FLD.RDB$COLLATION_ID.NULL, FLD.RDB$COLLATION_ID,
+			FLD.RDB$SEGMENT_LENGTH.NULL, FLD.RDB$SEGMENT_LENGTH);
+
+		if (dims != 0)
 		{
-			FLD.RDB$SYSTEM_FLAG = 0;
-			strcpy(FLD.RDB$FIELD_NAME, name.c_str());
+			FLD.RDB$DIMENSIONS.NULL = FALSE;
+			FLD.RDB$DIMENSIONS = dims;
+		}
 
-			updateRdbFields(field,
-				FLD.RDB$FIELD_TYPE,
-				FLD.RDB$FIELD_LENGTH,
-				FLD.RDB$FIELD_SUB_TYPE.NULL, FLD.RDB$FIELD_SUB_TYPE,
-				FLD.RDB$FIELD_SCALE.NULL, FLD.RDB$FIELD_SCALE,
-				FLD.RDB$CHARACTER_SET_ID.NULL, FLD.RDB$CHARACTER_SET_ID,
-				FLD.RDB$CHARACTER_LENGTH.NULL, FLD.RDB$CHARACTER_LENGTH,
-				FLD.RDB$FIELD_PRECISION.NULL, FLD.RDB$FIELD_PRECISION,
-				FLD.RDB$COLLATION_ID.NULL, FLD.RDB$COLLATION_ID,
-				FLD.RDB$SEGMENT_LENGTH.NULL, FLD.RDB$SEGMENT_LENGTH);
+		if (computedSource.hasData())
+		{
+			FLD.RDB$COMPUTED_SOURCE.NULL = FALSE;
+			attachment->storeMetaDataBlob(tdbb, transaction, &FLD.RDB$COMPUTED_SOURCE,
+				computedSource);
+		}
 
-			endStore = true;
+		if (computedValue.hasData())
+		{
+			FLD.RDB$COMPUTED_BLR.NULL = FALSE;
+			attachment->storeBinaryBlob(tdbb, transaction, &FLD.RDB$COMPUTED_BLR,
+				computedValue);
 		}
-		END_STORE
 	}
-	catch (const status_exception& ex)
+	END_STORE
+
+	if (elements)	// Is the type an array?
 	{
-		// STORE RDB$FIELDS failed
-		rethrowMetaException(ex, ENCODE_ISC_MSG(13, DYN_MSG_FAC), endStore);
+		AutoCacheRequest request(tdbb, drq_s_fld_dym, DYN_REQUESTS);
+
+		SSHORT position = 0;
+		const dsql_nod* const* ptr = elements->nod_arg;
+		for (const dsql_nod* const* const end = ptr + elements->nod_count; ptr < end; ++ptr, ++position)
+		{
+			const dsql_nod* element = *ptr++;
+			const SLONG lrange = element->getSlong();
+			element = *ptr;
+			const SLONG hrange = element->getSlong();
+
+			if (lrange >= hrange)
+			{
+				status_exception::raise(
+					Arg::Gds(isc_sqlerr) << Arg::Num(-604) <<
+					Arg::Gds(isc_dsql_arr_range_error));
+			}
+
+			STORE (REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
+				DIM IN RDB$FIELD_DIMENSIONS
+			{
+				strcpy(DIM.RDB$FIELD_NAME, name.c_str());
+				DIM.RDB$DIMENSION = position;
+				DIM.RDB$UPPER_BOUND = hrange;
+				DIM.RDB$LOWER_BOUND = lrange;
+			}
+			END_STORE
+		}
 	}
 }
 
@@ -358,11 +810,10 @@
 {
 }
 
-
-void TypeClause::resolve(DsqlCompilerScratch* dsqlScratch)
+void TypeClause::resolve(DsqlCompilerScratch* dsqlScratch, bool modifying)
 {
-	DDL_resolve_intl_type(dsqlScratch, legacyField,
-		(collate.isEmpty() ? NULL : MAKE_cstring(collate.c_str())));
+	DDL_resolve_intl_type2(dsqlScratch, legacyField,
+		(collate.isEmpty() ? NULL : MAKE_cstring(collate.c_str())), modifying);
 
 	type = legacyField->fld_dtype;
 	length = legacyField->fld_length;
@@ -385,7 +836,6 @@
 	typeOfName = legacyField->fld_type_of_name;
 }
 
-
 void TypeClause::print(string& text) const
 {
 	text.printf("typeOfTable: '%s'  typeOfName: '%s'  notNull: %d  fieldSource: '%s'",
@@ -405,7 +855,6 @@
 {
 }
 
-
 void ParameterClause::print(string& text) const
 {
 	string s;
@@ -426,7 +875,6 @@
 		charSet.c_str(), defaultCollation.c_str());
 }
 
-
 void AlterCharSetNode::execute(thread_db* tdbb, jrd_tra* transaction)
 {
 	METD_drop_charset(transaction, charSet);
@@ -467,16 +915,12 @@
 	END_FOR
 
 	if (!charSetFound)
-	{
-		status_exception::raise(Arg::Gds(isc_no_meta_update) <<
-								Arg::Gds(isc_charset_not_found) << Arg::Str(charSet));
-	}
+		status_exception::raise(Arg::Gds(isc_charset_not_found) << Arg::Str(charSet));
 
 	if (!collationFound)
 	{
-		status_exception::raise(Arg::Gds(isc_no_meta_update) <<
-								Arg::Gds(isc_collation_not_found) << Arg::Str(defaultCollation) <<
-																	 Arg::Str(charSet));
+		status_exception::raise(
+			Arg::Gds(isc_collation_not_found) << Arg::Str(defaultCollation) << Arg::Str(charSet));
 	}
 
 	executeDdlTrigger(tdbb, transaction, DTW_AFTER, DDL_TRIGGER_ALTER_CHARACTER_SET, charSet);
@@ -496,7 +940,6 @@
 		objType, objName.c_str(), text.c_str());
 }
 
-
 // select rdb$relation_name from rdb$relation_fields where rdb$field_name = 'RDB$DESCRIPTION';
 // gives the list of objects that accept descriptions. At FB2 time, the only
 // subobjects with descriptions are relation's fields and procedure's parameters.
@@ -691,7 +1134,6 @@
 	}
 }
 
-
 DdlNode* CreateAlterFunctionNode::internalDsqlPass()
 {
 	DsqlCompiledStatement* const statement = dsqlScratch->getStatement();
@@ -762,7 +1204,6 @@
 	return DdlNode::internalDsqlPass();
 }
 
-
 void CreateAlterFunctionNode::execute(thread_db* tdbb, jrd_tra* transaction)
 {
 	fb_assert(create || alter);
@@ -781,15 +1222,9 @@
 		else
 		{
 			if (create)	// create or alter
-			{
 				executeCreate(tdbb, transaction);
-			}
 			else
-			{
-				status_exception::raise(
-					Arg::Gds(isc_no_meta_update) <<
-					Arg::Gds(isc_dyn_func_not_found) << Arg::Str(name));
-			}
+				status_exception::raise(Arg::Gds(isc_dyn_func_not_found) << Arg::Str(name));
 		}
 	}
 	else
@@ -817,7 +1252,6 @@
 	}
 }
 
-
 void CreateAlterFunctionNode::executeCreate(thread_db* tdbb, jrd_tra* transaction)
 {
 	Attachment* attachment = transaction->getAttachment();
@@ -918,7 +1352,6 @@
 	executeAlter(tdbb, transaction, false, false);
 }
 
-
 bool CreateAlterFunctionNode::executeAlter(thread_db* tdbb, jrd_tra* transaction,
 	bool secondPass, bool runTriggers)
 {
@@ -935,9 +1368,8 @@
 	{
 		if (!FUN.RDB$SYSTEM_FLAG.NULL && FUN.RDB$SYSTEM_FLAG)
 		{
-			status_exception::raise(Arg::Gds(isc_no_meta_update) <<
-									Arg::Gds(isc_dyn_cannot_mod_sysfunc) <<
-									FUN.RDB$FUNCTION_NAME);
+			status_exception::raise(
+				Arg::Gds(isc_dyn_cannot_mod_sysfunc) << FUN.RDB$FUNCTION_NAME);
 		}
 
 		if (!secondPass && runTriggers && package.isEmpty())
@@ -1031,7 +1463,6 @@
 	return modified;
 }
 
-
 void CreateAlterFunctionNode::storeArgument(thread_db* tdbb, jrd_tra* transaction,
 	unsigned pos, const ParameterClause& parameter)
 {
@@ -1099,7 +1530,7 @@
 			else
 			{
 				MetaName fieldName;
-				storeGlobalField(tdbb, transaction, parameter, fieldName);
+				storeGlobalField(tdbb, transaction, fieldName, parameter);
 				strcpy(ARG.RDB$FIELD_SOURCE, fieldName.c_str());
 			}
 		}
@@ -1155,7 +1586,6 @@
 	END_STORE
 }
 
-
 void CreateAlterFunctionNode::compile(thread_db* tdbb, jrd_tra* /*transaction*/)
 {
 	if (invalid)
@@ -1327,7 +1757,6 @@
 	END_FOR
 }
 
-
 void DropFunctionNode::print(string& text, Array<dsql_nod*>& /*nodes*/) const
 {
 	text.printf(
@@ -1336,14 +1765,12 @@
 		name.c_str());
 }
 
-
 DdlNode* DropFunctionNode::internalDsqlPass()
 {
 	dsqlScratch->flags |= (DsqlCompilerScratch::FLAG_BLOCK | DsqlCompilerScratch::FLAG_FUNCTION);
 	return DdlNode::internalDsqlPass();
 }
 
-
 void DropFunctionNode::execute(thread_db* tdbb, jrd_tra* transaction)
 {
 	// run all statements under savepoint control
@@ -1360,10 +1787,7 @@
 			 FUN.RDB$PACKAGE_NAME EQUIV NULLIF(package.c_str(), '')
 	{
 		if (!FUN.RDB$SYSTEM_FLAG.NULL && FUN.RDB$SYSTEM_FLAG)
-		{
-			status_exception::raise(Arg::Gds(isc_no_meta_update) <<
-									Arg::Gds(isc_dyn_cannot_mod_sysfunc) << FUN.RDB$FUNCTION_NAME);
-		}
+			status_exception::raise(Arg::Gds(isc_dyn_cannot_mod_sysfunc) << FUN.RDB$FUNCTION_NAME);
 
 		if (package.isEmpty())
 			executeDdlTrigger(tdbb, transaction, DTW_BEFORE, DDL_TRIGGER_DROP_FUNCTION, name);
@@ -1371,18 +1795,14 @@
 		ERASE FUN;
 
 		if (!FUN.RDB$SECURITY_CLASS.NULL)
-			DYN_delete_security_class2(transaction, FUN.RDB$SECURITY_CLASS);
+			deleteSecurityClass(tdbb, transaction, FUN.RDB$SECURITY_CLASS);
 
 		found = true;
 	}
 	END_FOR
 
 	if (!found && !silent)
-	{
-		status_exception::raise(
-			Arg::Gds(isc_no_meta_update) <<
-			Arg::Gds(isc_dyn_func_not_found) << Arg::Str(name));
-	}
+		status_exception::raise(Arg::Gds(isc_dyn_func_not_found) << Arg::Str(name));
 
 	if (package.isEmpty())
 	{
@@ -1426,7 +1846,6 @@
 	text.printf("RecreateFunctionNode\n");
 }
 
-
 DdlNode* RecreateFunctionNode::internalDsqlPass()
 {
 	createNode->dsqlPass(dsqlScratch);
@@ -1434,14 +1853,13 @@
 	return DdlNode::internalDsqlPass();
 }
 
-
 void RecreateFunctionNode::execute(thread_db* tdbb, jrd_tra* transaction)
 {
 	// run all statements under savepoint control
 	AutoSavePoint savePoint(tdbb, transaction);
 
-	dropNode.executeDdl(tdbb, transaction);
-	createNode->executeDdl(tdbb, transaction);
+	dropNode.execute(tdbb, transaction);
+	createNode->execute(tdbb, transaction);
 
 	savePoint.release();	// everything is ok
 }
@@ -1488,7 +1906,6 @@
 	}
 }
 
-
 DdlNode* CreateAlterProcedureNode::internalDsqlPass()
 {
 	DsqlCompiledStatement* statement = dsqlScratch->getStatement();
@@ -1565,7 +1982,6 @@
 	return DdlNode::internalDsqlPass();
 }
 
-
 void CreateAlterProcedureNode::execute(thread_db* tdbb, jrd_tra* transaction)
 {
 	fb_assert(create || alter);
@@ -1584,11 +2000,7 @@
 			if (create)	// create or alter
 				executeCreate(tdbb, transaction);
 			else
-			{
-				status_exception::raise(
-					Arg::Gds(isc_no_meta_update) <<
-					Arg::Gds(isc_dyn_proc_not_found) << Arg::Str(name));
-			}
+				status_exception::raise(Arg::Gds(isc_dyn_proc_not_found) << Arg::Str(name));
 		}
 	}
 	else
@@ -1614,7 +2026,6 @@
 	}
 }
 
-
 void CreateAlterProcedureNode::executeCreate(thread_db* tdbb, jrd_tra* transaction)
 {
 	Attachment* attachment = transaction->getAttachment();
@@ -1704,7 +2115,6 @@
 	executeAlter(tdbb, transaction, false, false);
 }
 
-
 bool CreateAlterProcedureNode::executeAlter(thread_db* tdbb, jrd_tra* transaction,
 	bool secondPass, bool runTriggers)
 {
@@ -1721,8 +2131,7 @@
 	{
 		if (!P.RDB$SYSTEM_FLAG.NULL && P.RDB$SYSTEM_FLAG)
 		{
-			status_exception::raise(Arg::Gds(isc_no_meta_update) <<
-									Arg::Gds(isc_dyn_cannot_mod_sysproc) << P.RDB$PROCEDURE_NAME);
+			status_exception::raise(Arg::Gds(isc_dyn_cannot_mod_sysproc) << P.RDB$PROCEDURE_NAME);
 		}
 
 		if (!secondPass && runTriggers && package.isEmpty())
@@ -1852,7 +2261,6 @@
 	return modified;
 }
 
-
 void CreateAlterProcedureNode::storeParameter(thread_db* tdbb, jrd_tra* transaction,
 	USHORT type, unsigned pos, const ParameterClause& parameter)
 {
@@ -1905,7 +2313,7 @@
 			else
 			{
 				MetaName fieldName;
-				storeGlobalField(tdbb, transaction, parameter, fieldName);
+				storeGlobalField(tdbb, transaction, fieldName, parameter);
 				strcpy(PRM.RDB$FIELD_SOURCE, fieldName.c_str());
 			}
 		}
@@ -1958,7 +2366,6 @@
 	END_STORE
 }
 
-
 void CreateAlterProcedureNode::compile(thread_db* tdbb, jrd_tra* /*transaction*/)
 {
 	if (invalid)
@@ -2132,7 +2539,6 @@
 	END_FOR
 }
 
-
 void DropProcedureNode::print(string& text, Array<dsql_nod*>& /*nodes*/) const
 {
 	text.printf(
@@ -2141,14 +2547,12 @@
 		name.c_str());
 }
 
-
 DdlNode* DropProcedureNode::internalDsqlPass()
 {
 	dsqlScratch->flags |= (DsqlCompilerScratch::FLAG_BLOCK | DsqlCompilerScratch::FLAG_PROCEDURE);
 	return DdlNode::internalDsqlPass();
 }
 
-
 void DropProcedureNode::execute(thread_db* tdbb, jrd_tra* transaction)
 {
 	// run all statements under savepoint control
@@ -2165,10 +2569,7 @@
 			 PRC.RDB$PACKAGE_NAME EQUIV NULLIF(package.c_str(), '')
 	{
 		if (!PRC.RDB$SYSTEM_FLAG.NULL && PRC.RDB$SYSTEM_FLAG)
-		{
-			status_exception::raise(Arg::Gds(isc_no_meta_update) <<
-									Arg::Gds(isc_dyn_cannot_mod_sysproc) << PRC.RDB$PROCEDURE_NAME);
-		}
+			status_exception::raise(Arg::Gds(isc_dyn_cannot_mod_sysproc) << PRC.RDB$PROCEDURE_NAME);
 
 		if (package.isEmpty())
 			executeDdlTrigger(tdbb, transaction, DTW_BEFORE, DDL_TRIGGER_DROP_PROCEDURE, name);
@@ -2176,18 +2577,14 @@
 		ERASE PRC;
 
 		if (!PRC.RDB$SECURITY_CLASS.NULL)
-			DYN_delete_security_class2(transaction, PRC.RDB$SECURITY_CLASS);
+			deleteSecurityClass(tdbb, transaction, PRC.RDB$SECURITY_CLASS);
 
 		found = true;
 	}
 	END_FOR
 
 	if (!found && !silent)
-	{
-		status_exception::raise(
-			Arg::Gds(isc_no_meta_update) <<
-			Arg::Gds(isc_dyn_proc_not_found) << Arg::Str(name));
-	}
+		status_exception::raise(Arg::Gds(isc_dyn_proc_not_found) << Arg::Str(name));
 
 	if (package.isEmpty())
 	{
@@ -2231,7 +2628,6 @@
 	text.printf("RecreateProcedureNode\n");
 }
 
-
 DdlNode* RecreateProcedureNode::internalDsqlPass()
 {
 	dropNode.dsqlPass(dsqlScratch);
@@ -2239,14 +2635,13 @@
 	return DdlNode::internalDsqlPass();
 }
 
-
 void RecreateProcedureNode::execute(thread_db* tdbb, jrd_tra* transaction)
 {
 	// run all statements under savepoint control
 	AutoSavePoint savePoint(tdbb, transaction);
 
-	dropNode.executeDdl(tdbb, transaction);
-	createNode->executeDdl(tdbb, transaction);
+	dropNode.execute(tdbb, transaction);
+	createNode->execute(tdbb, transaction);
 
 	savePoint.release();	// everything is ok
 }
@@ -2255,15 +2650,156 @@
 //----------------------
 
 
+void TriggerDefinition::store(thread_db* tdbb, jrd_tra* transaction)
+{
+	if (name.isEmpty())
+		DYN_UTIL_generate_trigger_name(tdbb, transaction, name);
+
+	AutoCacheRequest requestHandle(tdbb, drq_s_triggers2, DYN_REQUESTS);
+
+	STORE (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction)
+		TRG IN RDB$TRIGGERS
+	{
+		TRG.RDB$SYSTEM_FLAG = SSHORT(systemFlag);
+		TRG.RDB$FLAGS = TRG_sql | (fkTrigger ? TRG_ignore_perm : 0);
+		strcpy(TRG.RDB$TRIGGER_NAME, name.c_str());
+
+		TRG.RDB$RELATION_NAME.NULL = relationName.isEmpty();
+		strcpy(TRG.RDB$RELATION_NAME, relationName.c_str());
+
+		fb_assert(type.specified);
+		TRG.RDB$TRIGGER_TYPE = type.value;
+
+		TRG.RDB$TRIGGER_SEQUENCE = (!position.specified ? 0 : position.value);
+		TRG.RDB$TRIGGER_INACTIVE = (!active.specified ? 0 : (USHORT) !active.value);
+	}
+	END_STORE
+
+	modify(tdbb, transaction);
+}
+
+bool TriggerDefinition::modify(thread_db* tdbb, jrd_tra* transaction)
+{
+	Attachment* attachment = transaction->getAttachment();
+	bool modified = false;
+
+	// ASF: Unregistered bug (2.0, 2.1, 2.5, 3.0): CREATE OR ALTER TRIGGER accepts different table
+	// than one used in already created trigger.
+
+	AutoCacheRequest requestHandle(tdbb, drq_m_trigger2, DYN_REQUESTS);
+
+	FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction)
+		TRG IN RDB$TRIGGERS
+		WITH TRG.RDB$TRIGGER_NAME EQ name.c_str()
+	{
+		if (type.specified && type.value != (FB_UINT64) TRG.RDB$TRIGGER_TYPE &&
+			TRG.RDB$RELATION_NAME.NULL)
+		{
+			status_exception::raise(
+				Arg::Gds(isc_dsql_command_err) <<
+				Arg::Gds(isc_dsql_db_trigger_type_cant_change));
+		}
+
+		if (systemFlag == fb_sysflag_user && !TRG.RDB$SYSTEM_FLAG.NULL)
+		{
+			switch (TRG.RDB$SYSTEM_FLAG)
+			{
+				case fb_sysflag_check_constraint:
+				case fb_sysflag_referential_constraint:
+				case fb_sysflag_view_check:
+					status_exception::raise(Arg::Gds(isc_dyn_cant_modify_auto_trig));
+					break;
+
+				case fb_sysflag_system:
+					status_exception::raise(
+						Arg::Gds(isc_dyn_cannot_mod_systrig) << TRG.RDB$TRIGGER_NAME);
+					break;
+
+				default:
+					break;
+			}
+		}
+
+		preModify(tdbb, transaction);
+
+		MODIFY TRG
+			if (blrData.length > 0 || external)
+			{
+				fb_assert(!(blrData.length > 0 && external));
+
+				TRG.RDB$ENGINE_NAME.NULL = TRUE;
+				TRG.RDB$ENTRYPOINT.NULL = TRUE;
+				TRG.RDB$TRIGGER_SOURCE.NULL = TRUE;
+				TRG.RDB$TRIGGER_BLR.NULL = TRUE;
+				TRG.RDB$DEBUG_INFO.NULL = TRUE;
+			}
+
+			if (type.specified)
+				TRG.RDB$TRIGGER_TYPE = type.value;
+
+			if (position.specified)
+				TRG.RDB$TRIGGER_SEQUENCE = position.value;
+			if (active.specified)
+				TRG.RDB$TRIGGER_INACTIVE = (USHORT) !active.value;
+
+			if (external)
+			{
+				TRG.RDB$ENGINE_NAME.NULL = FALSE;
+				strcpy(TRG.RDB$ENGINE_NAME, external->engine.c_str());
+
+				if (external->name.length() >= sizeof(TRG.RDB$ENTRYPOINT))
+				{
+					status_exception::raise(
+						Arg::Gds(isc_arith_except) <<
+						Arg::Gds(isc_string_truncation));
+				}
+
+				TRG.RDB$ENTRYPOINT.NULL = (SSHORT) external->name.isEmpty();
+				strcpy(TRG.RDB$ENTRYPOINT, external->name.c_str());
+			}
+			else if (blrData.length > 0)
+			{
+				TRG.RDB$TRIGGER_BLR.NULL = FALSE;
+				attachment->storeBinaryBlob(tdbb, transaction, &TRG.RDB$TRIGGER_BLR, blrData);
+			}
+
+			if (debugData.length > 0)
+			{
+				TRG.RDB$DEBUG_INFO.NULL = FALSE;
+				attachment->storeBinaryBlob(tdbb, transaction, &TRG.RDB$DEBUG_INFO, debugData);
+			}
+
+			if (source.hasData())
+			{
+				TRG.RDB$TRIGGER_SOURCE.NULL = FALSE;
+				attachment->storeMetaDataBlob(tdbb, transaction, &TRG.RDB$TRIGGER_SOURCE, source);
+			}
+
+			TRG.RDB$VALID_BLR = TRUE;
+
+			modified = true;
+		END_MODIFY
+	}
+	END_FOR
+
+	if (modified)
+		postModify(tdbb, transaction);
+
+	return modified;
+}
+
+
+//----------------------
+
+
 void CreateAlterTriggerNode::print(string& text, Array<dsql_nod*>& /*nodes*/) const
 {
 	text.printf(
 		"CreateAlterTriggerNode\n"
 		"  name: '%s'  create: %d  alter: %d  relationName: '%s'\n"
 		"  type: %d, %d  active: %d, %d  position: %d, %d\n",
-		name.c_str(), create, alter, relationName.c_str(),
-		type.specified, type.value, active.specified, active.value,
-		position.specified, position.value);
+		name.c_str(), create, alter, relationName.c_str(), type.specified, type.value,
+		active.specified, active.value, position.specified, position.value);
 
 	if (external)
 	{
@@ -2274,7 +2810,6 @@
 	}
 }
 
-
 DdlNode* CreateAlterTriggerNode::internalDsqlPass()
 {
 	DsqlCompiledStatement* statement = dsqlScratch->getStatement();
@@ -2299,7 +2834,6 @@
 	return DdlNode::internalDsqlPass();
 }
 
-
 void CreateAlterTriggerNode::execute(thread_db* tdbb, jrd_tra* transaction)
 {
 	fb_assert(create || alter);
@@ -2331,27 +2865,22 @@
 		END_FOR
 
 		if (!type.specified)
-		{
-			status_exception::raise(
-				Arg::Gds(isc_no_meta_update) <<
-				Arg::Gds(isc_dyn_trig_not_found) << Arg::Str(name));
-		}
+			status_exception::raise(Arg::Gds(isc_dyn_trig_not_found) << Arg::Str(name));
 	}
 
 	compile(tdbb, transaction);
 
+	blrData = dsqlScratch->getBlrData();
+	debugData = dsqlScratch->getDebugData();
+
 	if (alter)
 	{
-		if (!executeAlter(tdbb, transaction, true))
+		if (!modify(tdbb, transaction))
 		{
 			if (create)	// create or alter
 				executeCreate(tdbb, transaction);
 			else
-			{
-				status_exception::raise(
-					Arg::Gds(isc_no_meta_update) <<
-					Arg::Gds(isc_dyn_trig_not_found) << Arg::Str(name));
-			}
+				status_exception::raise(Arg::Gds(isc_dyn_trig_not_found) << Arg::Str(name));
 		}
 	}
 	else
@@ -2360,166 +2889,13 @@
 	savePoint.release();	// everything is ok
 }
 
-
 void CreateAlterTriggerNode::executeCreate(thread_db* tdbb, jrd_tra* transaction)
 {
 	executeDdlTrigger(tdbb, transaction, DTW_BEFORE, DDL_TRIGGER_CREATE_TRIGGER, name);
-
-	AutoCacheRequest requestHandle(tdbb, drq_s_triggers2, DYN_REQUESTS);
-	bool endStore = false;
-
-	try
-	{
-		STORE (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction)
-			TRG IN RDB$TRIGGERS
-		{
-			TRG.RDB$SYSTEM_FLAG = 0;
-			TRG.RDB$FLAGS = TRG_sql;	// ASF: For FK triggers, TRG_ignore_perm will also be needed.
-			strcpy(TRG.RDB$TRIGGER_NAME, name.c_str());
-
-			TRG.RDB$RELATION_NAME.NULL = relationName.isEmpty();
-			strcpy(TRG.RDB$RELATION_NAME, relationName.c_str());
-
-			fb_assert(type.specified);
-			TRG.RDB$TRIGGER_TYPE = type.value;
-
-			TRG.RDB$TRIGGER_SEQUENCE = (!position.specified ? 0 : position.value);
-			TRG.RDB$TRIGGER_INACTIVE = (!active.specified ? 0 : (USHORT) !active.value);
-
-			endStore = true;
-		}
-		END_STORE
-	}
-	catch (const status_exception& ex)
-	{
-		rethrowMetaException(ex, ENCODE_ISC_MSG(31, DYN_MSG_FAC), endStore);	// DEFINE TRIGGER failed
-	}
-
-	executeAlter(tdbb, transaction, false);
-
+	store(tdbb, transaction);
 	executeDdlTrigger(tdbb, transaction, DTW_AFTER, DDL_TRIGGER_CREATE_TRIGGER, name);
 }
 
-
-bool CreateAlterTriggerNode::executeAlter(thread_db* tdbb, jrd_tra* transaction, bool runTriggers)
-{
-	Attachment* attachment = transaction->getAttachment();
-	bool modified = false;
-
-	// ASF: Unregistered bug (2.0, 2.1, 2.5, 3.0): CREATE OR ALTER TRIGGER accepts different table
-	// than one used in already created trigger.
-
-	AutoCacheRequest requestHandle(tdbb, drq_m_trigger2, DYN_REQUESTS);
-
-	try
-	{
-		FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction)
-			TRG IN RDB$TRIGGERS
-			WITH TRG.RDB$TRIGGER_NAME EQ name.c_str()
-		{
-			if (type.specified && type.value != (FB_UINT64) TRG.RDB$TRIGGER_TYPE &&
-				((create && relationName.isEmpty()) || TRG.RDB$RELATION_NAME.NULL))
-			{
-				status_exception::raise(
-					Arg::Gds(isc_dsql_command_err) <<
-					Arg::Gds(isc_dsql_db_trigger_type_cant_change));
-			}
-
-			if (!TRG.RDB$SYSTEM_FLAG.NULL)
-			{
-				switch (TRG.RDB$SYSTEM_FLAG)
-				{
-					case fb_sysflag_check_constraint:
-					case fb_sysflag_referential_constraint:
-					case fb_sysflag_view_check:
-						status_exception::raise(Arg::Gds(isc_no_meta_update) <<
-												Arg::Gds(isc_dyn_cant_modify_auto_trig));
-						break;
-
-					case fb_sysflag_system:
-						status_exception::raise(Arg::Gds(isc_no_meta_update) <<
-							Arg::Gds(isc_dyn_cannot_mod_systrig) << TRG.RDB$TRIGGER_NAME);
-						break;
-
-					default:
-						break;
-				}
-			}
-
-			if (runTriggers)
-				executeDdlTrigger(tdbb, transaction, DTW_BEFORE, DDL_TRIGGER_ALTER_TRIGGER, name);
-
-			MODIFY TRG
-				if (body || external)
-				{
-					fb_assert(!(body && external));
-
-					TRG.RDB$ENGINE_NAME.NULL = TRUE;
-					TRG.RDB$ENTRYPOINT.NULL = TRUE;
-					TRG.RDB$TRIGGER_SOURCE.NULL = TRUE;
-					TRG.RDB$TRIGGER_BLR.NULL = TRUE;
-					TRG.RDB$DEBUG_INFO.NULL = TRUE;
-				}
-
-				if (type.specified)
-					TRG.RDB$TRIGGER_TYPE = type.value;
-
-				if (position.specified)
-					TRG.RDB$TRIGGER_SEQUENCE = position.value;
-				if (active.specified)
-					TRG.RDB$TRIGGER_INACTIVE = (USHORT) !active.value;
-
-				if (external)
-				{
-					TRG.RDB$ENGINE_NAME.NULL = FALSE;
-					strcpy(TRG.RDB$ENGINE_NAME, external->engine.c_str());
-
-					if (external->name.length() >= sizeof(TRG.RDB$ENTRYPOINT))
-					{
-						status_exception::raise(
-							Arg::Gds(isc_arith_except) <<
-							Arg::Gds(isc_string_truncation));
-					}
-
-					TRG.RDB$ENTRYPOINT.NULL = (SSHORT) external->name.isEmpty();
-					strcpy(TRG.RDB$ENTRYPOINT, external->name.c_str());
-				}
-				else if (body)
-				{
-					TRG.RDB$TRIGGER_BLR.NULL = FALSE;
-					attachment->storeBinaryBlob(tdbb, transaction, &TRG.RDB$TRIGGER_BLR,
-						dsqlScratch->getBlrData());
-
-					TRG.RDB$DEBUG_INFO.NULL = FALSE;
-					attachment->storeBinaryBlob(tdbb, transaction, &TRG.RDB$DEBUG_INFO,
-						dsqlScratch->getDebugData());
-				}
-
-				if (source.hasData())
-				{
-					TRG.RDB$TRIGGER_SOURCE.NULL = FALSE;
-					attachment->storeMetaDataBlob(tdbb, transaction, &TRG.RDB$TRIGGER_SOURCE, source);
-				}
-
-				TRG.RDB$VALID_BLR = TRUE;
-
-				modified = true;
-			END_MODIFY
-		}
-		END_FOR
-	}
-	catch (const status_exception& ex)
-	{
-		rethrowMetaException(ex, ENCODE_ISC_MSG(102, DYN_MSG_FAC), modified);	// MODIFY TRIGGER failed
-	}
-
-	if (modified && runTriggers)
-		executeDdlTrigger(tdbb, transaction, DTW_AFTER, DDL_TRIGGER_ALTER_TRIGGER, name);
-
-	return modified;
-}
-
-
 void CreateAlterTriggerNode::compile(thread_db* tdbb, jrd_tra* /*transaction*/)
 {
 	if (invalid)
@@ -2629,14 +3005,12 @@
 		name.c_str());
 }
 
-
 DdlNode* DropTriggerNode::internalDsqlPass()
 {
 	dsqlScratch->flags |= (DsqlCompilerScratch::FLAG_BLOCK | DsqlCompilerScratch::FLAG_TRIGGER);
 	return DdlNode::internalDsqlPass();
 }
 
-
 void DropTriggerNode::execute(thread_db* tdbb, jrd_tra* transaction)
 {
 	// run all statements under savepoint control
@@ -2657,13 +3031,12 @@
 				case fb_sysflag_check_constraint:
 				case fb_sysflag_referential_constraint:
 				case fb_sysflag_view_check:
-					status_exception::raise(Arg::Gds(isc_no_meta_update) <<
-											Arg::Gds(isc_dyn_cant_modify_auto_trig));
+					status_exception::raise(Arg::Gds(isc_dyn_cant_modify_auto_trig));
 					break;
 
 				case fb_sysflag_system:
-					status_exception::raise(Arg::Gds(isc_no_meta_update) <<
-											Arg::Gds(isc_dyn_cannot_mod_systrig) << X.RDB$TRIGGER_NAME);
+					status_exception::raise(
+						Arg::Gds(isc_dyn_cannot_mod_systrig) << X.RDB$TRIGGER_NAME);
 					break;
 
 				default:
@@ -2683,11 +3056,7 @@
 	END_FOR
 
 	if (!found && !silent)
-	{
-		status_exception::raise(
-			Arg::Gds(isc_no_meta_update) <<
-			Arg::Gds(isc_dyn_trig_not_found) << Arg::Str(name));
-	}
+		status_exception::raise(Arg::Gds(isc_dyn_trig_not_found) << Arg::Str(name));
 
 	requestHandle.reset(tdbb, drq_e_trg_msgs3, DYN_REQUESTS);
 
@@ -2758,7 +3127,6 @@
 	text.printf("RecreateTriggerNode\n");
 }
 
-
 DdlNode* RecreateTriggerNode::internalDsqlPass()
 {
 	dropNode.dsqlPass(dsqlScratch);
@@ -2766,14 +3134,13 @@
 	return DdlNode::internalDsqlPass();
 }
 
-
 void RecreateTriggerNode::execute(thread_db* tdbb, jrd_tra* transaction)
 {
 	// run all statements under savepoint control
 	AutoSavePoint savePoint(tdbb, transaction);
 
-	dropNode.executeDdl(tdbb, transaction);
-	createNode->executeDdl(tdbb, transaction);
+	dropNode.execute(tdbb, transaction);
+	createNode->execute(tdbb, transaction);
 
 	savePoint.release();	// everything is ok
 }
@@ -2805,170 +3172,147 @@
 
 	executeDdlTrigger(tdbb, transaction, DTW_BEFORE, DDL_TRIGGER_CREATE_COLLATION, name);
 
-	bool endStore = false;
+	AutoCacheRequest request(tdbb, drq_s_colls, DYN_REQUESTS);
 
-	try
+	STORE(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
+		X IN RDB$COLLATIONS
 	{
-		AutoCacheRequest request(tdbb, drq_s_colls, DYN_REQUESTS);
+		X.RDB$CHARACTER_SET_ID = forCharSetId;
+		strcpy(X.RDB$COLLATION_NAME, name.c_str());
+		X.RDB$SYSTEM_FLAG = 0;
 
-		STORE(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
-			X IN RDB$COLLATIONS
-		{
-			X.RDB$CHARACTER_SET_ID = forCharSetId;
-			strcpy(X.RDB$COLLATION_NAME, name.c_str());
-			X.RDB$SYSTEM_FLAG = 0;
+		X.RDB$SPECIFIC_ATTRIBUTES.NULL = TRUE;
+		X.RDB$BASE_COLLATION_NAME.NULL = TRUE;
 
-			X.RDB$SPECIFIC_ATTRIBUTES.NULL = TRUE;
-			X.RDB$BASE_COLLATION_NAME.NULL = TRUE;
+		CharSet* cs = INTL_charset_lookup(tdbb, forCharSetId);
+		SubtypeInfo info;
 
-			CharSet* cs = INTL_charset_lookup(tdbb, forCharSetId);
-			SubtypeInfo info;
-
-			if (fromName.hasData())
+		if (fromName.hasData())
+		{
+			if (MET_get_char_coll_subtype_info(tdbb,
+					INTL_CS_COLL_TO_TTYPE(forCharSetId, fromCollationId), &info) &&
+				info.specificAttributes.hasData())
 			{
-				if (MET_get_char_coll_subtype_info(tdbb,
-						INTL_CS_COLL_TO_TTYPE(forCharSetId, fromCollationId), &info) &&
-					info.specificAttributes.hasData())
-				{
-					UCharBuffer temp;
-					ULONG size = info.specificAttributes.getCount() * cs->maxBytesPerChar();
-
-					size = INTL_convert_bytes(tdbb, forCharSetId, temp.getBuffer(size), size,
-						CS_METADATA, info.specificAttributes.begin(),
-						info.specificAttributes.getCount(), status_exception::raise);
-					temp.shrink(size);
-					info.specificAttributes = temp;
-				}
-
-				strcpy(X.RDB$BASE_COLLATION_NAME, info.baseCollationName.c_str());
-				X.RDB$BASE_COLLATION_NAME.NULL = FALSE;
-			}
-			else if (fromExternal.hasData())
-			{
-				strcpy(X.RDB$BASE_COLLATION_NAME, fromExternal.c_str());
-				X.RDB$BASE_COLLATION_NAME.NULL = FALSE;
-			}
-
-			if (specificAttributes.hasData())
-			{
 				UCharBuffer temp;
-				ULONG size = specificAttributes.getCount() * cs->maxBytesPerChar();
+				ULONG size = info.specificAttributes.getCount() * cs->maxBytesPerChar();
 
 				size = INTL_convert_bytes(tdbb, forCharSetId, temp.getBuffer(size), size,
-					attachment->att_charset, specificAttributes.begin(),
-					specificAttributes.getCount(), status_exception::raise);
+					CS_METADATA, info.specificAttributes.begin(),
+					info.specificAttributes.getCount(), status_exception::raise);
 				temp.shrink(size);
-				specificAttributes = temp;
+				info.specificAttributes = temp;
 			}
 
-			info.charsetName = forCharSet.c_str();
-			info.collationName = name;
-			if (X.RDB$BASE_COLLATION_NAME.NULL)
-				info.baseCollationName = info.collationName;
-			else
-				info.baseCollationName = X.RDB$BASE_COLLATION_NAME;
-			info.ignoreAttributes = false;
+			strcpy(X.RDB$BASE_COLLATION_NAME, info.baseCollationName.c_str());
+			X.RDB$BASE_COLLATION_NAME.NULL = FALSE;
+		}
+		else if (fromExternal.hasData())
+		{
+			strcpy(X.RDB$BASE_COLLATION_NAME, fromExternal.c_str());
+			X.RDB$BASE_COLLATION_NAME.NULL = FALSE;
+		}
 
-			if (!IntlManager::collationInstalled(info.baseCollationName.c_str(),
-					info.charsetName.c_str()))
-			{
-				// msg: 223: "Collation @1 not installed for character set @2"
-				status_exception::raise(
-					Arg::Gds(isc_no_meta_update) <<
-					Arg::Gds(ENCODE_ISC_MSG(223, DYN_MSG_FAC)) <<
-					info.baseCollationName << info.charsetName);
-			}
+		if (specificAttributes.hasData())
+	...
 
[truncated message content] |