Skip to content

Commit 68b1b14

Browse files
authored
Fix #8934 - Allow LTT commands in RO replica (#8943)
1 parent e541db2 commit 68b1b14

5 files changed

Lines changed: 53 additions & 2 deletions

File tree

src/dsql/DdlNodes.epp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ static const UCHAR nonnull_validation_blr[] =
9999
blr_eoc
100100
};
101101

102+
static void checkDeferredDdlInReadOnlyReplica(thread_db* tdbb);
102103
static void checkForeignKeyTempScope(thread_db* tdbb, jrd_tra* transaction,
103104
const QualifiedName& childRelName, const QualifiedName& masterIndexName);
104105
static void checkLttNotInUse(thread_db* tdbb, jrd_tra* transaction, const LocalTemporaryTable* ltt);
@@ -209,6 +210,16 @@ void ExecInSecurityDb::executeInSecurityDb(jrd_tra* localTransaction)
209210
//----------------------
210211

211212

213+
// Check if we are trying to execute prohibited DDL in read-only replica and raise an error if so.
214+
static void checkDeferredDdlInReadOnlyReplica(thread_db* tdbb)
215+
{
216+
if (tdbb->getDatabase()->isReplica(REPLICA_READ_ONLY) &&
217+
!(tdbb->tdbb_flags & TDBB_replicator))
218+
{
219+
ERRD_post(Arg::Gds(isc_read_only_trans));
220+
}
221+
}
222+
212223
// Check temporary table reference rules between given child relation and master
213224
// relation (owner of given PK/UK index).
214225
static void checkForeignKeyTempScope(thread_db* tdbb, jrd_tra* transaction,
@@ -9232,6 +9243,7 @@ void CreateRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScrat
92329243

92339244
if (tempFlag == REL_temp_ltt)
92349245
{
9246+
dsqlScratch->flags |= DsqlCompilerScratch::FLAG_ACTUAL_LTT_DDL;
92359247
defineLocalTempTable(tdbb, dsqlScratch, transaction);
92369248

92379249
dsqlScratch->relation->rel_flags &= ~REL_creating;
@@ -9618,6 +9630,7 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc
96189630
// Handle Local Temporary Tables differently
96199631
if (relation->rel_flags & REL_ltt_created)
96209632
{
9633+
dsqlScratch->flags |= DsqlCompilerScratch::FLAG_ACTUAL_LTT_DDL;
96219634
alterLocalTempTable(tdbb, dsqlScratch, transaction);
96229635

96239636
// Update DSQL cache
@@ -9626,6 +9639,8 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc
96269639
return;
96279640
}
96289641

9642+
checkDeferredDdlInReadOnlyReplica(tdbb);
9643+
96299644
bool beforeTriggerWasExecuted = false;
96309645

96319646
const auto executeBeforeTrigger = [&]()
@@ -10939,6 +10954,8 @@ void DropRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch
1093910954

1094010955
if (const auto lttIt = attachment->att_local_temporary_tables.get(name))
1094110956
{
10957+
dsqlScratch->flags |= DsqlCompilerScratch::FLAG_ACTUAL_LTT_DDL;
10958+
1094210959
if (view)
1094310960
{
1094410961
status_exception::raise(
@@ -10976,6 +10993,8 @@ void DropRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch
1097610993
if (!rel && silent)
1097710994
return;
1097810995

10996+
checkDeferredDdlInReadOnlyReplica(tdbb);
10997+
1097910998
if (tdbb->getDatabase()->readOnly())
1098010999
ERRD_post(Arg::Gds(isc_read_only_database));
1098111000

@@ -13195,11 +13214,14 @@ void CreateIndexNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch,
1319513214
// Check if target relation is a Local Temporary Table
1319613215
if (const auto lttPtr = attachment->att_local_temporary_tables.get(relation->dsqlName))
1319713216
{
13217+
dsqlScratch->flags |= DsqlCompilerScratch::FLAG_ACTUAL_LTT_DDL;
1319813218
defineLocalTempIndex(tdbb, dsqlScratch, transaction, *lttPtr);
1319913219
savePoint.release(); // everything is ok
1320013220
return;
1320113221
}
1320213222

13223+
checkDeferredDdlInReadOnlyReplica(tdbb);
13224+
1320313225
if (tdbb->getDatabase()->readOnly())
1320413226
ERRD_post(Arg::Gds(isc_read_only_database));
1320513227

@@ -13428,11 +13450,14 @@ void AlterIndexNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch,
1342813450

1342913451
if (MET_get_ltt_index(transaction->getAttachment(), indexName, &ltt, &lttIndex))
1343013452
{
13453+
dsqlScratch->flags |= DsqlCompilerScratch::FLAG_ACTUAL_LTT_DDL;
1343113454
alterLocalTempIndex(tdbb, dsqlScratch, transaction, ltt, lttIndex);
1343213455
savePoint.release(); // everything is ok
1343313456
return;
1343413457
}
1343513458

13459+
checkDeferredDdlInReadOnlyReplica(tdbb);
13460+
1343613461
if (tdbb->getDatabase()->readOnly())
1343713462
ERRD_post(Arg::Gds(isc_read_only_database));
1343813463

@@ -13627,11 +13652,14 @@ void SetStatisticsNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc
1362713652

1362813653
if (MET_get_ltt_index(transaction->getAttachment(), indexName, &ltt, &lttIndex))
1362913654
{
13655+
dsqlScratch->flags |= DsqlCompilerScratch::FLAG_ACTUAL_LTT_DDL;
1363013656
setStatisticsLocalTempIndex(tdbb, dsqlScratch, transaction, ltt, lttIndex);
1363113657
savePoint.release(); // everything is ok
1363213658
return;
1363313659
}
1363413660

13661+
checkDeferredDdlInReadOnlyReplica(tdbb);
13662+
1363513663
AutoCacheRequest request(tdbb, drq_m_set_statistics, DYN_REQUESTS);
1363613664
bool found = false;
1363713665

@@ -13742,11 +13770,14 @@ void DropIndexNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, j
1374213770

1374313771
if (MET_get_ltt_index(transaction->getAttachment(), indexName, &ltt, &lttIndex))
1374413772
{
13773+
dsqlScratch->flags |= DsqlCompilerScratch::FLAG_ACTUAL_LTT_DDL;
1374513774
dropLocalTempIndex(tdbb, dsqlScratch, transaction, ltt, lttIndex);
1374613775
savePoint.release(); // everything is ok
1374713776
return;
1374813777
}
1374913778

13779+
checkDeferredDdlInReadOnlyReplica(tdbb);
13780+
1375013781
if (tdbb->getDatabase()->readOnly())
1375113782
ERRD_post(Arg::Gds(isc_read_only_database));
1375213783

src/dsql/DdlNodes.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,11 @@ class RecreateNode : public DdlNode
237237
return createNode->disallowedInReadOnlyDatabase();
238238
}
239239

240+
bool mustBeReplicated() const override
241+
{
242+
return createNode->mustBeReplicated();
243+
}
244+
240245
protected:
241246
void putErrorPrefix(Firebird::Arg::StatusVector& statusVector) override
242247
{
@@ -1760,6 +1765,11 @@ class CreateRelationNode final : public RelationNode
17601765
return RelationNode::dsqlPass(dsqlScratch);
17611766
}
17621767

1768+
bool mustBeReplicated() const override
1769+
{
1770+
return tempFlag != REL_temp_ltt;
1771+
}
1772+
17631773
bool disallowedInReadOnlyDatabase() const override
17641774
{
17651775
return tempFlag != REL_temp_ltt;
@@ -2128,6 +2138,11 @@ class SetStatisticsNode final : public DdlNode
21282138
return DdlNode::dsqlPass(dsqlScratch);
21292139
}
21302140

2141+
bool disallowedInReadOnlyDatabase() const override
2142+
{
2143+
return false; // Deferred to execute() - LTT status unknown at parse time
2144+
}
2145+
21312146
private:
21322147
void setStatisticsLocalTempIndex(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch,
21332148
jrd_tra* transaction, LocalTemporaryTable* ltt, LocalTemporaryTable::Index* lttIndex);

src/dsql/DsqlCompilerScratch.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ class DsqlCompilerScratch : public BlrDebugWriter
7878
static const unsigned FLAG_EXEC_BLOCK = 0x010000;
7979
static const unsigned FLAG_ALLOW_LTT_REFERENCES = 0x020000;
8080
static const unsigned FLAG_USING_STATEMENT = 0x040000;
81+
static const unsigned FLAG_ACTUAL_LTT_DDL = 0x080000;
8182

8283
static const unsigned MAX_NESTING = 512;
8384

src/dsql/DsqlRequests.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -972,6 +972,7 @@ void DsqlDdlRequest::execute(thread_db* tdbb, jrd_tra** traHandle,
972972
try
973973
{
974974
AutoSetRestoreFlag<ULONG> execDdl(&tdbb->tdbb_flags, TDBB_repl_in_progress, true);
975+
internalScratch->flags &= ~DsqlCompilerScratch::FLAG_ACTUAL_LTT_DDL;
975976

976977
//// Doing it in DFW_perform_work to avoid problems with DDL+DML in the same transaction.
977978
/// req_dbb->dbb_attachment->att_dsql_instance->dbb_statement_cache->purgeAllAttachments(tdbb);
@@ -981,7 +982,9 @@ void DsqlDdlRequest::execute(thread_db* tdbb, jrd_tra** traHandle,
981982
const bool isInternalRequest =
982983
(internalScratch->flags & DsqlCompilerScratch::FLAG_INTERNAL_REQUEST);
983984

984-
if (!isInternalRequest && node->mustBeReplicated())
985+
if (!isInternalRequest &&
986+
node->mustBeReplicated() &&
987+
!(internalScratch->flags & DsqlCompilerScratch::FLAG_ACTUAL_LTT_DDL))
985988
{
986989
REPL_exec_sql(tdbb, req_transaction, getDsqlStatement()->getOrgText(),
987990
*getDsqlStatement()->getSchemaSearchPath());

src/dsql/DsqlStatements.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,8 @@ void DsqlDdlStatement::dsqlPass(thread_db* tdbb, DsqlCompilerScratch* scratch, n
261261
// As an exception, not replicated DDL statements are also allowed.
262262
if (dbb->isReplica(REPLICA_READ_ONLY) &&
263263
!(tdbb->tdbb_flags & TDBB_replicator) &&
264-
node->mustBeReplicated())
264+
node->mustBeReplicated() &&
265+
node->disallowedInReadOnlyDatabase())
265266
{
266267
ERRD_post(Arg::Gds(isc_read_only_trans));
267268
}

0 commit comments

Comments
 (0)