feat!: to the moon
This commit is contained in:
@@ -318,14 +318,13 @@
|
|||||||
"host sameuser all ::1/128 scram-sha-256"
|
"host sameuser all ::1/128 scram-sha-256"
|
||||||
];
|
];
|
||||||
initialScript = pkgs.writeText "init-sql-script" ''
|
initialScript = pkgs.writeText "init-sql-script" ''
|
||||||
|
SET log_min_messages TO DEBUG1;
|
||||||
|
ALTER DATABASE postgres SET log_min_messages TO DEBUG1;
|
||||||
CREATE EXTENSION "hemar";
|
CREATE EXTENSION "hemar";
|
||||||
|
|
||||||
-- SELECT hemar.parse('{% zalupa %}');
|
-- SELECT hemar.parse('{% zalupa %}');
|
||||||
-- SELECT hemar.parse('{% zalupa %}');
|
SELECT hemar.render('{"a": "b"}'::JSONB, 'a {% a %}');
|
||||||
-- SELECT hemar.parse('zalupa {% her %} davalka')::JSON;
|
SELECT hemar.render('{"a": ["b", "c"]}'::JSONB, 'a {% for i in a do text %}');
|
||||||
-- SELECT hemar.parse('zalupa {% her %} davalka')::JSON;
|
|
||||||
-- SELECT hemar.parse('zalupa {% her %} davalka')::JSON;
|
|
||||||
-- SELECT hemar.parse('zalupa {% her %} davalka')::JSON;
|
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -38,16 +38,25 @@ static bool is_jsonb_container_valid(JsonbContainer *container);
|
|||||||
static bool
|
static bool
|
||||||
is_jsonb_container_valid(JsonbContainer *container)
|
is_jsonb_container_valid(JsonbContainer *container)
|
||||||
{
|
{
|
||||||
/* Basic sanity check: non-NULL pointer */
|
PG_TRY();
|
||||||
|
{
|
||||||
|
container->header;
|
||||||
|
container->children;
|
||||||
|
}
|
||||||
|
PG_CATCH();
|
||||||
|
{
|
||||||
|
elog(ERROR, "Invalid JSONB container");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
PG_END_TRY();
|
||||||
|
|
||||||
if (container == NULL)
|
if (container == NULL)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* Check that container has a valid header size (at least 4 bytes) */
|
|
||||||
uint32 header = *(uint32 *)container;
|
uint32 header = *(uint32 *)container;
|
||||||
if (header == 0) /* Simplistic check for corrupted/empty header */
|
if (header == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* This is a simplified check. In a real implementation, we'd do more validation. */
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -826,7 +835,6 @@ template_render(MemoryContext context, TemplateNode *node, Datum jsonb_context,
|
|||||||
case TEMPLATE_NODE_SECTION:
|
case TEMPLATE_NODE_SECTION:
|
||||||
case TEMPLATE_NODE_EXECUTE:
|
case TEMPLATE_NODE_EXECUTE:
|
||||||
case TEMPLATE_NODE_INCLUDE:
|
case TEMPLATE_NODE_INCLUDE:
|
||||||
/* Use nested PG_TRY/PG_CATCH blocks for each node type for better error handling */
|
|
||||||
PG_TRY();
|
PG_TRY();
|
||||||
{
|
{
|
||||||
if (current->type == TEMPLATE_NODE_INTERPOLATE)
|
if (current->type == TEMPLATE_NODE_INTERPOLATE)
|
||||||
@@ -1256,7 +1264,6 @@ get_jsonb_path_value(Datum jsonb_context, const char *path, bool *found)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Use PG_TRY/PG_CATCH to handle any errors during extraction */
|
|
||||||
PG_TRY();
|
PG_TRY();
|
||||||
{
|
{
|
||||||
/* Handle simple top-level key */
|
/* Handle simple top-level key */
|
||||||
@@ -1339,7 +1346,6 @@ get_jsonb_path_value(Datum jsonb_context, const char *path, bool *found)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Handle nested paths using a JSON path expression */
|
/* Handle nested paths using a JSON path expression */
|
||||||
/* This is a simplified implementation */
|
|
||||||
elog(DEBUG1, "Complex path not fully supported: %s", path);
|
elog(DEBUG1, "Complex path not fully supported: %s", path);
|
||||||
result = pstrdup("[Complex Path]");
|
result = pstrdup("[Complex Path]");
|
||||||
*found = true;
|
*found = true;
|
||||||
@@ -1403,7 +1409,7 @@ get_jsonb_array(Datum jsonb_context, const char *path, bool *found)
|
|||||||
|
|
||||||
if (jbv_result)
|
if (jbv_result)
|
||||||
{
|
{
|
||||||
elog(DEBUG1, "Found value for key %s (type=%d)", path, jbv_result->type);
|
elog(DEBUG1, "Found value for key %s (type=%d) value=%s", path, jbv_result->type, jbv_result->val.string.val);
|
||||||
|
|
||||||
if (jbv_result->type == jbvBinary)
|
if (jbv_result->type == jbvBinary)
|
||||||
{
|
{
|
||||||
@@ -1411,12 +1417,13 @@ get_jsonb_array(Datum jsonb_context, const char *path, bool *found)
|
|||||||
elog(DEBUG1, "Binary value found, trying to examine structure");
|
elog(DEBUG1, "Binary value found, trying to examine structure");
|
||||||
|
|
||||||
/* Validate the binary container before iterating */
|
/* Validate the binary container before iterating */
|
||||||
if (!is_jsonb_container_valid((JsonbContainer *)&jbv_result->val.binary))
|
if (!is_jsonb_container_valid(jbv_result->val.binary.data))
|
||||||
{
|
{
|
||||||
elog(WARNING, "Invalid binary JSONB container for key: %s", path);
|
elog(WARNING, "Invalid binary JSONB container for key: %s", path);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
elog(DEBUG1, "Trying to initialize the iterator...");
|
||||||
/* Try to initialize the iterator */
|
/* Try to initialize the iterator */
|
||||||
PG_TRY();
|
PG_TRY();
|
||||||
{
|
{
|
||||||
@@ -1429,7 +1436,7 @@ get_jsonb_array(Datum jsonb_context, const char *path, bool *found)
|
|||||||
|
|
||||||
/* Initialize the iterator with careful error handling */
|
/* Initialize the iterator with careful error handling */
|
||||||
elog(DEBUG1, "Initializing iterator for binary container");
|
elog(DEBUG1, "Initializing iterator for binary container");
|
||||||
it = JsonbIteratorInit((JsonbContainer *)&jbv_result->val.binary);
|
it = JsonbIteratorInit(jbv_result->val.binary.data);
|
||||||
elog(DEBUG1, "Iterator initialized successfully");
|
elog(DEBUG1, "Iterator initialized successfully");
|
||||||
|
|
||||||
elog(DEBUG1, "Getting first token");
|
elog(DEBUG1, "Getting first token");
|
||||||
@@ -1484,111 +1491,10 @@ get_jsonb_array(Datum jsonb_context, const char *path, bool *found)
|
|||||||
}
|
}
|
||||||
PG_END_TRY();
|
PG_END_TRY();
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
elog(DEBUG1, "Complex path not fully supported: %s", path);
|
||||||
/* Handle nested paths */
|
result = pstrdup("[Complex Path]");
|
||||||
/* This is a simplified implementation */
|
*found = true;
|
||||||
char *current_path = pstrdup(path);
|
|
||||||
char *token_str;
|
|
||||||
char *saveptr;
|
|
||||||
JsonbValue *current_jbv;
|
|
||||||
|
|
||||||
/* Use PG_TRY/PG_CATCH to handle any errors during iteration */
|
|
||||||
PG_TRY();
|
|
||||||
{
|
|
||||||
token_str = strtok_r(current_path, ".", &saveptr);
|
|
||||||
while (token_str != NULL)
|
|
||||||
{
|
|
||||||
key.type = jbvString;
|
|
||||||
key.val.string.val = token_str;
|
|
||||||
key.val.string.len = strlen(token_str);
|
|
||||||
|
|
||||||
current_jbv = findJsonbValueFromContainer(&jb->root, JB_FOBJECT, &key);
|
|
||||||
|
|
||||||
if (!current_jbv)
|
|
||||||
{
|
|
||||||
elog(DEBUG1, "Path segment %s not found in nested path %s", token_str, path);
|
|
||||||
pfree(current_path);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
token_str = strtok_r(NULL, ".", &saveptr);
|
|
||||||
|
|
||||||
/* If there are more path segments, current value must be an object */
|
|
||||||
if (token_str != NULL)
|
|
||||||
{
|
|
||||||
if (current_jbv->type != jbvBinary)
|
|
||||||
{
|
|
||||||
elog(DEBUG1, "Path segment %s is not a binary JSONB object in nested path %s", token_str, path);
|
|
||||||
pfree(current_path);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Validate the binary container before using it */
|
|
||||||
if (!is_jsonb_container_valid((JsonbContainer *)¤t_jbv->val.binary))
|
|
||||||
{
|
|
||||||
elog(WARNING, "Invalid binary JSONB container for path segment: %s", token_str);
|
|
||||||
pfree(current_path);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
jb = (Jsonb *) DatumGetPointer(JsonbValueToJsonb(current_jbv));
|
|
||||||
|
|
||||||
/* Validate the new container */
|
|
||||||
if (!jb || !is_jsonb_container_valid(&jb->root))
|
|
||||||
{
|
|
||||||
elog(WARNING, "Invalid JSONB container after path segment: %s", token_str);
|
|
||||||
pfree(current_path);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Check if the final value is an array */
|
|
||||||
if (current_jbv->type == jbvBinary)
|
|
||||||
{
|
|
||||||
/* Validate the binary container before iterating */
|
|
||||||
if (!is_jsonb_container_valid((JsonbContainer *)¤t_jbv->val.binary))
|
|
||||||
{
|
|
||||||
elog(WARNING, "Invalid binary JSONB container for nested path: %s", path);
|
|
||||||
pfree(current_path);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
it = JsonbIteratorInit((JsonbContainer *)¤t_jbv->val.binary);
|
|
||||||
token = JsonbIteratorNext(&it, &v, false);
|
|
||||||
|
|
||||||
if (token == WJB_BEGIN_ARRAY)
|
|
||||||
{
|
|
||||||
*found = true;
|
|
||||||
result = PointerGetDatum(JsonbValueToJsonb(current_jbv));
|
|
||||||
elog(DEBUG1, "Found array at nested path %s", path);
|
|
||||||
debug_jsonb_value(result, "Array");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
elog(DEBUG1, "Nested path %s exists but is not an array (token type: %d)", path, token);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
elog(DEBUG1, "Nested path %s exists but is not binary JSONB (type: %d)", path, current_jbv->type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PG_CATCH();
|
|
||||||
{
|
|
||||||
elog(WARNING, "Exception while processing nested array at path %s", path);
|
|
||||||
if (current_path)
|
|
||||||
pfree(current_path);
|
|
||||||
FlushErrorState();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
PG_END_TRY();
|
|
||||||
|
|
||||||
if (current_path)
|
|
||||||
pfree(current_path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
Reference in New Issue
Block a user