Skip to content

Commit a8759b6

Browse files
committed
Blocking insert-exec inside function at runtime to match tsql semantics
1 parent 3824cf2 commit a8759b6

2 files changed

Lines changed: 27 additions & 30 deletions

File tree

contrib/babelfishpg_tsql/src/pl_exec.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9964,9 +9964,11 @@ pltsql_xact_cb(XactEvent event, void *arg)
99649964
ResetTopTransactionName();
99659965

99669966
/*
9967-
* Clean up INSERT EXEC context on transaction end. This is a safety
9968-
* net for timeouts, interrupts, and other cases where normal cleanup
9969-
* paths are bypassed. On commit, any remaining context is stale.
9967+
* Clean up INSERT EXEC context on transaction end. This is a signal that an
9968+
* aborted INSERT EXEC has nothing to flush: on abort the buffer temp
9969+
* table is gone, so clearing the context here makes the subsequent
9970+
* flush a no-op (it early-returns on a NULL context) instead of
9971+
* opening a dropped relation.
99709972
*/
99719973
if (pltsql_insert_exec_active())
99729974
pltsql_insert_exec_reset_all();

contrib/babelfishpg_tsql/src/pl_insert_exec.c

Lines changed: 22 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -223,11 +223,11 @@ void
223223
pltsql_set_insert_exec_context_info(const char *target_table)
224224
{
225225
Assert(insert_exec_ctx == NULL);
226-
insert_exec_ctx = MemoryContextAllocZero(TopTransactionContext,
226+
insert_exec_ctx = MemoryContextAllocZero(TopMemoryContext,
227227
sizeof(InsertExecContext));
228228

229229
insert_exec_ctx->target_table = target_table
230-
? MemoryContextStrdup(TopTransactionContext, target_table)
230+
? MemoryContextStrdup(TopMemoryContext, target_table)
231231
: NULL;
232232
/*
233233
* Snapshot the call stack entry at INSERT EXEC start. Comparing this
@@ -531,7 +531,6 @@ flush_insert_exec_temp_table(PLtsql_execstate *estate, const char *target_schema
531531
Relation temp_rel;
532532
char *qualified_target;
533533
InlineCodeBlockArgs *flush_args;
534-
PLtsql_execstate *flush_estate_saved;
535534

536535
if (insert_exec_ctx == NULL)
537536
return;
@@ -597,19 +596,21 @@ flush_insert_exec_temp_table(PLtsql_execstate *estate, const char *target_schema
597596
*/
598597
flush_args = create_args(0);
599598

600-
flush_estate_saved = insert_exec_flush_estate;
599+
if (insert_exec_flush_estate != NULL)
600+
elog(ERROR, "insert_exec_flush_estate is already set; INSERT EXEC flush must not nest");
601+
601602
insert_exec_flush_estate = estate;
602603
PG_TRY();
603604
{
604605
rc = execute_batch(estate, flush_query.data, flush_args, NULL);
605606
}
606607
PG_CATCH();
607608
{
608-
insert_exec_flush_estate = flush_estate_saved;
609+
insert_exec_flush_estate = NULL;
609610
PG_RE_THROW();
610611
}
611612
PG_END_TRY();
612-
insert_exec_flush_estate = flush_estate_saved;
613+
insert_exec_flush_estate = NULL;
613614

614615
pfree(flush_query.data);
615616

@@ -841,6 +842,19 @@ insert_exec_setup(PLtsql_execstate *estate,
841842
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
842843
errmsg("nested INSERT ... EXECUTE statements are not allowed")));
843844

845+
/*
846+
* T-SQL does not allow INSERT EXEC inside a function. The parser blocks
847+
* the common cases at CREATE FUNCTION time; this catches anything that
848+
* still reaches runtime (e.g. a table-variable target).
849+
*/
850+
if (estate->func &&
851+
estate->func->fn_oid != InvalidOid &&
852+
estate->func->fn_prokind == PROKIND_FUNCTION &&
853+
estate->func->fn_is_trigger == PLTSQL_NOT_TRIGGER)
854+
ereport(ERROR,
855+
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
856+
errmsg("'INSERT EXEC' cannot be used within a function")));
857+
844858
/* Build the quoted column list (if any) for temp table creation */
845859
column_list = build_quoted_column_list(info->columns);
846860

@@ -851,15 +865,9 @@ insert_exec_setup(PLtsql_execstate *estate,
851865
*/
852866
if (start_implicit_txn)
853867
{
854-
bool in_function = (estate->func &&
855-
estate->func->fn_oid != InvalidOid &&
856-
estate->func->fn_prokind == PROKIND_FUNCTION &&
857-
estate->func->fn_is_trigger == PLTSQL_NOT_TRIGGER);
858-
859868
if (!pltsql_disable_batch_auto_commit &&
860869
pltsql_support_tsql_transactions() &&
861-
!IsTransactionBlockActive() &&
862-
!in_function)
870+
!IsTransactionBlockActive())
863871
{
864872
elog(DEBUG4, "TSQL TXN Start internal transaction for INSERT EXEC");
865873
pltsql_start_txn();
@@ -899,20 +907,7 @@ insert_exec_flush_and_cleanup(PLtsql_execstate *estate, InsertExecInfo *info)
899907
char *column_list = build_quoted_column_list(info->columns);
900908
const char *flush_schema = (info->db_name != NULL || info->schema != NULL) ? info->schema : NULL;
901909

902-
PG_TRY();
903-
{
904-
/* Flush temp table to target table */
905-
flush_insert_exec_temp_table(estate, flush_schema, info->db_name, column_list);
906-
}
907-
PG_CATCH();
908-
{
909-
/* Free the column list and reset context before re-throwing. */
910-
if (column_list != NULL)
911-
pfree(column_list);
912-
pltsql_insert_exec_reset_all();
913-
PG_RE_THROW();
914-
}
915-
PG_END_TRY();
910+
flush_insert_exec_temp_table(estate, flush_schema, info->db_name, column_list);
916911

917912
if (column_list != NULL)
918913
pfree(column_list);

0 commit comments

Comments
 (0)