8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-22 20:03:02 +01:00

DDL control for replication

This commit is contained in:
Dmitry Yemanov 2020-04-06 10:46:47 +03:00
parent 1b6b717f78
commit ddd5621666
17 changed files with 461 additions and 29 deletions

View File

@ -303,6 +303,7 @@ Firebird 4.0
LOCAL LOCAL
LOCALTIME LOCALTIME
LOCALTIMESTAMP LOCALTIMESTAMP
PUBLICATION *
RDB$ERROR * RDB$ERROR *
RDB$ROLE_IN_USE * RDB$ROLE_IN_USE *
RDB$SYSTEM_PRIVILEGE * RDB$SYSTEM_PRIVILEGE *
@ -319,6 +320,8 @@ Firebird 4.0
COMPARE_DECFLOAT * COMPARE_DECFLOAT *
CUME_DIST (1) CUME_DIST (1)
DEFINER DEFINER
DISABLE *
ENABLE *
EXCLUDE EXCLUDE
FIRST_DAY * FIRST_DAY *
FOLLOWING FOLLOWING

View File

@ -185,6 +185,7 @@ static const TOK tokens[] =
{TOK_DESCRIPTOR, "DESCRIPTOR", true}, {TOK_DESCRIPTOR, "DESCRIPTOR", true},
{TOK_DETERMINISTIC, "DETERMINISTIC", false}, {TOK_DETERMINISTIC, "DETERMINISTIC", false},
{TOK_DIFFERENCE, "DIFFERENCE", true}, {TOK_DIFFERENCE, "DIFFERENCE", true},
{TOK_DISABLE, "DISABLE", true},
{TOK_DISCONNECT, "DISCONNECT", false}, {TOK_DISCONNECT, "DISCONNECT", false},
{TOK_DISTINCT, "DISTINCT", false}, {TOK_DISTINCT, "DISTINCT", false},
{TOK_DO, "DO", true}, {TOK_DO, "DO", true},
@ -192,6 +193,7 @@ static const TOK tokens[] =
{TOK_DOUBLE, "DOUBLE", false}, {TOK_DOUBLE, "DOUBLE", false},
{TOK_DROP, "DROP", false}, {TOK_DROP, "DROP", false},
{TOK_ELSE, "ELSE", false}, {TOK_ELSE, "ELSE", false},
{TOK_ENABLE, "ENABLE", true},
{TOK_ENCRYPT, "ENCRYPT", true}, {TOK_ENCRYPT, "ENCRYPT", true},
{TOK_END, "END", false}, {TOK_END, "END", false},
{TOK_ENGINE, "ENGINE", true}, {TOK_ENGINE, "ENGINE", true},
@ -369,6 +371,7 @@ static const TOK tokens[] =
{TOK_PRIVILEGES, "PRIVILEGES", true}, {TOK_PRIVILEGES, "PRIVILEGES", true},
{TOK_PROCEDURE, "PROCEDURE", false}, {TOK_PROCEDURE, "PROCEDURE", false},
{TOK_PROTECTED, "PROTECTED", true}, {TOK_PROTECTED, "PROTECTED", true},
{TOK_PUBLICATION, "PUBLICATION", false},
{TOK_QUANTIZE, "QUANTIZE", true}, {TOK_QUANTIZE, "QUANTIZE", true},
{TOK_RAND, "RAND", true}, {TOK_RAND, "RAND", true},
{TOK_RANGE, "RANGE", true}, {TOK_RANGE, "RANGE", true},

View File

@ -7442,6 +7442,43 @@ void CreateRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScrat
} }
END_STORE END_STORE
bool replicationEnabled;
if (replicationState.specified)
replicationEnabled = replicationState.value;
else
{
// Apply the default replication state to the table being created
AutoCacheRequest request2(tdbb, drq_l_pub_mode, DYN_REQUESTS);
FOR(REQUEST_HANDLE request2 TRANSACTION_HANDLE transaction)
PUB IN RDB$PUBLICATIONS
WITH PUB.RDB$PUBLICATION_NAME EQ DEFAULT_PUBLICATION
{
replicationEnabled = (PUB.RDB$AUTO_ENABLE != 0);
}
END_FOR
}
if (replicationEnabled)
{
// Add table to the default publication
AutoCacheRequest request2(tdbb, drq_s_pub_tab, DYN_REQUESTS);
STORE(REQUEST_HANDLE request2 TRANSACTION_HANDLE transaction)
PTAB IN RDB$PUBLICATION_TABLES
{
strcpy(PTAB.RDB$PUBLICATION_NAME, DEFAULT_PUBLICATION);
PTAB.RDB$PUBLICATION_NAME.NULL = FALSE;
strcpy(PTAB.RDB$TABLE_NAME, name.c_str());
PTAB.RDB$TABLE_NAME.NULL = FALSE;
}
END_STORE
}
storePrivileges(tdbb, transaction, name, obj_relation, ALL_PRIVILEGES); storePrivileges(tdbb, transaction, name, obj_relation, ALL_PRIVILEGES);
ObjectsArray<CreateDropConstraint> constraints; ObjectsArray<CreateDropConstraint> constraints;
@ -7787,6 +7824,58 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc
break; break;
} }
case Clause::TYPE_ALTER_PUBLICATION:
{
const bool publicationState =
static_cast<const AlterPublicationClause*>(i->getObject())->state;
if (publicationState)
{
// Add table to the publication
try
{
AutoCacheRequest request(tdbb, drq_s_pub_tab, DYN_REQUESTS);
STORE(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
PTAB IN RDB$PUBLICATION_TABLES
{
strcpy(PTAB.RDB$PUBLICATION_NAME, DEFAULT_PUBLICATION);
PTAB.RDB$PUBLICATION_NAME.NULL = FALSE;
strcpy(PTAB.RDB$TABLE_NAME, name.c_str());
PTAB.RDB$TABLE_NAME.NULL = FALSE;
}
END_STORE
}
catch (const status_exception& ex)
{
if (ex.value()[1] != isc_unique_key_violation)
throw;
// Ignore duplicated records
fb_utils::init_status(tdbb->tdbb_status_vector);
}
}
else
{
// Drop table from the publication
AutoCacheRequest request(tdbb, drq_e_pub_tab, DYN_REQUESTS);
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
PTAB IN RDB$PUBLICATION_TABLES
WITH PTAB.RDB$PUBLICATION_NAME EQ DEFAULT_PUBLICATION
AND PTAB.RDB$TABLE_NAME EQ name.c_str()
{
ERASE PTAB;
}
END_FOR
}
break;
}
default: default:
fb_assert(false); fb_assert(false);
break; break;
@ -8551,6 +8640,18 @@ void DropRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch
} }
END_FOR END_FOR
// Drop table from all publications
request.reset(tdbb, drq_e_pub_tab_all, DYN_REQUESTS);
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
PTAB IN RDB$PUBLICATION_TABLES
WITH PTAB.RDB$TABLE_NAME EQ name.c_str()
{
ERASE PTAB;
}
END_FOR
if (found) if (found)
executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, ddlTriggerAction, name, NULL); executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, ddlTriggerAction, name, NULL);
else else
@ -12386,9 +12487,10 @@ void AlterDatabaseNode::checkPermission(thread_db* tdbb, jrd_tra* transaction)
void AlterDatabaseNode::checkClauses(thread_db* tdbb) void AlterDatabaseNode::checkClauses(thread_db* tdbb)
{ {
// Raises msg 298: Incompatible ALTER DATABASE clauses: '@1' and '@2'
if (clauses & CLAUSE_END_BACKUP) if (clauses & CLAUSE_END_BACKUP)
{ {
// msg 298: Incompatible ALTER DATABASE clauses: '@1' and '@2'
if (clauses & CLAUSE_BEGIN_BACKUP) if (clauses & CLAUSE_BEGIN_BACKUP)
(Arg::PrivateDyn(298) << Arg::Str("BEGIN BACKUP") << Arg::Str("END BACKUP")).raise(); (Arg::PrivateDyn(298) << Arg::Str("BEGIN BACKUP") << Arg::Str("END BACKUP")).raise();
@ -12400,10 +12502,13 @@ void AlterDatabaseNode::checkClauses(thread_db* tdbb)
} }
if ((clauses & CLAUSE_DROP_DIFFERENCE) && differenceFile.hasData()) if ((clauses & CLAUSE_DROP_DIFFERENCE) && differenceFile.hasData())
{
// msg 298: Incompatible ALTER DATABASE clauses: '@1' and '@2'
(Arg::PrivateDyn(298) << Arg::Str("ADD DIFFERENCE FILE") << Arg::Str("DROP DIFFERENCE FILE")).raise(); (Arg::PrivateDyn(298) << Arg::Str("ADD DIFFERENCE FILE") << Arg::Str("DROP DIFFERENCE FILE")).raise();
}
if ((clauses & CLAUSE_ENABLE_PUB) && (clauses & CLAUSE_DISABLE_PUB))
(Arg::PrivateDyn(298) << Arg::Str("ENABLE PUBLICATION") << Arg::Str("DISABLE PUBLICATION")).raise();
if ((clauses & CLAUSE_PUB_ADD_TABLE) && (clauses & CLAUSE_PUB_DROP_TABLE))
(Arg::PrivateDyn(298) << Arg::Str("ADD TABLE TO PUBLICATION") << Arg::Str("DROP TABLE FROM PUBLICATION")).raise();
} }
void AlterDatabaseNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, void AlterDatabaseNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch,
@ -12440,6 +12545,128 @@ void AlterDatabaseNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc
if (clauses & CLAUSE_DROP_DIFFERENCE) if (clauses & CLAUSE_DROP_DIFFERENCE)
changeBackupMode(tdbb, transaction, CLAUSE_DROP_DIFFERENCE); changeBackupMode(tdbb, transaction, CLAUSE_DROP_DIFFERENCE);
if (clauses & (CLAUSE_ENABLE_PUB | CLAUSE_DISABLE_PUB))
{
AutoCacheRequest request(tdbb, drq_m_pub_state, DYN_REQUESTS);
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
PUB IN RDB$PUBLICATIONS
WITH PUB.RDB$PUBLICATION_NAME EQ DEFAULT_PUBLICATION
{
MODIFY PUB
PUB.RDB$ACTIVE_FLAG.NULL = FALSE;
PUB.RDB$ACTIVE_FLAG = (clauses & CLAUSE_ENABLE_PUB) ? 1 : 0;
END_MODIFY
}
END_FOR
}
if (clauses & (CLAUSE_PUB_ADD_TABLE | CLAUSE_PUB_DROP_TABLE))
{
if (pubTables.isEmpty())
{
AutoCacheRequest request(tdbb, drq_l_pub_all_rels, DYN_REQUESTS);
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
REL IN RDB$RELATIONS
WITH REL.RDB$SYSTEM_FLAG EQ 0
AND REL.RDB$VIEW_BLR MISSING
{
const rel_t relType =
relationType(REL.RDB$RELATION_TYPE.NULL, REL.RDB$RELATION_TYPE);
if (relType == rel_persistent)
pubTables.add(REL.RDB$RELATION_NAME);
}
END_FOR
AutoCacheRequest request2(tdbb, drq_m_pub_mode, DYN_REQUESTS);
FOR(REQUEST_HANDLE request2 TRANSACTION_HANDLE transaction)
PUB IN RDB$PUBLICATIONS
WITH PUB.RDB$PUBLICATION_NAME EQ DEFAULT_PUBLICATION
{
MODIFY PUB
PUB.RDB$AUTO_ENABLE = (clauses & CLAUSE_PUB_ADD_TABLE) ? 1 : 0;
PUB.RDB$AUTO_ENABLE.NULL = FALSE;
END_MODIFY
}
END_FOR
}
else
{
AutoCacheRequest request(tdbb, drq_l_pub_rel_name, DYN_REQUESTS);
for (const MetaName* iter = pubTables.begin(); iter != pubTables.end(); ++iter)
{
const MetaName& tableName = *iter;
bool found = false;
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
REL IN RDB$RELATIONS
WITH REL.RDB$SYSTEM_FLAG EQ 0
AND REL.RDB$VIEW_BLR MISSING
AND REL.RDB$RELATION_NAME EQ tableName.c_str()
{
const rel_t relType =
relationType(REL.RDB$RELATION_TYPE.NULL, REL.RDB$RELATION_TYPE);
if (relType == rel_persistent)
found = true;
}
END_FOR
if (!found)
status_exception::raise(Arg::Gds(isc_dyn_table_not_found) << tableName);
}
}
for (const MetaName* iter = pubTables.begin(); iter != pubTables.end(); ++iter)
{
const MetaName& tableName = *iter;
if (clauses & CLAUSE_PUB_ADD_TABLE)
{
try
{
AutoCacheRequest request(tdbb, drq_s_pub_tab, DYN_REQUESTS);
STORE(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
PTAB IN RDB$PUBLICATION_TABLES
{
strcpy(PTAB.RDB$PUBLICATION_NAME, DEFAULT_PUBLICATION);
PTAB.RDB$PUBLICATION_NAME.NULL = FALSE;
strcpy(PTAB.RDB$TABLE_NAME, tableName.c_str());
PTAB.RDB$TABLE_NAME.NULL = FALSE;
}
END_STORE
}
catch (const status_exception& ex)
{
if (ex.value()[1] != isc_unique_key_violation)
throw;
// Ignore duplicated records
fb_utils::init_status(tdbb->tdbb_status_vector);
}
}
else
{
AutoCacheRequest request(tdbb, drq_e_pub_tab, DYN_REQUESTS);
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
PTAB IN RDB$PUBLICATION_TABLES
WITH PTAB.RDB$PUBLICATION_NAME EQ DEFAULT_PUBLICATION
AND PTAB.RDB$TABLE_NAME EQ tableName.c_str()
{
ERASE PTAB;
}
END_FOR
}
}
}
SLONG dbAlloc = PageSpace::maxAlloc(tdbb->getDatabase()); SLONG dbAlloc = PageSpace::maxAlloc(tdbb->getDatabase());
SLONG start = create ? createLength + 1 : 0; SLONG start = create ? createLength + 1 : 0;
for (NestConst<DbFileClause>* i = files.begin(); i != files.end(); ++i) for (NestConst<DbFileClause>* i = files.begin(); i != files.end(); ++i)

View File

@ -1310,7 +1310,8 @@ public:
TYPE_ALTER_COL_TYPE, TYPE_ALTER_COL_TYPE,
TYPE_DROP_COLUMN, TYPE_DROP_COLUMN,
TYPE_DROP_CONSTRAINT, TYPE_DROP_CONSTRAINT,
TYPE_ALTER_SQL_SECURITY TYPE_ALTER_SQL_SECURITY,
TYPE_ALTER_PUBLICATION
}; };
explicit Clause(MemoryPool& p, Type aType) explicit Clause(MemoryPool& p, Type aType)
@ -1508,6 +1509,16 @@ public:
Nullable<bool> ssDefiner; Nullable<bool> ssDefiner;
}; };
struct AlterPublicationClause : public Clause
{
explicit AlterPublicationClause(MemoryPool& p)
: Clause(p, TYPE_ALTER_PUBLICATION)
{
}
bool state;
};
RelationNode(MemoryPool& p, RelationSourceNode* aDsqlNode); RelationNode(MemoryPool& p, RelationSourceNode* aDsqlNode);
static void deleteLocalField(thread_db* tdbb, jrd_tra* transaction, static void deleteLocalField(thread_db* tdbb, jrd_tra* transaction,
@ -1556,6 +1567,7 @@ public:
Firebird::MetaName name; Firebird::MetaName name;
Firebird::Array<NestConst<Clause> > clauses; Firebird::Array<NestConst<Clause> > clauses;
Nullable<bool> ssDefiner; Nullable<bool> ssDefiner;
Nullable<bool> replicationState;
}; };
@ -2391,6 +2403,10 @@ public:
static const unsigned CLAUSE_END_BACKUP = 0x02; static const unsigned CLAUSE_END_BACKUP = 0x02;
static const unsigned CLAUSE_DROP_DIFFERENCE = 0x04; static const unsigned CLAUSE_DROP_DIFFERENCE = 0x04;
static const unsigned CLAUSE_CRYPT = 0x08; static const unsigned CLAUSE_CRYPT = 0x08;
static const unsigned CLAUSE_ENABLE_PUB = 0x10;
static const unsigned CLAUSE_DISABLE_PUB = 0x20;
static const unsigned CLAUSE_PUB_ADD_TABLE = 0x40;
static const unsigned CLAUSE_PUB_DROP_TABLE = 0x80;
static const unsigned RDB_DATABASE_MASK = static const unsigned RDB_DATABASE_MASK =
CLAUSE_BEGIN_BACKUP | CLAUSE_END_BACKUP | CLAUSE_DROP_DIFFERENCE; CLAUSE_BEGIN_BACKUP | CLAUSE_END_BACKUP | CLAUSE_DROP_DIFFERENCE;
@ -2407,7 +2423,8 @@ public:
setDefaultCollation(p), setDefaultCollation(p),
files(p), files(p),
cryptPlugin(p), cryptPlugin(p),
keyName(p) keyName(p),
pubTables(p)
{ {
} }
@ -2450,6 +2467,7 @@ public:
Firebird::MetaName cryptPlugin; Firebird::MetaName cryptPlugin;
Firebird::MetaName keyName; Firebird::MetaName keyName;
Nullable<bool> ssDefiner; Nullable<bool> ssDefiner;
Firebird::Array<Firebird::MetaName> pubTables;
}; };

View File

@ -605,6 +605,8 @@ using namespace Firebird;
%token <metaNamePtr> CUME_DIST %token <metaNamePtr> CUME_DIST
%token <metaNamePtr> DECFLOAT %token <metaNamePtr> DECFLOAT
%token <metaNamePtr> DEFINER %token <metaNamePtr> DEFINER
%token <metaNamePtr> DISABLE
%token <metaNamePtr> ENABLE
%token <metaNamePtr> EXCESS %token <metaNamePtr> EXCESS
%token <metaNamePtr> EXCLUDE %token <metaNamePtr> EXCLUDE
%token <metaNamePtr> EXTENDED %token <metaNamePtr> EXTENDED
@ -634,6 +636,7 @@ using namespace Firebird;
%token <metaNamePtr> PERCENT_RANK %token <metaNamePtr> PERCENT_RANK
%token <metaNamePtr> PRECEDING %token <metaNamePtr> PRECEDING
%token <metaNamePtr> PRIVILEGE %token <metaNamePtr> PRIVILEGE
%token <metaNamePtr> PUBLICATION
%token <metaNamePtr> QUANTIZE %token <metaNamePtr> QUANTIZE
%token <metaNamePtr> RANGE %token <metaNamePtr> RANGE
%token <metaNamePtr> RDB_ERROR %token <metaNamePtr> RDB_ERROR
@ -2175,13 +2178,28 @@ table_clause
{ {
$<createRelationNode>$ = newNode<CreateRelationNode>($1, $2); $<createRelationNode>$ = newNode<CreateRelationNode>($1, $2);
} }
'(' table_elements($3) ')' sql_security_clause '(' table_elements($3) ')' sql_security_clause publication_state
{ {
$$ = $3; $$ = $3;
$$->ssDefiner = $7; $$->ssDefiner = $7;
$$->replicationState = $8;
} }
; ;
%type <nullableBoolVal> sql_security_clause
sql_security_clause
: /* nothing */ { $$ = Nullable<bool>::empty(); }
| SQL SECURITY DEFINER { $$ = Nullable<bool>::val(true); }
| SQL SECURITY INVOKER { $$ = Nullable<bool>::val(false); }
;
%type <nullableBoolVal> publication_state
publication_state
: /* nothing */ { $$ = Nullable<bool>::empty(); }
| ENABLE PUBLICATION { $$ = Nullable<bool>::val(true); }
| DISABLE PUBLICATION { $$ = Nullable<bool>::val(false); }
;
%type <createRelationNode> gtt_table_clause %type <createRelationNode> gtt_table_clause
gtt_table_clause gtt_table_clause
: simple_table_name : simple_table_name
@ -2641,13 +2659,6 @@ procedure_clause_start
{ $$ = $2; } { $$ = $2; }
; ;
%type <nullableBoolVal> sql_security_clause
sql_security_clause
: /* nothing */ { $$ = Nullable<bool>::empty(); }
| SQL SECURITY DEFINER { $$ = Nullable<bool>::val(true); }
| SQL SECURITY INVOKER { $$ = Nullable<bool>::val(false); }
;
%type <createAlterProcedureNode> alter_procedure_clause %type <createAlterProcedureNode> alter_procedure_clause
alter_procedure_clause alter_procedure_clause
: procedure_clause : procedure_clause
@ -4135,6 +4146,20 @@ alter_op($relationNode)
newNode<RelationNode::AlterSqlSecurityClause>(); newNode<RelationNode::AlterSqlSecurityClause>();
$relationNode->clauses.add(clause); $relationNode->clauses.add(clause);
} }
| ENABLE PUBLICATION
{
RelationNode::AlterPublicationClause* clause =
newNode<RelationNode::AlterPublicationClause>();
clause->state = true;
$relationNode->clauses.add(clause);
}
| DISABLE PUBLICATION
{
RelationNode::AlterPublicationClause* clause =
newNode<RelationNode::AlterPublicationClause>();
clause->state = false;
$relationNode->clauses.add(clause);
}
; ;
%type <metaNamePtr> alter_column_name %type <metaNamePtr> alter_column_name
@ -4390,6 +4415,14 @@ db_alter_clause($alterDatabaseNode)
{ $alterDatabaseNode->linger = 0; } { $alterDatabaseNode->linger = 0; }
| SET DEFAULT sql_security_clause | SET DEFAULT sql_security_clause
{ $alterDatabaseNode->ssDefiner = $3; } { $alterDatabaseNode->ssDefiner = $3; }
| ENABLE PUBLICATION
{ $alterDatabaseNode->clauses |= AlterDatabaseNode::CLAUSE_ENABLE_PUB; }
| DISABLE PUBLICATION
{ $alterDatabaseNode->clauses |= AlterDatabaseNode::CLAUSE_DISABLE_PUB; }
| ADD pub_table_filter($alterDatabaseNode) TO PUBLICATION
{ $alterDatabaseNode->clauses |= AlterDatabaseNode::CLAUSE_PUB_ADD_TABLE; }
| DROP pub_table_filter($alterDatabaseNode) FROM PUBLICATION
{ $alterDatabaseNode->clauses |= AlterDatabaseNode::CLAUSE_PUB_DROP_TABLE; }
; ;
%type crypt_key_clause(<alterDatabaseNode>) %type crypt_key_clause(<alterDatabaseNode>)
@ -4398,6 +4431,24 @@ crypt_key_clause($alterDatabaseNode)
| KEY valid_symbol_name { $alterDatabaseNode->keyName = *$2; } | KEY valid_symbol_name { $alterDatabaseNode->keyName = *$2; }
; ;
%type pub_table_filter(<alterDatabaseNode>)
pub_table_filter($alterDatabaseNode)
: ALL
| TABLE pub_table_list($alterDatabaseNode)
;
%type pub_table_list(<alterDatabaseNode>)
pub_table_list($alterDatabaseNode)
: pub_table_clause($alterDatabaseNode)
| pub_table_list ',' pub_table_clause($alterDatabaseNode)
;
%type pub_table_clause(<alterDatabaseNode>)
pub_table_clause($alterDatabaseNode)
: symbol_table_name
{ $alterDatabaseNode->pubTables.add(*$1); }
;
// ALTER TRIGGER // ALTER TRIGGER
%type <createAlterTriggerNode> alter_trigger_clause %type <createAlterTriggerNode> alter_trigger_clause
@ -8650,8 +8701,8 @@ non_reserved_word
| FREE_IT | FREE_IT
| RESTRICT | RESTRICT
| ROLE | ROLE
| TYPE // added in IB 6.0 | TYPE // added in IB 6.0
| BREAK // added in FB 1.0 | BREAK // added in FB 1.0
| DESCRIPTOR | DESCRIPTOR
| SUBSTRING | SUBSTRING
| COALESCE // added in FB 1.5 | COALESCE // added in FB 1.5
@ -8868,6 +8919,8 @@ non_reserved_word
| CTR_LITTLE_ENDIAN | CTR_LITTLE_ENDIAN
| CUME_DIST | CUME_DIST
| DEFINER | DEFINER
| DISABLE
| ENABLE
| EXCESS | EXCESS
| EXCLUDE | EXCLUDE
| EXTENDED | EXTENDED

View File

@ -393,6 +393,7 @@ const ULONG REL_jrd_view = 0x10000; // relation is VIEW
const ULONG REL_gc_blocking = 0x20000; // request to downgrade\release gc lock const ULONG REL_gc_blocking = 0x20000; // request to downgrade\release gc lock
const ULONG REL_gc_disabled = 0x40000; // gc is disabled temporarily const ULONG REL_gc_disabled = 0x40000; // gc is disabled temporarily
const ULONG REL_gc_lockneed = 0x80000; // gc lock should be acquired const ULONG REL_gc_lockneed = 0x80000; // gc lock should be acquired
const ULONG REL_replicating = 0x100000; // table is being replicated
/// class jrd_rel /// class jrd_rel

View File

@ -147,6 +147,8 @@ const char* const FUNCTIONS_GENERATOR = "RDB$FUNCTIONS";
const char* const IMPLICIT_INTEGRITY_PREFIX = "INTEG_"; const char* const IMPLICIT_INTEGRITY_PREFIX = "INTEG_";
const int IMPLICIT_INTEGRITY_PREFIX_LEN = 6; const int IMPLICIT_INTEGRITY_PREFIX_LEN = 6;
// Default publication name
const char* const DEFAULT_PUBLICATION = "RDB$DEFAULT";
//***************************************** //*****************************************
// System flag meaning - mainly Firebird. // System flag meaning - mainly Firebird.

View File

@ -244,6 +244,14 @@ enum drq_type_t
drq_generator_exist, // check if generator exists drq_generator_exist, // check if generator exists
drq_rel_field_exist, // check if a field of relation or view exists drq_rel_field_exist, // check if a field of relation or view exists
drq_m_coll_attrs, // modify collation attributes drq_m_coll_attrs, // modify collation attributes
drq_l_pub_mode, // lookup publication auto-enable mode
drq_m_pub_state, // modify publication state
drq_m_pub_mode, // modify publication auto-enable mode
drq_s_pub_tab, // store relation into publication
drq_e_pub_tab, // erase relation from publication
drq_l_pub_rel_name, // lookup relation by name
drq_l_pub_all_rels, // iterate through all user relations
drq_e_pub_tab_all, // erase relation from all publication
drq_MAX drq_MAX
}; };

View File

@ -210,3 +210,5 @@
FIELD(fld_crypt_state , nam_crypt_state , dtype_short , sizeof(SSHORT) , 0 , NULL , true) FIELD(fld_crypt_state , nam_crypt_state , dtype_short , sizeof(SSHORT) , 0 , NULL , true)
FIELD(fld_remote_crypt , nam_wire_crypt_plugin, dtype_varying, MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true) FIELD(fld_remote_crypt , nam_wire_crypt_plugin, dtype_varying, MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true)
FIELD(fld_pub_name , nam_pub_name , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , false)

View File

@ -295,6 +295,15 @@ static const struct ini_idx_t indices[] =
INDEX(54, rel_backup_history, idx_unique, 1) INDEX(54, rel_backup_history, idx_unique, 1)
SEGMENT(f_backup_guid, idx_string) // backup guid SEGMENT(f_backup_guid, idx_string) // backup guid
}}, }},
// define index RDB$INDEX_55 for RDB$PUBLICATIONS unique RDB$PUBLICATION_NAME;
INDEX(55, rel_pubs, idx_unique, 1)
SEGMENT(f_pub_name, idx_string) // publication name
}},
// define index RDB$INDEX_56 for RDB$PUBLICATION_TABLES unique RDB$TABLE_NAME, RDB$PUBLICATION_NAME;
INDEX(56, rel_pub_tables, idx_unique, 2)
SEGMENT(f_pubtab_tab_name, idx_string), // table name
SEGMENT(f_pubtab_pub_name, idx_string) // publication name
}},
}; };
#define SYSTEM_INDEX_COUNT FB_NELEM(indices) #define SYSTEM_INDEX_COUNT FB_NELEM(indices)

View File

@ -77,6 +77,7 @@ static void add_security_class(thread_db* tdbb, AutoRequest&, const MetaName& cl
USHORT acl_length, const UCHAR* acl); USHORT acl_length, const UCHAR* acl);
static void add_security_to_sys_rel(thread_db*, AutoRequest&, AutoRequest&, AutoRequest&, const MetaName&, static void add_security_to_sys_rel(thread_db*, AutoRequest&, AutoRequest&, AutoRequest&, const MetaName&,
const TEXT*, const USHORT, const UCHAR*); const TEXT*, const USHORT, const UCHAR*);
static void store_default_pub(thread_db*, const MetaName&);
static void store_generator(thread_db*, const gen*, AutoRequest&, const MetaName&); static void store_generator(thread_db*, const gen*, AutoRequest&, const MetaName&);
static void store_global_field(thread_db*, const gfld*, AutoRequest&, const MetaName&); static void store_global_field(thread_db*, const gfld*, AutoRequest&, const MetaName&);
static void store_intlnames(thread_db*, const MetaName&); static void store_intlnames(thread_db*, const MetaName&);
@ -327,6 +328,10 @@ void INI_format(const char* owner, const char* charset)
rdbRelationId = USER_DEF_REL_INIT_ID; rdbRelationId = USER_DEF_REL_INIT_ID;
ps->execute(tdbb, transaction); ps->execute(tdbb, transaction);
// Store default publication
store_default_pub(tdbb, ownerName);
// Store system role // Store system role
store_admin_role(tdbb, ADMIN_ROLE, ownerName, NULL); store_admin_role(tdbb, ADMIN_ROLE, ownerName, NULL);
@ -592,6 +597,8 @@ void INI_format(const char* owner, const char* charset)
for (const trigger_msg* message = trigger_messages; message->trigmsg_name; ++message) for (const trigger_msg* message = trigger_messages; message->trigmsg_name; ++message)
store_message(tdbb, message, handle1); store_message(tdbb, message, handle1);
handle1.reset();
// Add additional grants // Add additional grants
MetaName buf; MetaName buf;
@ -1311,6 +1318,32 @@ static void store_admin_role(thread_db* tdbb, const MetaName& roleName, MetaName
} }
static void store_default_pub(thread_db* tdbb, const MetaName& ownerName)
{
Attachment* const attachment = tdbb->getAttachment();
AutoRequest handle;
STORE(REQUEST_HANDLE handle) PUB IN RDB$PUBLICATIONS
{
PAD(DEFAULT_PUBLICATION, PUB.RDB$PUBLICATION_NAME);
PUB.RDB$PUBLICATION_NAME.NULL = FALSE;
PAD(ownerName.c_str(), PUB.RDB$OWNER_NAME);
PUB.RDB$OWNER_NAME.NULL = FALSE;
PUB.RDB$SYSTEM_FLAG = RDB_system;
PUB.RDB$SYSTEM_FLAG.NULL = FALSE;
PUB.RDB$ACTIVE_FLAG = 0;
PUB.RDB$ACTIVE_FLAG.NULL = FALSE;
PUB.RDB$AUTO_ENABLE = 0;
PUB.RDB$AUTO_ENABLE.NULL = FALSE;
}
END_STORE
}
// Add security class. // Add security class.
static void add_security_class(thread_db* tdbb, AutoRequest& handle, const MetaName& class_name, USHORT acl_length, const UCHAR* acl) static void add_security_class(thread_db* tdbb, AutoRequest& handle, const MetaName& class_name, USHORT acl_length, const UCHAR* acl)
{ {

View File

@ -179,6 +179,7 @@ enum irq_type_t
irq_linger, // get database linger value irq_linger, // get database linger value
irq_dbb_ss_definer, // get database sql security value irq_dbb_ss_definer, // get database sql security value
irq_out_proc_param_dep, // check output procedure parameter dependency irq_out_proc_param_dep, // check output procedure parameter dependency
irq_l_pub_tab_state, // lookup publication state for a table
irq_MAX irq_MAX
}; };

View File

@ -4085,6 +4085,23 @@ void MET_scan_relation(thread_db* tdbb, jrd_rel* relation)
delete csb; delete csb;
// Get publication state for this relation
request.reset(tdbb, irq_l_pub_tab_state, IRQ_REQUESTS);
relation->rel_flags &= ~REL_replicating;
FOR(REQUEST_HANDLE request)
PUB IN RDB$PUBLICATIONS CROSS
PTAB IN RDB$PUBLICATION_TABLES OVER RDB$PUBLICATION_NAME
WITH PUB.RDB$PUBLICATION_NAME EQ DEFAULT_PUBLICATION
AND PUB.RDB$ACTIVE_FLAG EQ 1
AND PTAB.RDB$TABLE_NAME EQ relation->rel_name.c_str()
{
relation->rel_flags |= REL_replicating;
}
END_FOR
// release any triggers in case of a rescan, but not if the rescan // release any triggers in case of a rescan, but not if the rescan
// hapenned while system triggers were being loaded. // hapenned while system triggers were being loaded.

View File

@ -428,3 +428,10 @@ NAME("RDB$TIME_ZONE_NAME", nam_tz_name)
NAME("RDB$TIME_ZONE_OFFSET", nam_tz_offset) NAME("RDB$TIME_ZONE_OFFSET", nam_tz_offset)
NAME("RDB$TIMESTAMP_TZ", nam_timestamp_tz) NAME("RDB$TIMESTAMP_TZ", nam_timestamp_tz)
NAME("RDB$DBTZ_VERSION", nam_tz_db_version) NAME("RDB$DBTZ_VERSION", nam_tz_db_version)
NAME("RDB$ACTIVE_FLAG", nam_active_flag)
NAME("RDB$AUTO_ENABLE", nam_auto_enable)
NAME("RDB$PUBLICATIONS", nam_pubs)
NAME("RDB$PUBLICATION_NAME", nam_pub_name)
NAME("RDB$PUBLICATION_TABLES", nam_pub_tables)
NAME("RDB$TABLE_NAME", nam_tab_name)

View File

@ -704,3 +704,18 @@ RELATION(nam_time_zones, rel_time_zones, ODS_13_0, rel_virtual)
FIELD(f_tz_id, nam_tz_id, fld_tz_id, 0, ODS_13_0) FIELD(f_tz_id, nam_tz_id, fld_tz_id, 0, ODS_13_0)
FIELD(f_tz_name, nam_tz_name, fld_tz_name, 0, ODS_13_0) FIELD(f_tz_name, nam_tz_name, fld_tz_name, 0, ODS_13_0)
END_RELATION END_RELATION
// Relation 51 (RDB$PUBLICATIONS)
RELATION(nam_pubs, rel_pubs, ODS_13_0, rel_persistent)
FIELD(f_pub_name, nam_pub_name, fld_pub_name, 1, ODS_13_0)
FIELD(f_pub_owner, nam_owner, fld_user, 1, ODS_13_0)
FIELD(f_pub_sys_flag, nam_sys_flag, fld_flag, 1, ODS_13_0)
FIELD(f_pub_active_flag, nam_active_flag, fld_flag, 1, ODS_13_0)
FIELD(f_pub_auto_enable, nam_auto_enable, fld_flag, 1, ODS_13_0)
END_RELATION
// Relation 52 (RDB$PUBLICATION_TABLES)
RELATION(nam_pub_tables, rel_pub_tables, ODS_13_0, rel_persistent)
FIELD(f_pubtab_pub_name, nam_pub_name, fld_pub_name, 1, ODS_13_0)
FIELD(f_pubtab_tab_name, nam_tab_name, fld_r_name, 1, ODS_13_0)
END_RELATION

View File

@ -389,10 +389,16 @@ void REPL_store(thread_db* tdbb, const record_param* rpb, jrd_tra* transaction)
if (relation->isTemporary()) if (relation->isTemporary())
return; return;
const auto matcher = attachment->att_repl_matcher.get(); if (!relation->isSystem())
{
if (!(relation->rel_flags & REL_replicating))
return;
if (!relation->isSystem() && matcher && !matcher->matchTable(relation->rel_name)) const auto matcher = attachment->att_repl_matcher.get();
return;
if (matcher && !matcher->matchTable(relation->rel_name))
return;
}
const auto record = upgradeRecord(tdbb, relation, rpb->rpb_record); const auto record = upgradeRecord(tdbb, relation, rpb->rpb_record);
fb_assert(record); fb_assert(record);
@ -460,10 +466,16 @@ void REPL_modify(thread_db* tdbb, const record_param* orgRpb,
if (relation->isTemporary()) if (relation->isTemporary())
return; return;
const auto matcher = attachment->att_repl_matcher.get(); if (!relation->isSystem())
{
if (!(relation->rel_flags & REL_replicating))
return;
if (!relation->isSystem() && matcher && !matcher->matchTable(relation->rel_name)) const auto matcher = attachment->att_repl_matcher.get();
return;
if (matcher && !matcher->matchTable(relation->rel_name))
return;
}
const auto newRecord = upgradeRecord(tdbb, relation, newRpb->rpb_record); const auto newRecord = upgradeRecord(tdbb, relation, newRpb->rpb_record);
fb_assert(newRecord); fb_assert(newRecord);
@ -546,10 +558,16 @@ void REPL_erase(thread_db* tdbb, const record_param* rpb, jrd_tra* transaction)
if (relation->isTemporary()) if (relation->isTemporary())
return; return;
const auto matcher = attachment->att_repl_matcher.get(); if (!relation->isSystem())
{
if (!(relation->rel_flags & REL_replicating))
return;
if (!relation->isSystem() && matcher && !matcher->matchTable(relation->rel_name)) const auto matcher = attachment->att_repl_matcher.get();
return;
if (matcher && !matcher->matchTable(relation->rel_name))
return;
}
const auto record = upgradeRecord(tdbb, relation, rpb->rpb_record); const auto record = upgradeRecord(tdbb, relation, rpb->rpb_record);
fb_assert(record); fb_assert(record);

View File

@ -1605,6 +1605,8 @@ bool VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
case rel_dims: case rel_dims:
case rel_filters: case rel_filters:
case rel_vrel: case rel_vrel:
case rel_args:
case rel_pub_tables:
protect_system_table_delupd(tdbb, relation, "DELETE"); protect_system_table_delupd(tdbb, relation, "DELETE");
break; break;
@ -1752,10 +1754,6 @@ bool VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
DFW_post_work(transaction, dfw_delete_global, &desc2, 0); DFW_post_work(transaction, dfw_delete_global, &desc2, 0);
break; break;
case rel_args:
protect_system_table_delupd(tdbb, relation, "DELETE");
break;
case rel_prc_prms: case rel_prc_prms:
protect_system_table_delupd(tdbb, relation, "DELETE"); protect_system_table_delupd(tdbb, relation, "DELETE");
EVL_field(0, rpb->rpb_record, f_prm_procedure, &desc); EVL_field(0, rpb->rpb_record, f_prm_procedure, &desc);
@ -1858,6 +1856,10 @@ bool VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
DFW_post_work(transaction, dfw_grant, &desc, id); DFW_post_work(transaction, dfw_grant, &desc, id);
break; break;
case rel_pubs:
protect_system_table_delupd(tdbb, relation, "DELETE");
break;
default: // Shut up compiler warnings default: // Shut up compiler warnings
break; break;
} }
@ -2861,6 +2863,7 @@ bool VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j
case rel_prc_prms: case rel_prc_prms:
case rel_auth_mapping: case rel_auth_mapping:
case rel_roles: case rel_roles:
case rel_pub_tables:
protect_system_table_delupd(tdbb, relation, "UPDATE"); protect_system_table_delupd(tdbb, relation, "UPDATE");
break; break;
@ -3147,6 +3150,11 @@ bool VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j
check_owner(tdbb, transaction, org_rpb, new_rpb, f_xcp_owner); check_owner(tdbb, transaction, org_rpb, new_rpb, f_xcp_owner);
break; break;
case rel_pubs:
protect_system_table_delupd(tdbb, relation, "UPDATE");
check_owner(tdbb, transaction, org_rpb, new_rpb, f_pub_owner);
break;
default: default:
break; break;
} }
@ -3495,6 +3503,7 @@ void VIO_store(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
case rel_dpds: case rel_dpds:
case rel_dims: case rel_dims:
case rel_segments: case rel_segments:
case rel_pub_tables:
protect_system_table_insert(tdbb, request, relation); protect_system_table_insert(tdbb, request, relation);
break; break;
@ -3785,6 +3794,12 @@ void VIO_store(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
f_backup_id, drq_g_nxt_nbakhist_id, "RDB$BACKUP_HISTORY"); f_backup_id, drq_g_nxt_nbakhist_id, "RDB$BACKUP_HISTORY");
break; break;
case rel_pubs:
protect_system_table_insert(tdbb, request, relation);
set_system_flag(tdbb, rpb->rpb_record, f_pub_sys_flag);
set_owner_name(tdbb, rpb->rpb_record, f_pub_owner);
break;
default: // Shut up compiler warnings default: // Shut up compiler warnings
break; break;
} }