Skip to content
Draft
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
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,9 @@ contrib/babelfishpg_tsql/src/pl_gram.c
contrib/babelfishpg_tsql/src/pl_gram.h
contrib/babelfishpg_tsql/src/pl_gram.output

# PLtsql serialization - auto-generated by gen_pltsql_node_support.pl
contrib/babelfishpg_tsql/src/pltsql_serialize/pltsql_nodetags.h
contrib/babelfishpg_tsql/src/pltsql_serialize/pltsql_outfuncs_gen.c
contrib/babelfishpg_tsql/src/pltsql_serialize/pltsql_outfuncs_switch.c
contrib/babelfishpg_tsql/src/pltsql_serialize/pltsql_readfuncs_gen.c
contrib/babelfishpg_tsql/src/pltsql_serialize/pltsql_readfuncs_switch.c
23 changes: 23 additions & 0 deletions contrib/babelfishpg_tsql/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,29 @@ export ANTLR4_RUNTIME_INCLUDE_DIR=/usr/local/include/antlr4-runtime
export ANTLR4_RUNTIME_LIB_DIR=/usr/local/lib

OBJS += src/pltsql_bulkcopy.o
OBJS += src/pltsql_serialize/pltsql_node_stubs.o

# PLtsql serialization code generation (babelfishpg_tsql.enable_routine_parse_cache)
PLTSQL_SER_DIR = src/pltsql_serialize
PLTSQL_SER_HEADERS = $(PLTSQL_SER_DIR)/pltsql_serializable_1.h $(PLTSQL_SER_DIR)/pltsql_serializable_2.h
PLTSQL_GEN_SCRIPT = $(PLTSQL_SER_DIR)/gen_pltsql_node_support.pl

$(PLTSQL_SER_DIR)/pltsql_nodetags.h $(PLTSQL_SER_DIR)/pltsql_outfuncs_gen.c $(PLTSQL_SER_DIR)/pltsql_readfuncs_gen.c $(PLTSQL_SER_DIR)/pltsql_outfuncs_switch.c $(PLTSQL_SER_DIR)/pltsql_readfuncs_switch.c: $(PLTSQL_SER_HEADERS) $(PLTSQL_GEN_SCRIPT)
$(PERL) $(PLTSQL_GEN_SCRIPT) --outdir $(PLTSQL_SER_DIR) $(PLTSQL_SER_HEADERS)

# Wrapper .c files #include the generated .c files (mirroring engine pattern)
# so we compile the wrappers, not the gen files directly.
OBJS += $(PLTSQL_SER_DIR)/pltsql_outfuncs.o
OBJS += $(PLTSQL_SER_DIR)/pltsql_readfuncs.o

# pltsql_nodetags.h must be generated before any .o that includes pltsql.h
# The first OBJS entry (src/pl_gram.o) triggers this via implicit ordering,
# but we make it explicit for safety.
src/pl_gram.o: $(PLTSQL_SER_DIR)/pltsql_nodetags.h

# Wrapper .o depends on generated .c files (included via #include)
$(PLTSQL_SER_DIR)/pltsql_outfuncs.o: $(PLTSQL_SER_DIR)/pltsql_outfuncs_gen.c $(PLTSQL_SER_DIR)/pltsql_outfuncs_switch.c
$(PLTSQL_SER_DIR)/pltsql_readfuncs.o: $(PLTSQL_SER_DIR)/pltsql_readfuncs_gen.c $(PLTSQL_SER_DIR)/pltsql_readfuncs_switch.c

PG_CXXFLAGS += -g -Werror -Wfloat-conversion
PG_CXXFLAGS += -Wno-deprecated -Wno-error=attributes -Wno-suggest-attribute=format # disable some warnings from ANTLR runtime header
Expand Down
5 changes: 5 additions & 0 deletions contrib/babelfishpg_tsql/sql/ownership.sql
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ CREATE TABLE sys.babelfish_function_ext (
create_date SYS.DATETIME NOT NULL,
modify_date SYS.DATETIME NOT NULL,
definition sys.NTEXT DEFAULT NULL,
antlr_parse_tree_text TEXT DEFAULT NULL, -- Native PG nodeToString() serialized parse tree
antlr_parse_tree_datums TEXT DEFAULT NULL, -- Native PG nodeToString() serialized datums array
antlr_parse_tree_modify_date SYS.DATETIME DEFAULT NULL,
antlr_parse_tree_bbf_version TEXT DEFAULT NULL,
antlr_cache_enabled BOOL DEFAULT false,
PRIMARY KEY(funcname, nspname, funcsignature)
);
GRANT SELECT ON sys.babelfish_function_ext TO PUBLIC;
Expand Down
7 changes: 7 additions & 0 deletions contrib/babelfishpg_tsql/sql/sys_functions.sql
Original file line number Diff line number Diff line change
Expand Up @@ -5312,3 +5312,10 @@ RETURNS table (
AS 'babelfishpg_tsql', 'openxml_simple'
LANGUAGE C IMMUTABLE;


-- Function-specific ANTLR parse tree cache GUC control
CREATE OR REPLACE FUNCTION sys.enable_routine_parse_cache(
IN func_identifier TEXT,
IN enable_flag BOOLEAN
) RETURNS BOOLEAN
AS 'babelfishpg_tsql', 'enable_routine_parse_cache' LANGUAGE C;
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,21 @@ $$
end;
$$;

-- BABELFISH_FUNCTION_EXT
SET allow_system_table_mods = on;
ALTER TABLE sys.babelfish_function_ext ADD COLUMN IF NOT EXISTS antlr_parse_tree_text TEXT DEFAULT NULL;
ALTER TABLE sys.babelfish_function_ext ADD COLUMN IF NOT EXISTS antlr_parse_tree_datums TEXT DEFAULT NULL;
ALTER TABLE sys.babelfish_function_ext ADD COLUMN IF NOT EXISTS antlr_parse_tree_modify_date SYS.DATETIME DEFAULT NULL;
ALTER TABLE sys.babelfish_function_ext ADD COLUMN IF NOT EXISTS antlr_parse_tree_bbf_version TEXT DEFAULT NULL;
ALTER TABLE sys.babelfish_function_ext ADD COLUMN IF NOT EXISTS antlr_cache_enabled BOOL DEFAULT false;
RESET allow_system_table_mods;

CREATE OR REPLACE FUNCTION sys.enable_routine_parse_cache(
IN func_identifier TEXT,
IN enable_flag BOOLEAN
) RETURNS BOOLEAN
AS 'babelfishpg_tsql', 'enable_routine_parse_cache' LANGUAGE C;

-- Please add your SQLs here

-- Deprecate and drop old aggregates first (they depend on the function)
Expand Down
189 changes: 188 additions & 1 deletion contrib/babelfishpg_tsql/src/catalog.c
Original file line number Diff line number Diff line change
Expand Up @@ -3655,6 +3655,18 @@ rename_procfunc_update_bbf_catalog(RenameStmt *stmt)
new_record_repl_func_ext[Anum_bbf_function_ext_orig_name - 1] = true;
}

/* Invalidate cached parse tree — procedure name is embedded in the parse tree namespace stack */
/* Alternatively, if guc enabled, explore if worth looking up session cache PLtsql_HashTable for
* updated parse tree result and serialize and re-populate babelfish_function_ext's antlr_parse_tree column */
new_record_nulls_func_ext[Anum_bbf_function_ext_antlr_parse_tree_text - 1] = true;
new_record_repl_func_ext[Anum_bbf_function_ext_antlr_parse_tree_text - 1] = true;
new_record_nulls_func_ext[Anum_bbf_function_ext_antlr_parse_tree_datums - 1] = true;
new_record_repl_func_ext[Anum_bbf_function_ext_antlr_parse_tree_datums - 1] = true;
new_record_nulls_func_ext[Anum_bbf_function_ext_antlr_parse_tree_modify_date - 1] = true;
new_record_repl_func_ext[Anum_bbf_function_ext_antlr_parse_tree_modify_date - 1] = true;
new_record_nulls_func_ext[Anum_bbf_function_ext_antlr_parse_tree_bbf_version - 1] = true;
new_record_repl_func_ext[Anum_bbf_function_ext_antlr_parse_tree_bbf_version - 1] = true;

new_tuple = heap_modify_tuple(usertuple,
bbf_func_ext_dsc,
new_record_func_ext,
Expand Down Expand Up @@ -6490,4 +6502,179 @@ bbf_check_member_has_direct_priv_to_grant_role(Oid member, Oid role)

ReleaseSysCacheList(memlist);
return false;
}
}

/*
* Helper: update antlr_cache_enabled flag and optionally clear cache columns
* in babelfish_function_ext for a given bbf function tuple.
*/
static void
update_bbf_function_cache_enabled(HeapTuple bbffunctuple, bool enable_flag)
{
Relation rel;
TupleDesc dsc;
HeapTuple newtup;
Datum new_record[BBF_FUNCTION_EXT_NUM_COLS];
bool new_record_nulls[BBF_FUNCTION_EXT_NUM_COLS];
bool new_record_replaces[BBF_FUNCTION_EXT_NUM_COLS];

rel = table_open(get_bbf_function_ext_oid(), RowExclusiveLock);
dsc = RelationGetDescr(rel);

MemSet(new_record, 0, sizeof(new_record));
MemSet(new_record_nulls, false, sizeof(new_record_nulls));
MemSet(new_record_replaces, false, sizeof(new_record_replaces));

/* Set antlr_cache_enabled */
new_record[Anum_bbf_function_ext_antlr_cache_enabled - 1] = BoolGetDatum(enable_flag);
new_record_replaces[Anum_bbf_function_ext_antlr_cache_enabled - 1] = true;

/* If disabling, NULL out the 4 cache columns for immediate invalidation */
if (!enable_flag)
{
new_record_nulls[Anum_bbf_function_ext_antlr_parse_tree_text - 1] = true;
new_record_replaces[Anum_bbf_function_ext_antlr_parse_tree_text - 1] = true;
new_record_nulls[Anum_bbf_function_ext_antlr_parse_tree_datums - 1] = true;
new_record_replaces[Anum_bbf_function_ext_antlr_parse_tree_datums - 1] = true;
new_record_nulls[Anum_bbf_function_ext_antlr_parse_tree_modify_date - 1] = true;
new_record_replaces[Anum_bbf_function_ext_antlr_parse_tree_modify_date - 1] = true;
new_record_nulls[Anum_bbf_function_ext_antlr_parse_tree_bbf_version - 1] = true;
new_record_replaces[Anum_bbf_function_ext_antlr_parse_tree_bbf_version - 1] = true;
}

newtup = heap_modify_tuple(bbffunctuple, dsc,
new_record, new_record_nulls, new_record_replaces);
CatalogTupleUpdate(rel, &newtup->t_self, newtup);

heap_freetuple(newtup);
table_close(rel, RowExclusiveLock);
}

/*
* enable_routine_parse_cache
*
* SQL-callable: sys.enable_routine_parse_cache(func_identifier TEXT, enable_flag BOOLEAN)
*
* Enables or disables ANTLR parse result caching for a specific function.
*
* func_identifier formats:
* 'schema.funcname' — unique function (no overloads)
* 'funcname' — defaults to dbo schema
* 'schema.funcname(argtypes)' — disambiguate overloads, e.g. 'dbo.myProc("sys"."varchar")'
*
* Uses PROCNAMENSPSIGNATURE syscache (funcname, nspname, funcsignature).
* When no arg types given, uses 2-key list lookup; errors if ambiguous.
*/
PG_FUNCTION_INFO_V1(enable_routine_parse_cache);
Datum
enable_routine_parse_cache(PG_FUNCTION_ARGS)
{
text *func_id_text = PG_GETARG_TEXT_PP(0);
bool enable_flag = PG_GETARG_BOOL(1);
char *func_id = text_to_cstring(func_id_text);
char *dot;
char *schema_name;
char *func_part;
char *funcname_str;
char *paren;
NameData nsp_name;
NameData funcname_data;

/* Split schema from func_part on first dot */
dot = strchr(func_id, '.');
if (dot != NULL)
{
*dot = '\0';
schema_name = func_id;
func_part = dot + 1;
}
else
{
schema_name = "dbo";
func_part = func_id;
}

/* Extract bare funcname (everything before '(' if present) */
funcname_str = pstrdup(func_part);
paren = strchr(funcname_str, '(');
if (paren != NULL)
*paren = '\0';

/* Convert logical schema name (e.g. 'dbo') to physical (e.g. 'master_dbo') */
{
char *cur_db = get_cur_db_name();
char *physical_schema = get_physical_schema_name(cur_db, schema_name);

namestrcpy(&nsp_name, physical_schema);
pfree(cur_db);
pfree(physical_schema);
}
namestrcpy(&funcname_data, funcname_str);

if (strchr(func_part, '(') != NULL)
{
/* Full signature provided — exact 3-key lookup */
HeapTuple bbffunctuple;

bbffunctuple = SearchSysCache3(PROCNAMENSPSIGNATURE,
NameGetDatum(&funcname_data),
NameGetDatum(&nsp_name),
CStringGetTextDatum(func_part));

if (!HeapTupleIsValid(bbffunctuple))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("function \"%s\" not found in schema \"%s\"",
func_part, schema_name),
errhint("Use sys.babelfish_get_pltsql_function_signature(oid) to find the exact signature.")));

{
HeapTuple copytup = heap_copytuple(bbffunctuple);

ReleaseSysCache(bbffunctuple);
update_bbf_function_cache_enabled(copytup, enable_flag);
heap_freetuple(copytup);
}
}
else
{
/* No arg types — 2-key list lookup */
CatCList *catlist;

catlist = SearchSysCacheList2(PROCNAMENSPSIGNATURE,
NameGetDatum(&funcname_data),
NameGetDatum(&nsp_name));

if (catlist->n_members == 0)
{
ReleaseSysCacheList(catlist);
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("function \"%s\" not found in schema \"%s\"",
funcname_str, schema_name)));
}
else if (catlist->n_members > 1)
{
ReleaseSysCacheList(catlist);
ereport(ERROR,
(errcode(ERRCODE_AMBIGUOUS_FUNCTION),
errmsg("multiple overloads of \"%s\" exist in schema \"%s\"",
funcname_str, schema_name),
errhint("Specify the full signature, e.g. 'dbo.%s(integer)'. "
"Use sys.babelfish_get_pltsql_function_signature(oid) to find the exact signature.",
funcname_str)));
}
else
{
HeapTuple copytup = heap_copytuple(&catlist->members[0]->tuple);

ReleaseSysCacheList(catlist);
update_bbf_function_cache_enabled(copytup, enable_flag);
heap_freetuple(copytup);
}
}

pfree(funcname_str);
pfree(func_id);
PG_RETURN_BOOL(enable_flag);
}
7 changes: 6 additions & 1 deletion contrib/babelfishpg_tsql/src/catalog.h
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,12 @@ typedef FormData_bbf_servers_def *Form_bbf_servers_def;
#define Anum_bbf_function_ext_create_date 8
#define Anum_bbf_function_ext_modify_date 9
#define Anum_bbf_function_ext_definition 10
#define BBF_FUNCTION_EXT_NUM_COLS 10
#define Anum_bbf_function_ext_antlr_parse_tree_text 11
#define Anum_bbf_function_ext_antlr_parse_tree_datums 12
#define Anum_bbf_function_ext_antlr_parse_tree_modify_date 13
#define Anum_bbf_function_ext_antlr_parse_tree_bbf_version 14
#define Anum_bbf_function_ext_antlr_cache_enabled 15
#define BBF_FUNCTION_EXT_NUM_COLS 15
#define FLAG_IS_ANSI_NULLS_ON (1<<0)
#define FLAG_USES_QUOTED_IDENTIFIER (1<<1)
#define FLAG_CREATED_WITH_RECOMPILE (1<<2)
Expand Down
8 changes: 4 additions & 4 deletions contrib/babelfishpg_tsql/src/codegen.c
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ create_goto(int lineno)
{
PLtsql_stmt_goto *stmt_goto;

stmt_goto = palloc(sizeof(PLtsql_stmt_goto));
stmt_goto = makeNode(PLtsql_stmt_goto);
stmt_goto->cmd_type = PLTSQL_STMT_GOTO;
stmt_goto->lineno = lineno;
stmt_goto->cond = NULL; /* unconditional goto */
Expand All @@ -159,7 +159,7 @@ create_goto(int lineno)
static PLtsql_stmt_save_ctx *
create_save_ctx(int lineno)
{
PLtsql_stmt_save_ctx *save_ctx = palloc(sizeof(PLtsql_stmt_save_ctx));
PLtsql_stmt_save_ctx *save_ctx = makeNode(PLtsql_stmt_save_ctx);

save_ctx->cmd_type = PLTSQL_STMT_SAVE_CTX;
save_ctx->lineno = lineno;
Expand All @@ -171,7 +171,7 @@ create_save_ctx(int lineno)
static PLtsql_stmt_restore_ctx_full *
create_restore_ctx_full(int lineno)
{
PLtsql_stmt_restore_ctx_full *restore_ctx = palloc(sizeof(PLtsql_stmt_restore_ctx_full));
PLtsql_stmt_restore_ctx_full *restore_ctx = makeNode(PLtsql_stmt_restore_ctx_full);

restore_ctx->cmd_type = PLTSQL_STMT_RESTORE_CTX_FULL;
restore_ctx->lineno = lineno;
Expand All @@ -181,7 +181,7 @@ create_restore_ctx_full(int lineno)
static PLtsql_stmt_restore_ctx_partial *
create_restore_ctx_partial(int lineno)
{
PLtsql_stmt_restore_ctx_partial *restore_ctx = palloc(sizeof(PLtsql_stmt_restore_ctx_partial));
PLtsql_stmt_restore_ctx_partial *restore_ctx = makeNode(PLtsql_stmt_restore_ctx_partial);

restore_ctx->cmd_type = PLTSQL_STMT_RESTORE_CTX_PARTIAL;
restore_ctx->lineno = lineno;
Expand Down
13 changes: 13 additions & 0 deletions contrib/babelfishpg_tsql/src/guc.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ char *pltsql_host_service_pack_level = NULL;

bool pltsql_enable_create_alter_view_from_pg = false;
bool pltsql_enable_alter_owner_from_pg = false;
bool pltsql_enable_routine_parse_cache = false;

static const struct config_enum_entry explain_format_options[] = {
{"text", EXPLAIN_FORMAT_TEXT, false},
Expand Down Expand Up @@ -1140,6 +1141,18 @@ define_custom_variables(void)
GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE,
NULL, NULL, NULL);

/*
* Enable/disable procedure ANTLR parse result caching for cross-session (sys.babelfish_function_ext->antlr_parse_tree) performance optimization.
*/
DefineCustomBoolVariable("babelfishpg_tsql.enable_routine_parse_cache",
gettext_noop("Enables caching of ANTLR parse results for stored procedures across sessions"),
NULL,
&pltsql_enable_routine_parse_cache,
false,
PGC_USERSET,
GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE,
NULL, NULL, NULL);

/* Dump and Restore */
DefineCustomBoolVariable("babelfishpg_tsql.dump_restore",
gettext_noop("Enable special handlings during dump and restore"),
Expand Down
1 change: 1 addition & 0 deletions contrib/babelfishpg_tsql/src/guc.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ typedef enum IsolationOptions
extern bool pltsql_fmtonly;
extern bool pltsql_enable_create_alter_view_from_pg;
extern bool pltsql_enable_alter_owner_from_pg;
extern bool pltsql_enable_routine_parse_cache;
extern bool pltsql_enable_linked_servers;
extern bool pltsql_enable_ownership_chaining;
extern bool pltsql_allow_windows_login;
Expand Down
Loading
Loading