|
101 | 101 | #include "bbf_parallel_query.h" |
102 | 102 | #include "extendedproperty.h" |
103 | 103 | #include "utils/xml.h" |
| 104 | +#include "pltsql_serialize_jsonb.h" |
104 | 105 |
|
105 | 106 | #ifdef USE_LIBXML |
106 | 107 | #include <libxml/tree.h> |
@@ -4102,6 +4103,86 @@ pltsql_store_func_default_positions(ObjectAddress address, List *parameters, con |
4102 | 4103 | new_record_nulls[Anum_bbf_function_ext_definition - 1] = true; |
4103 | 4104 | new_record_replaces[Anum_bbf_function_ext_default_positions - 1] = true; |
4104 | 4105 |
|
| 4106 | + /* |
| 4107 | + * Store serialized ANTLR parse result for cross-session caching. |
| 4108 | + * Look up the compiled function and serialize its parse tree. |
| 4109 | + */ |
| 4110 | + { |
| 4111 | + PLtsql_func_hashkey hashkey; |
| 4112 | + PLtsql_function *function = NULL; |
| 4113 | + char *serialized_parse_tree = NULL; |
| 4114 | + PLtsql_serial_status status; |
| 4115 | + |
| 4116 | + /* [TODO]: complete hashkey logic |
| 4117 | + * Build a hashkey to look up the function in the hash table. |
| 4118 | + * Note: This uses a simplified hashkey that may not match all |
| 4119 | + * function overloads perfectly (e.g., default parameter values). |
| 4120 | + * This is acceptable since we're just trying to find the compiled |
| 4121 | + * function to serialize its parse tree. |
| 4122 | + */ |
| 4123 | + MemSet(&hashkey, 0, sizeof(PLtsql_func_hashkey)); |
| 4124 | + hashkey.funcOid = address.objectId; |
| 4125 | + hashkey.isTrigger = false; |
| 4126 | + hashkey.isEventTrigger = false; |
| 4127 | + hashkey.trigOid = 0; |
| 4128 | + hashkey.inputCollation = 0; |
| 4129 | + |
| 4130 | + if (form_proctup->pronargs > 0) |
| 4131 | + { |
| 4132 | + /* Copy argument types from proc tuple */ |
| 4133 | + memcpy(hashkey.argtypes, form_proctup->proargtypes.values, |
| 4134 | + form_proctup->pronargs * sizeof(Oid)); |
| 4135 | + } |
| 4136 | + |
| 4137 | + /* Look up the compiled function in the hash table */ |
| 4138 | + function = pltsql_HashTableLookup(&hashkey); |
| 4139 | + |
| 4140 | + if (function != NULL && function->action != NULL) |
| 4141 | + { |
| 4142 | + //[TODO] Save engine version in additional column |
| 4143 | + /* Serialize the parse tree to JSON string */ |
| 4144 | + serialized_parse_tree = pltsql_serialize_stmt_block_jsonb(function->action, &status); |
| 4145 | + |
| 4146 | + if (status == PLTSQL_SERIAL_SUPPORTED && serialized_parse_tree != NULL) |
| 4147 | + { |
| 4148 | + /* Convert JSON string to JSONB datum and store directly */ |
| 4149 | + new_record[Anum_bbf_function_ext_antlr_parse_tree - 1] = DirectFunctionCall1(jsonb_in, |
| 4150 | + CStringGetDatum(serialized_parse_tree)); |
| 4151 | + new_record_nulls[Anum_bbf_function_ext_antlr_parse_tree - 1] = false; |
| 4152 | + new_record_replaces[Anum_bbf_function_ext_antlr_parse_tree - 1] = true; |
| 4153 | + |
| 4154 | + elog(DEBUG1, "Stored cached parse result for function %u (%zu bytes JSON)", |
| 4155 | + address.objectId, strlen(serialized_parse_tree)); |
| 4156 | + } |
| 4157 | + else |
| 4158 | + { |
| 4159 | + /* Serialization failed or unsupported - skip caching */ |
| 4160 | + if (status == PLTSQL_SERIAL_UNSUPPORTED) |
| 4161 | + { |
| 4162 | + elog(DEBUG1, "Parse result caching skipped for function %u: contains unsupported node types", |
| 4163 | + address.objectId); |
| 4164 | + } |
| 4165 | + else if (status == PLTSQL_SERIAL_ERROR) |
| 4166 | + { |
| 4167 | + elog(DEBUG1, "Failed to serialize parse result for function %u", |
| 4168 | + address.objectId); |
| 4169 | + } |
| 4170 | + /* Set to NULL */ |
| 4171 | + new_record_nulls[Anum_bbf_function_ext_antlr_parse_tree - 1] = true; |
| 4172 | + new_record_replaces[Anum_bbf_function_ext_antlr_parse_tree - 1] = true; |
| 4173 | + } |
| 4174 | + |
| 4175 | + if (serialized_parse_tree) |
| 4176 | + pfree(serialized_parse_tree); |
| 4177 | + } |
| 4178 | + else |
| 4179 | + { |
| 4180 | + /* Function not found in hash table or no action - set to NULL */ |
| 4181 | + new_record_nulls[Anum_bbf_function_ext_antlr_parse_tree - 1] = true; |
| 4182 | + new_record_replaces[Anum_bbf_function_ext_antlr_parse_tree - 1] = true; |
| 4183 | + } |
| 4184 | + } |
| 4185 | + |
4105 | 4186 | oldtup = get_bbf_function_tuple_from_proctuple(proctup); |
4106 | 4187 |
|
4107 | 4188 | if (HeapTupleIsValid(oldtup)) |
@@ -4139,6 +4220,81 @@ pltsql_store_func_default_positions(ObjectAddress address, List *parameters, con |
4139 | 4220 | table_close(bbf_function_ext_rel, RowExclusiveLock); |
4140 | 4221 | } |
4141 | 4222 |
|
| 4223 | +/* |
| 4224 | + * pltsql_restore_func_parse_result |
| 4225 | + * Attempt to restore a cached parse result from babelfish_function_ext |
| 4226 | + * |
| 4227 | + * Retrieves a previously serialized ANTLR parse tree from the catalog and |
| 4228 | + * deserializes it back into a PLtsql_stmt_block structure. This allows |
| 4229 | + * procedures to skip ANTLR parsing on subsequent executions in new sessions. |
| 4230 | + * |
| 4231 | + * Parameters: |
| 4232 | + * proctup - HeapTuple from pg_proc for the function |
| 4233 | + * |
| 4234 | + * Returns: |
| 4235 | + * PLtsql_stmt_block * - Deserialized parse tree if cache hit |
| 4236 | + * NULL - If no cache entry exists, deserialization fails, or during restore |
| 4237 | + */ |
| 4238 | +PLtsql_stmt_block * |
| 4239 | +pltsql_restore_func_parse_result(HeapTuple proctup) |
| 4240 | +{ |
| 4241 | + HeapTuple bbffunctuple; |
| 4242 | + Datum cached_parse_tree_datum; |
| 4243 | + PLtsql_stmt_block *deserialized; |
| 4244 | + PLtsql_serial_status status; |
| 4245 | + bool isnull; |
| 4246 | + Jsonb *jsonb_data; |
| 4247 | + |
| 4248 | + /* Disallow during restore */ |
| 4249 | + if (babelfish_dump_restore) |
| 4250 | + return NULL; |
| 4251 | + |
| 4252 | + /* 1. Get babelfish_function_ext tuple using existing helper */ |
| 4253 | + bbffunctuple = get_bbf_function_tuple_from_proctuple(proctup); |
| 4254 | + |
| 4255 | + if (!HeapTupleIsValid(bbffunctuple)) |
| 4256 | + { |
| 4257 | + elog(DEBUG1, "pltsql_restore_func_parse_result: No babelfish_function_ext entry found"); |
| 4258 | + return NULL; |
| 4259 | + } |
| 4260 | + |
| 4261 | + /* 2. Fetch cached_parse_tree column (JSONB type) */ |
| 4262 | + cached_parse_tree_datum = SysCacheGetAttr( |
| 4263 | + PROCNAMENSPSIGNATURE, |
| 4264 | + bbffunctuple, |
| 4265 | + Anum_bbf_function_ext_antlr_parse_tree, |
| 4266 | + &isnull |
| 4267 | + ); |
| 4268 | + |
| 4269 | + |
| 4270 | + if (isnull) |
| 4271 | + { |
| 4272 | + elog(DEBUG1, "pltsql_restore_func_parse_result: No cached parse result in catalog"); |
| 4273 | + return NULL; |
| 4274 | + } |
| 4275 | + |
| 4276 | + /* 3. Get Jsonb pointer directly - detoasts automatically */ |
| 4277 | + jsonb_data = DatumGetJsonbP(cached_parse_tree_datum); |
| 4278 | + |
| 4279 | + elog(DEBUG1, "pltsql_restore_func_parse_result: Found cached parse result"); |
| 4280 | + |
| 4281 | + /* 4. Deserialize directly from Jsonb - efficient, no string conversion */ |
| 4282 | + deserialized = pltsql_deserialize_stmt_block_from_jsonb(jsonb_data, &status); |
| 4283 | + |
| 4284 | + if (status != PLTSQL_SERIAL_SUPPORTED) |
| 4285 | + { |
| 4286 | + elog(DEBUG1, "pltsql_restore_func_parse_result: Deserialization failed with status %d", status); |
| 4287 | + return NULL; |
| 4288 | + } |
| 4289 | + |
| 4290 | + elog(DEBUG1, "pltsql_restore_func_parse_result: Deserialization succeeded (cmd_type=%d, lineno=%d)", |
| 4291 | + deserialized->cmd_type, deserialized->lineno); |
| 4292 | + |
| 4293 | + /* Return deserialized result */ |
| 4294 | + heap_freetuple(bbffunctuple); |
| 4295 | + return deserialized; |
| 4296 | +} |
| 4297 | + |
4142 | 4298 | /* |
4143 | 4299 | * Update 'function_args' in 'sys.babelfish_schema_permissions' |
4144 | 4300 | */ |
|
0 commit comments