@@ -99,6 +99,7 @@ static const UCHAR nonnull_validation_blr[] =
9999 blr_eoc
100100};
101101
102+ static void checkDeferredDdlInReadOnlyReplica(thread_db* tdbb);
102103static void checkForeignKeyTempScope(thread_db* tdbb, jrd_tra* transaction,
103104 const QualifiedName& childRelName, const QualifiedName& masterIndexName);
104105static 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).
214225static 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, <t, <tIndex))
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, <t, <tIndex))
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, <t, <tIndex))
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
0 commit comments