Skip to content

Commit

Permalink
Refactor PL/pgSQL parser to work based on CREATE FUNCTION statements.
Browse files Browse the repository at this point in the history
  • Loading branch information
lfittl committed Jun 21, 2016
1 parent 0a7d82a commit 3c6d31b
Show file tree
Hide file tree
Showing 9 changed files with 559 additions and 295 deletions.
18 changes: 15 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,12 +103,22 @@ int main() {

pg_query_init();

result = pg_query_parse_plpgsql("BEGIN \nIF v_version IS NULL THEN \nRETURN v_name;\nEND IF; \nRETURN v_name || '/' || v_version; \nEND;");
result = pg_query_parse_plpgsql(" \
CREATE OR REPLACE FUNCTION cs_fmt_browser_version(v_name varchar, \
v_version varchar) \
RETURNS varchar AS $$ \
BEGIN \
IF v_version IS NULL THEN \
RETURN v_name; \
END IF; \
RETURN v_name || '/' || v_version; \
END; \
$$ LANGUAGE plpgsql;");
if (result.error) {
printf("error: %s at %d\n", result.error->message, result.error->cursorpos);
} else {
printf("%s\n", result.plpgsql_func);
printf("%s\n", result.plpgsql_funcs);
}
pg_query_free_plpgsql_parse_result(result);
Expand All @@ -120,7 +130,9 @@ int main() {
This will output:
```json
{"PLpgSQL_function": {"datums": [{"PLpgSQL_var": {"refname": "found", "datatype": {"PLpgSQL_type": {"typname": "UNKNOWN"}}}}], "action": {"PLpgSQL_stmt_block": {"lineno": 1, "body": [{"PLpgSQL_stmt_if": {"lineno": 2, "cond": {"PLpgSQL_expr": {"query": "SELECT v_version IS NULL"}}, "then_body": [{"PLpgSQL_stmt_return": {"lineno": 3, "expr": {"PLpgSQL_expr": {"query": "SELECT v_name"}}}}]}}, {"PLpgSQL_stmt_return": {"lineno": 5, "expr": {"PLpgSQL_expr": {"query": "SELECT v_name || '/' || v_version"}}}}]}}}}
[
{"PLpgSQL_function": {"datums": [{"PLpgSQL_var": {"refname": "found", "datatype": {"PLpgSQL_type": {"typname": "UNKNOWN"}}}}], "action": {"PLpgSQL_stmt_block": {"lineno": 1, "body": [{"PLpgSQL_stmt_if": {"lineno": 1, "cond": {"PLpgSQL_expr": {"query": "SELECT v_version IS NULL"}}, "then_body": [{"PLpgSQL_stmt_return": {"lineno": 1, "expr": {"PLpgSQL_expr": {"query": "SELECT v_name"}}}}]}}, {"PLpgSQL_stmt_return": {"lineno": 1, "expr": {"PLpgSQL_expr": {"query": "SELECT v_name || '/' || v_version"}}}}]}}}}
]
```
## Versions
Expand Down
14 changes: 12 additions & 2 deletions examples/simple_plpgsql.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,22 @@ int main() {

pg_query_init();

result = pg_query_parse_plpgsql("BEGIN \nIF v_version IS NULL THEN \nRETURN v_name;\nEND IF; \nRETURN v_name || '/' || v_version; \nEND;");
result = pg_query_parse_plpgsql(" \
CREATE OR REPLACE FUNCTION cs_fmt_browser_version(v_name varchar, \
v_version varchar) \
RETURNS varchar AS $$ \
BEGIN \
IF v_version IS NULL THEN \
RETURN v_name; \
END IF; \
RETURN v_name || '/' || v_version; \
END; \
$$ LANGUAGE plpgsql;");

if (result.error) {
printf("error: %s at %d\n", result.error->message, result.error->cursorpos);
} else {
printf("%s\n", result.plpgsql_func);
printf("%s\n", result.plpgsql_funcs);
}

pg_query_free_plpgsql_parse_result(result);
Expand Down
3 changes: 1 addition & 2 deletions pg_query.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ typedef struct {
} PgQueryParseResult;

typedef struct {
char* plpgsql_func;
char* stderr_buffer;
char* plpgsql_funcs;
PgQueryError* error;
} PgQueryPlpgsqlParseResult;

Expand Down
3 changes: 3 additions & 0 deletions src/pg_query_json_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ removeTrailingDelimiter(StringInfo str)
if (str->len >= 2 && str->data[str->len - 2] == ',' && str->data[str->len - 1] == ' ') {
str->len -= 2;
str->data[str->len] = '\0';
} else if (str->len >= 1 && str->data[str->len - 1] == ',') {
str->len -= 1;
str->data[str->len] = '\0';
}
}

Expand Down
28 changes: 23 additions & 5 deletions src/pg_query_json_plpgsql.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,32 @@
if (node->fldname != NULL) { \
ListCell *lc; \
appendStringInfo(str, "\"" CppAsString(fldname) "\": ["); \
foreach(lc, node->fldname) { outfunc(str, (fldtype *) lfirst(lc)); } \
foreach(lc, node->fldname) { \
appendStringInfoString(str, "{"); \
outfunc(str, (fldtype *) lfirst(lc)); \
removeTrailingDelimiter(str); \
appendStringInfoString(str, "}},"); \
} \
removeTrailingDelimiter(str); \
appendStringInfoString(str, "], "); \
}

#define WRITE_STATEMENTS_FIELD(fldname) \
if (node->fldname != NULL) { \
ListCell *lc; \
appendStringInfo(str, "\"" CppAsString(fldname) "\": ["); \
foreach(lc, node->fldname) { \
dump_stmt(str, (PLpgSQL_stmt *) lfirst(lc)); \
} \
removeTrailingDelimiter(str); \
appendStringInfoString(str, "],"); \
}

#define WRITE_EXPR_FIELD(fldname) WRITE_OBJ_FIELD(fldname, dump_expr)
#define WRITE_BLOCK_FIELD(fldname) WRITE_OBJ_FIELD(fldname, dump_block)
#define WRITE_RECORD_FIELD(fldname) WRITE_OBJ_FIELD(fldname, dump_record)
#define WRITE_ROW_FIELD(fldname) WRITE_OBJ_FIELD(fldname, dump_row)
#define WRITE_VAR_FIELD(fldname) WRITE_OBJ_FIELD(fldname, dump_var)
#define WRITE_STATEMENTS_FIELD(fldname) WRITE_LIST_FIELD(fldname, PLpgSQL_stmt, dump_stmt)

static void dump_record(StringInfo str, PLpgSQL_rec *stmt);
static void dump_row(StringInfo str, PLpgSQL_row *stmt);
Expand Down Expand Up @@ -156,8 +171,8 @@ dump_block(StringInfo str, PLpgSQL_stmt_block *node)
WRITE_NODE_TYPE("PLpgSQL_stmt_block");

WRITE_INT_FIELD(lineno);
WRITE_STRING_FIELD(label);
WRITE_LIST_FIELD(body, PLpgSQL_stmt, dump_stmt);
WRITE_STRING_FIELD(label);
WRITE_STATEMENTS_FIELD(body);
WRITE_OBJ_FIELD(exceptions, dump_exception_block);

removeTrailingDelimiter(str);
Expand All @@ -181,7 +196,10 @@ dump_exception(StringInfo str, PLpgSQL_exception *node)
appendStringInfo(str, "\"conditions\": [");
for (cond = node->conditions; cond; cond = cond->next)
{
appendStringInfoString(str, "{");
dump_condition(str, cond);
removeTrailingDelimiter(str);
appendStringInfoString(str, "}},");
}
removeTrailingDelimiter(str);
appendStringInfoString(str, "], ");
Expand Down Expand Up @@ -451,7 +469,7 @@ dump_execsql(StringInfo str, PLpgSQL_stmt_execsql *node)

WRITE_INT_FIELD(lineno);
WRITE_EXPR_FIELD(sqlstmt);
WRITE_BOOL_FIELD(mod_stmt);
//WRITE_BOOL_FIELD(mod_stmt); // This is only populated when executing the function
WRITE_BOOL_FIELD(into);
WRITE_BOOL_FIELD(strict);
WRITE_RECORD_FIELD(rec);
Expand Down
Loading

0 comments on commit 3c6d31b

Please sign in to comment.