Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions src/dsql/DdlNodes.epp
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ static const UCHAR nonnull_validation_blr[] =
blr_eoc
};

static void checkDeferredDdlInReadOnlyReplica(thread_db* tdbb);
static void checkForeignKeyTempScope(thread_db* tdbb, jrd_tra* transaction,
const QualifiedName& childRelName, const QualifiedName& masterIndexName);
static void checkLttNotInUse(thread_db* tdbb, jrd_tra* transaction, const LocalTemporaryTable* ltt);
Expand Down Expand Up @@ -209,6 +210,16 @@ void ExecInSecurityDb::executeInSecurityDb(jrd_tra* localTransaction)
//----------------------


// Check if we are trying to execute prohibited DDL in read-only replica and raise an error if so.
static void checkDeferredDdlInReadOnlyReplica(thread_db* tdbb)
{
if (tdbb->getDatabase()->isReplica(REPLICA_READ_ONLY) &&
!(tdbb->tdbb_flags & TDBB_replicator))
{
ERRD_post(Arg::Gds(isc_read_only_trans));
}
}

// 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,
Expand Down Expand Up @@ -9233,6 +9244,7 @@ void CreateRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScrat

if (tempFlag == REL_temp_ltt)
{
dsqlScratch->flags |= DsqlCompilerScratch::FLAG_ACTUAL_LTT_DDL;
defineLocalTempTable(tdbb, dsqlScratch, transaction);

dsqlScratch->relation->rel_flags &= ~REL_creating;
Expand Down Expand Up @@ -9619,6 +9631,7 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc
// Handle Local Temporary Tables differently
if (relation->rel_flags & REL_ltt_created)
{
dsqlScratch->flags |= DsqlCompilerScratch::FLAG_ACTUAL_LTT_DDL;
alterLocalTempTable(tdbb, dsqlScratch, transaction);

// Update DSQL cache
Expand All @@ -9627,6 +9640,8 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc
return;
}

checkDeferredDdlInReadOnlyReplica(tdbb);

bool beforeTriggerWasExecuted = false;

const auto executeBeforeTrigger = [&]()
Expand Down Expand Up @@ -10940,6 +10955,8 @@ void DropRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch

if (const auto lttIt = attachment->att_local_temporary_tables.get(name))
{
dsqlScratch->flags |= DsqlCompilerScratch::FLAG_ACTUAL_LTT_DDL;

if (view)
{
status_exception::raise(
Expand Down Expand Up @@ -10977,6 +10994,8 @@ void DropRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch
if (!rel && silent)
return;

checkDeferredDdlInReadOnlyReplica(tdbb);

if (tdbb->getDatabase()->readOnly())
ERRD_post(Arg::Gds(isc_read_only_database));

Expand Down Expand Up @@ -13197,11 +13216,14 @@ void CreateIndexNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch,
// Check if target relation is a Local Temporary Table
if (const auto lttPtr = attachment->att_local_temporary_tables.get(relation->dsqlName))
{
dsqlScratch->flags |= DsqlCompilerScratch::FLAG_ACTUAL_LTT_DDL;
defineLocalTempIndex(tdbb, dsqlScratch, transaction, *lttPtr);
savePoint.release(); // everything is ok
return;
}

checkDeferredDdlInReadOnlyReplica(tdbb);

if (tdbb->getDatabase()->readOnly())
ERRD_post(Arg::Gds(isc_read_only_database));

Expand Down Expand Up @@ -13430,11 +13452,14 @@ void AlterIndexNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch,

if (MET_get_ltt_index(transaction->getAttachment(), indexName, &ltt, &lttIndex))
{
dsqlScratch->flags |= DsqlCompilerScratch::FLAG_ACTUAL_LTT_DDL;
alterLocalTempIndex(tdbb, dsqlScratch, transaction, ltt, lttIndex);
savePoint.release(); // everything is ok
return;
}

checkDeferredDdlInReadOnlyReplica(tdbb);

if (tdbb->getDatabase()->readOnly())
ERRD_post(Arg::Gds(isc_read_only_database));

Expand Down Expand Up @@ -13629,11 +13654,14 @@ void SetStatisticsNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc

if (MET_get_ltt_index(transaction->getAttachment(), indexName, &ltt, &lttIndex))
{
dsqlScratch->flags |= DsqlCompilerScratch::FLAG_ACTUAL_LTT_DDL;
setStatisticsLocalTempIndex(tdbb, dsqlScratch, transaction, ltt, lttIndex);
savePoint.release(); // everything is ok
return;
}

checkDeferredDdlInReadOnlyReplica(tdbb);

AutoCacheRequest request(tdbb, drq_m_set_statistics, DYN_REQUESTS);
bool found = false;

Expand Down Expand Up @@ -13744,11 +13772,14 @@ void DropIndexNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, j

if (MET_get_ltt_index(transaction->getAttachment(), indexName, &ltt, &lttIndex))
{
dsqlScratch->flags |= DsqlCompilerScratch::FLAG_ACTUAL_LTT_DDL;
dropLocalTempIndex(tdbb, dsqlScratch, transaction, ltt, lttIndex);
savePoint.release(); // everything is ok
return;
}

checkDeferredDdlInReadOnlyReplica(tdbb);

if (tdbb->getDatabase()->readOnly())
ERRD_post(Arg::Gds(isc_read_only_database));

Expand Down
15 changes: 15 additions & 0 deletions src/dsql/DdlNodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,11 @@ class RecreateNode : public DdlNode
return createNode->disallowedInReadOnlyDatabase();
}

bool mustBeReplicated() const override
{
return createNode->mustBeReplicated();
}

protected:
void putErrorPrefix(Firebird::Arg::StatusVector& statusVector) override
{
Expand Down Expand Up @@ -1760,6 +1765,11 @@ class CreateRelationNode final : public RelationNode
return RelationNode::dsqlPass(dsqlScratch);
}

bool mustBeReplicated() const override
{
return tempFlag != REL_temp_ltt;
}

bool disallowedInReadOnlyDatabase() const override
{
return tempFlag != REL_temp_ltt;
Expand Down Expand Up @@ -2128,6 +2138,11 @@ class SetStatisticsNode final : public DdlNode
return DdlNode::dsqlPass(dsqlScratch);
}

bool disallowedInReadOnlyDatabase() const override
{
return false; // Deferred to execute() - LTT status unknown at parse time
}

private:
void setStatisticsLocalTempIndex(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch,
jrd_tra* transaction, LocalTemporaryTable* ltt, LocalTemporaryTable::Index* lttIndex);
Expand Down
1 change: 1 addition & 0 deletions src/dsql/DsqlCompilerScratch.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ class DsqlCompilerScratch : public BlrDebugWriter
static const unsigned FLAG_EXEC_BLOCK = 0x010000;
static const unsigned FLAG_ALLOW_LTT_REFERENCES = 0x020000;
static const unsigned FLAG_USING_STATEMENT = 0x040000;
static const unsigned FLAG_ACTUAL_LTT_DDL = 0x080000;

static const unsigned MAX_NESTING = 512;

Expand Down
5 changes: 4 additions & 1 deletion src/dsql/DsqlRequests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -972,6 +972,7 @@ void DsqlDdlRequest::execute(thread_db* tdbb, jrd_tra** traHandle,
try
{
AutoSetRestoreFlag<ULONG> execDdl(&tdbb->tdbb_flags, TDBB_repl_in_progress, true);
internalScratch->flags &= ~DsqlCompilerScratch::FLAG_ACTUAL_LTT_DDL;

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

if (!isInternalRequest && node->mustBeReplicated())
if (!isInternalRequest &&
node->mustBeReplicated() &&
!(internalScratch->flags & DsqlCompilerScratch::FLAG_ACTUAL_LTT_DDL))
{
REPL_exec_sql(tdbb, req_transaction, getDsqlStatement()->getOrgText(),
*getDsqlStatement()->getSchemaSearchPath());
Expand Down
3 changes: 2 additions & 1 deletion src/dsql/DsqlStatements.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,8 @@ void DsqlDdlStatement::dsqlPass(thread_db* tdbb, DsqlCompilerScratch* scratch, n
// As an exception, not replicated DDL statements are also allowed.
if (dbb->isReplica(REPLICA_READ_ONLY) &&
!(tdbb->tdbb_flags & TDBB_replicator) &&
node->mustBeReplicated())
node->mustBeReplicated() &&
node->disallowedInReadOnlyDatabase())
{
ERRD_post(Arg::Gds(isc_read_only_trans));
}
Expand Down
Loading