From 39495115a2108ca96c1873f3c3ac93d0b5603cd4 Mon Sep 17 00:00:00 2001 From: yukkop Date: Fri, 16 May 2025 00:37:30 +0000 Subject: [PATCH] feat: `hemar`: exec handle the {{ }} inside --- package/c/hemar/hemar.c | 28 +++++++++++-------- package/c/hemar/test/test_template_parser.sql | 25 +++++++++++++++++ 2 files changed, 42 insertions(+), 11 deletions(-) diff --git a/package/c/hemar/hemar.c b/package/c/hemar/hemar.c index ece77a0..71a1564 100755 --- a/package/c/hemar/hemar.c +++ b/package/c/hemar/hemar.c @@ -642,10 +642,11 @@ template_parse_execute(MemoryContext context, const char **s_ptr, code_start = *s; - /* Track quote state to handle SQL content properly */ + /* Track quote state and brace level to handle SQL content properly */ bool in_single_quote = false; bool in_double_quote = false; bool escaped = false; + int brace_level = 1; /* Start with 1 for the opening braces we already consumed */ while (**s != '\0') { @@ -665,18 +666,23 @@ template_parse_execute(MemoryContext context, const char **s_ptr, } } - /* Only check for closing braces when not inside quotes */ + /* Only check for braces when not inside quotes */ if (!in_single_quote && !in_double_quote) { - if (strncmp(*s, config->Syntax.Braces.close, strlen(config->Syntax.Braces.close)) == 0) { - break; - } - /* Check for nested opening braces */ if (strncmp(*s, config->Syntax.Braces.open, strlen(config->Syntax.Braces.open)) == 0) { - if (error_code) - *error_code = TEMPLATE_ERROR_NESTED_EXECUTE; - template_free_node(node); - return NULL; + brace_level++; + *s += strlen(config->Syntax.Braces.open) - 1; /* -1 because we'll increment s below */ + } + /* Check for closing braces */ + else if (strncmp(*s, config->Syntax.Braces.close, strlen(config->Syntax.Braces.close)) == 0) { + brace_level--; + + /* If we've reached the matching closing brace, we're done */ + if (brace_level == 0) { + break; + } + + *s += strlen(config->Syntax.Braces.close) - 1; /* -1 because we'll increment s below */ } } @@ -694,7 +700,7 @@ template_parse_execute(MemoryContext context, const char **s_ptr, node->value->execute.code = MemoryContextStrdup(context, pnstrdup(code_start, code_len)); /* Check for closing brace */ - if (strncmp(*s, config->Syntax.Braces.close, strlen(config->Syntax.Braces.close)) != 0) + if (brace_level != 0 || strncmp(*s, config->Syntax.Braces.close, strlen(config->Syntax.Braces.close)) != 0) { if (error_code) *error_code = TEMPLATE_ERROR_UNEXPECTED_EXECUTE_END; diff --git a/package/c/hemar/test/test_template_parser.sql b/package/c/hemar/test/test_template_parser.sql index 21b2c68..1db3de1 100755 --- a/package/c/hemar/test/test_template_parser.sql +++ b/package/c/hemar/test/test_template_parser.sql @@ -414,6 +414,31 @@ TEXT: " RAISE WARNING 'Test %: Execute with complex SQL and quotes - FAILED', total_tests; END IF; + -- Test 21: Execute tag with braces inside SQL code + total_tests := total_tests + 1; + result := test_template_parse( + $template21${{ exec + -- SQL with curly braces in string literals and comments + /* Comment with {{ braces }} inside */ + SELECT + '{{ This is inside a string literal }}' AS braced_text, + $str$String with {{ and }} inside$str$ AS dollar_quoted, + regexp_replace('test', 'e(.)t', 'a$1z') AS regex_with_curly; + }}$template21$, + $expected21$EXECUTE: "-- SQL with curly braces in string literals and comments + /* Comment with {{ braces }} inside */ + SELECT + '{{ This is inside a string literal }}' AS braced_text, + $str$String with {{ and }} inside$str$ AS dollar_quoted, + regexp_replace('test', 'e(.)t', 'a$1z') AS regex_with_curly;"$expected21$ + ); + IF result THEN + passed_tests := passed_tests + 1; + RAISE NOTICE 'Test %: Execute tag with braces inside SQL code - PASSED', total_tests; + ELSE + RAISE WARNING 'Test %: Execute tag with braces inside SQL code - FAILED', total_tests; + END IF; + -- Print summary IF passed_tests = total_tests THEN RAISE NOTICE '------------------------------------';