Skip to content

Commit 9746d29

Browse files
committed
INSERT EXEC: Code cleanup and improvements
- Remove dead code: flush_temp_table_to_target() function (unused, replaced by flush_insert_exec_temp_table()) - Remove dead estate fields from PLtsql_execstate: insert_exec_temp_table_oid, insert_exec_target_table, insert_exec_column_list (new design uses global variables instead) - Remove no-op functions: pltsql_insert_exec_enter_trycatch() and pltsql_insert_exec_exit_trycatch() (TRY-CATCH detection now uses err_ctx_stack via pltsql_insert_exec_in_trycatch()) - Change elog(LOG, ...) to elog(DEBUG1, ...) in TRY-CATCH cleanup code to avoid printing to server log in production - Improve DROP TABLE check in hooks.c: use OID comparison for regular tables (distinguishes schema-qualified names like schema1.orders vs schema2.orders), fall back to name comparison for temp tables
1 parent 00823dd commit 9746d29

File tree

3 files changed

+63
-217
lines changed

3 files changed

+63
-217
lines changed

contrib/babelfishpg_tsql/src/hooks.c

Lines changed: 47 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -824,59 +824,65 @@ pltsql_bbfCustomProcessUtility(ParseState *pstate, PlannedStmt *pstmt, const cha
824824
}
825825
case T_DropStmt:
826826
{
827-
/*
828-
* Check if DROP TABLE is trying to drop the INSERT EXEC target table.
829-
* SQL Server error 556: "cannot DROP TABLE because it is being used
830-
* by active queries in this session"
831-
*/
832-
DropStmt *stmt = (DropStmt *) parsetree;
833-
834-
if (stmt->removeType == OBJECT_TABLE && pltsql_insert_exec_active())
827+
DropStmt *drop = (DropStmt *) parsetree;
828+
if (drop->removeType == OBJECT_TABLE && pltsql_insert_exec_active())
835829
{
836-
const char *target_table = pltsql_get_insert_exec_target_table();
837-
838-
if (target_table != NULL)
830+
Oid target_oid = pltsql_get_insert_exec_target_rel_oid();
831+
832+
if (OidIsValid(target_oid))
839833
{
840-
ListCell *cell;
841-
842-
foreach(cell, stmt->objects)
834+
/*
835+
* Regular table: use OID comparison so schema-qualified names
836+
* like schema1.orders and schema2.orders are distinguished.
837+
*/
838+
ListCell *lc;
839+
foreach(lc, drop->objects)
843840
{
844-
List *names = (List *) lfirst(cell);
845-
char *table_name = NULL;
846-
847-
/* Get the table name from the list (last element) */
848-
if (list_length(names) > 0)
849-
{
850-
table_name = strVal(llast(names));
851-
}
852-
853-
if (table_name != NULL)
841+
List *names = lfirst_node(List, lc);
842+
RangeVar *rv = makeRangeVarFromNameList(names);
843+
Oid drop_oid = RangeVarGetRelid(rv, NoLock, true /* missing_ok */);
844+
845+
if (OidIsValid(drop_oid) && drop_oid == target_oid)
846+
ereport(ERROR,
847+
(errcode(ERRCODE_OBJECT_IN_USE),
848+
errmsg("cannot %s \"%s\" because it is "
849+
"being used by active queries in "
850+
"this session",
851+
"DROP TABLE", get_rel_name(drop_oid))));
852+
}
853+
}
854+
else
855+
{
856+
/*
857+
* Temp table / table variable: session-local, no persistent OID.
858+
* Fall back to unqualified name comparison (safe over-block).
859+
*/
860+
const char *target = pltsql_get_insert_exec_target_table();
861+
const char *dot = target ? strrchr(target, '.') : NULL;
862+
const char *unqualified = dot ? (dot + 1) : target;
863+
ListCell *lc;
864+
865+
if (unqualified != NULL)
866+
{
867+
foreach(lc, drop->objects)
854868
{
855-
/*
856-
* Compare table names (case-insensitive for temp tables).
857-
* The target_table might include schema prefix, so we need
858-
* to compare just the table name part.
859-
*/
860-
const char *target_name = strrchr(target_table, '.');
861-
if (target_name != NULL)
862-
target_name++; /* Skip the dot */
863-
else
864-
target_name = target_table;
865-
866-
if (pg_strcasecmp(table_name, target_name) == 0)
867-
{
869+
List *names = lfirst_node(List, lc);
870+
char *relname = strVal(llast(names));
871+
872+
if (pg_strcasecmp(relname, unqualified) == 0)
868873
ereport(ERROR,
869874
(errcode(ERRCODE_OBJECT_IN_USE),
870-
errmsg("cannot %s \"%s\" because it is being used by active queries in this session",
871-
"DROP TABLE", table_name)));
872-
}
875+
errmsg("cannot %s \"%s\" because it is "
876+
"being used by active queries in "
877+
"this session",
878+
"DROP TABLE", relname)));
873879
}
874880
}
875881
}
876882
}
877-
/* Let the default handler process the DROP */
878883
break;
879884
}
885+
880886
default:
881887
return false;
882888
break;

contrib/babelfishpg_tsql/src/pl_exec-2.c

Lines changed: 15 additions & 168 deletions
Original file line numberDiff line numberDiff line change
@@ -711,34 +711,23 @@ pltsql_get_insert_exec_target_table(void)
711711
}
712712

713713
/*
714-
* Get the column list for INSERT EXEC.
715-
*/
716-
const char *
717-
pltsql_get_insert_exec_column_list(void)
718-
{
719-
return insert_exec_column_list;
720-
}
721-
722-
/*
723-
* Increment TRY-CATCH depth when entering a TRY block during INSERT EXEC.
724-
* NOTE: This function is now a no-op. TRY-CATCH detection is done via err_ctx_stack.
725-
* Kept for API compatibility but does nothing.
714+
* Get the target table OID for INSERT EXEC.
715+
* This is the OID of the actual target table (not the temp table).
716+
* Used for schema-qualified DROP TABLE checks.
726717
*/
727-
void
728-
pltsql_insert_exec_enter_trycatch(void)
718+
Oid
719+
pltsql_get_insert_exec_target_rel_oid(void)
729720
{
730-
/* No-op: TRY-CATCH detection is done via err_ctx_stack in pltsql_insert_exec_in_trycatch() */
721+
return insert_exec_target_rel_oid;
731722
}
732723

733724
/*
734-
* Decrement TRY-CATCH depth when exiting a TRY block during INSERT EXEC.
735-
* NOTE: This function is now a no-op. TRY-CATCH detection is done via err_ctx_stack.
736-
* Kept for API compatibility but does nothing.
725+
* Get the column list for INSERT EXEC.
737726
*/
738-
void
739-
pltsql_insert_exec_exit_trycatch(void)
727+
const char *
728+
pltsql_get_insert_exec_column_list(void)
740729
{
741-
/* No-op: TRY-CATCH detection is done via err_ctx_stack in pltsql_insert_exec_in_trycatch() */
730+
return insert_exec_column_list;
742731
}
743732

744733
/*
@@ -2088,137 +2077,6 @@ flush_insert_exec_temp_table(PLtsql_execstate *estate)
20882077
pfree(saved_column_list);
20892078
}
20902079

2091-
/*
2092-
* Flush all rows from the temp table to the target table.
2093-
* This is the final step of INSERT EXEC - move data from buffer to target.
2094-
* When no column list is specified, we need to explicitly list non-IDENTITY
2095-
* columns to avoid column count mismatch.
2096-
*/
2097-
void
2098-
flush_temp_table_to_target(PLtsql_execstate *estate)
2099-
{
2100-
char temp_table_name[NAMEDATALEN];
2101-
StringInfoData flush_query;
2102-
int rc;
2103-
2104-
if (!OidIsValid(estate->insert_exec_temp_table_oid) ||
2105-
estate->insert_exec_target_table == NULL)
2106-
{
2107-
return;
2108-
}
2109-
2110-
snprintf(temp_table_name, sizeof(temp_table_name),
2111-
"#insert_exec_buf_%d", MyProcPid);
2112-
2113-
initStringInfo(&flush_query);
2114-
2115-
if (estate->insert_exec_column_list != NULL)
2116-
{
2117-
/* User specified columns - use them directly */
2118-
appendStringInfo(&flush_query,
2119-
"INSERT INTO %s (%s) SELECT * FROM %s",
2120-
estate->insert_exec_target_table,
2121-
estate->insert_exec_column_list,
2122-
temp_table_name);
2123-
}
2124-
else
2125-
{
2126-
/*
2127-
* No column list specified - we need to build one excluding
2128-
* IDENTITY and computed columns to match the temp table structure.
2129-
*/
2130-
StringInfoData col_query;
2131-
StringInfoData non_identity_cols;
2132-
bool first_col = true;
2133-
int proc_count;
2134-
uint64 i;
2135-
2136-
initStringInfo(&col_query);
2137-
initStringInfo(&non_identity_cols);
2138-
2139-
appendStringInfo(&col_query,
2140-
"SELECT a.attname "
2141-
"FROM pg_attribute a "
2142-
"JOIN pg_class c ON a.attrelid = c.oid "
2143-
"WHERE c.relname = '%s' "
2144-
"AND a.attnum > 0 "
2145-
"AND NOT a.attisdropped "
2146-
"AND a.attidentity = '' "
2147-
"AND a.attgenerated = '' "
2148-
"ORDER BY a.attnum",
2149-
estate->insert_exec_target_table);
2150-
2151-
rc = SPI_execute(col_query.data, true, 0);
2152-
if (rc != SPI_OK_SELECT)
2153-
{
2154-
pfree(col_query.data);
2155-
pfree(non_identity_cols.data);
2156-
/* Fall back to simple INSERT */
2157-
appendStringInfo(&flush_query,
2158-
"INSERT INTO %s SELECT * FROM %s",
2159-
estate->insert_exec_target_table,
2160-
temp_table_name);
2161-
}
2162-
else
2163-
{
2164-
proc_count = SPI_processed;
2165-
2166-
if (proc_count == 0)
2167-
{
2168-
/* No columns found, fall back */
2169-
pfree(col_query.data);
2170-
pfree(non_identity_cols.data);
2171-
appendStringInfo(&flush_query,
2172-
"INSERT INTO %s SELECT * FROM %s",
2173-
estate->insert_exec_target_table,
2174-
temp_table_name);
2175-
}
2176-
else
2177-
{
2178-
/* Build column list */
2179-
for (i = 0; i < proc_count; i++)
2180-
{
2181-
char *colname = SPI_getvalue(SPI_tuptable->vals[i],
2182-
SPI_tuptable->tupdesc, 1);
2183-
if (colname != NULL)
2184-
{
2185-
if (!first_col)
2186-
appendStringInfoString(&non_identity_cols, ", ");
2187-
appendStringInfoString(&non_identity_cols, colname);
2188-
first_col = false;
2189-
}
2190-
}
2191-
2192-
SPI_freetuptable(SPI_tuptable);
2193-
pfree(col_query.data);
2194-
2195-
appendStringInfo(&flush_query,
2196-
"INSERT INTO %s (%s) SELECT * FROM %s",
2197-
estate->insert_exec_target_table,
2198-
non_identity_cols.data,
2199-
temp_table_name);
2200-
2201-
pfree(non_identity_cols.data);
2202-
}
2203-
}
2204-
}
2205-
2206-
elog(DEBUG1, "INSERT-EXEC: Flushing temp table to target: %s", flush_query.data);
2207-
2208-
rc = SPI_execute(flush_query.data, false, 0);
2209-
if (rc != SPI_OK_INSERT)
2210-
elog(ERROR, "INSERT-EXEC: Failed to flush temp table to target: %s",
2211-
SPI_result_code_string(rc));
2212-
2213-
/* Update rowcount */
2214-
estate->eval_processed = SPI_processed;
2215-
exec_set_rowcount(SPI_processed);
2216-
exec_set_found(estate, SPI_processed > 0);
2217-
2218-
pfree(flush_query.data);
2219-
SPI_freetuptable(SPI_tuptable);
2220-
}
2221-
22222080
/* helper function to get current T-SQL estate */
22232081
PLtsql_execstate *get_current_tsql_estate(void);
22242082
PLtsql_execstate *get_outermost_tsql_estate(int *nestlevel);
@@ -2758,12 +2616,6 @@ exec_stmt_try_catch(PLtsql_execstate *estate, PLtsql_stmt_try_catch *stmt)
27582616

27592617
MemoryContext stmt_mcontext;
27602618

2761-
/*
2762-
* Track TRY-CATCH depth for INSERT EXEC.
2763-
* This is used as a fallback when exec_state_call_stack is NULL.
2764-
*/
2765-
pltsql_insert_exec_enter_trycatch();
2766-
27672619
/*
27682620
* Check if INSERT EXEC is active at the start of the TRY block.
27692621
* If so, we need special handling to preserve INSERT EXEC data
@@ -2897,7 +2749,7 @@ exec_stmt_try_catch(PLtsql_execstate *estate, PLtsql_stmt_try_catch *stmt)
28972749
MemoryContextSwitchTo(oldcontext);
28982750
CurrentResourceOwner = oldowner;
28992751

2900-
elog(LOG, "INSERT-EXEC TRY-CATCH cleanup: checking if active, is_stmt_terminating=%d, insert_exec_was_active=%d",
2752+
elog(DEBUG1, "INSERT-EXEC TRY-CATCH cleanup: checking if active, is_stmt_terminating=%d, insert_exec_was_active=%d",
29012753
is_stmt_terminating, insert_exec_was_active);
29022754

29032755
/*
@@ -2915,7 +2767,7 @@ exec_stmt_try_catch(PLtsql_execstate *estate, PLtsql_stmt_try_catch *stmt)
29152767
{
29162768
Oid temp_oid = pltsql_get_insert_exec_temp_table_oid();
29172769

2918-
elog(LOG, "INSERT-EXEC TRY-CATCH cleanup: is_stmt_terminating=%d, insert_exec_was_active=%d, temp_oid=%u",
2770+
elog(DEBUG1, "INSERT-EXEC TRY-CATCH cleanup: is_stmt_terminating=%d, insert_exec_was_active=%d, temp_oid=%u",
29192771
is_stmt_terminating, insert_exec_was_active, temp_oid);
29202772

29212773
/* Close target table and release lock first */
@@ -2930,17 +2782,17 @@ exec_stmt_try_catch(PLtsql_execstate *estate, PLtsql_stmt_try_catch *stmt)
29302782
*/
29312783
if (is_stmt_terminating && insert_exec_was_active && OidIsValid(temp_oid))
29322784
{
2933-
elog(LOG, "INSERT-EXEC TRY-CATCH cleanup: dropping temp table");
2785+
elog(DEBUG1, "INSERT-EXEC TRY-CATCH cleanup: dropping temp table");
29342786
drop_insert_exec_temp_table(temp_oid);
29352787
}
29362788
}
29372789
else if (pltsql_insert_exec_active())
29382790
{
2939-
elog(LOG, "INSERT-EXEC TRY-CATCH cleanup: INSERT EXEC active but TRY-CATCH is inside procedure, not cleaning up");
2791+
elog(DEBUG1, "INSERT-EXEC TRY-CATCH cleanup: INSERT EXEC active but TRY-CATCH is inside procedure, not cleaning up");
29402792
}
29412793
else
29422794
{
2943-
elog(LOG, "INSERT-EXEC TRY-CATCH cleanup: INSERT EXEC not active");
2795+
elog(DEBUG1, "INSERT-EXEC TRY-CATCH cleanup: INSERT EXEC not active");
29442796
}
29452797

29462798
/*
@@ -2994,11 +2846,6 @@ exec_stmt_try_catch(PLtsql_execstate *estate, PLtsql_stmt_try_catch *stmt)
29942846

29952847
Assert(save_cur_error == estate->cur_error->error);
29962848

2997-
/*
2998-
* Decrement TRY-CATCH depth for INSERT EXEC tracking.
2999-
*/
3000-
pltsql_insert_exec_exit_trycatch();
3001-
30022849
estate->err_text = NULL;
30032850

30042851
/*

contrib/babelfishpg_tsql/src/pltsql.h

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1545,11 +1545,6 @@ typedef struct PLtsql_execstate
15451545
*/
15461546
bool insert_exec;
15471547

1548-
/* INSERT EXEC temp table buffering fields */
1549-
Oid insert_exec_temp_table_oid; /* OID of temp table for buffering */
1550-
char *insert_exec_target_table; /* Final target table name */
1551-
char *insert_exec_column_list; /* Column list for final INSERT (NULL = all) */
1552-
15531548
List *explain_infos;
15541549
instr_time planning_start;
15551550
instr_time planning_end;
@@ -2409,9 +2404,8 @@ extern bool pltsql_insert_exec_flush_in_progress(void);
24092404
extern int pltsql_get_insert_exec_base_tran_count(void);
24102405
extern Oid pltsql_get_insert_exec_temp_table_oid(void);
24112406
extern const char *pltsql_get_insert_exec_target_table(void);
2407+
extern Oid pltsql_get_insert_exec_target_rel_oid(void);
24122408
extern const char *pltsql_get_insert_exec_column_list(void);
2413-
extern void pltsql_insert_exec_enter_trycatch(void);
2414-
extern void pltsql_insert_exec_exit_trycatch(void);
24152409
extern bool pltsql_insert_exec_in_trycatch(void);
24162410
extern bool pltsql_insert_exec_should_cleanup_on_trycatch(void);
24172411
extern Oid pltsql_get_and_clear_insert_exec_temp_table_for_cleanup(void);
@@ -2426,7 +2420,6 @@ extern bool pltsql_insert_exec_verify_schema(void);
24262420
extern DestReceiver *CreateInsertExecDestReceiver(Oid temp_table_oid);
24272421
extern Oid create_insert_exec_temp_table(const char *target_table, const char *column_list);
24282422
extern void drop_insert_exec_temp_table(Oid temp_table_oid);
2429-
extern void flush_temp_table_to_target(PLtsql_execstate *estate);
24302423
extern void flush_insert_exec_temp_table(PLtsql_execstate *estate);
24312424

24322425
#define NUM_DB_OBJECTS 11

0 commit comments

Comments
 (0)