From 039846d845fe4a2c744f4f80c629a9756dc6f911 Mon Sep 17 00:00:00 2001 From: h3n4l Date: Tue, 24 Sep 2024 13:54:52 +0800 Subject: [PATCH 1/2] chore: update libpg_query source to 680f5ee67c6fdae497c8d1edfadd02b9b8eac74f Signed-off-by: h3n4l --- Makefile | 2 +- parse_test.go | 2 +- parser/pg_query_outfuncs_json.c | 4 ++- parser/pg_query_parse_plpgsql.c | 2 +- parser/src_backend_utils_adt_ruleutils.c | 12 +++++++ parser/src_pl_plpgsql_src_pl_comp.c | 46 +++++++++++++++++++++++- pg_query.pb.go | 2 +- 7 files changed, 64 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 5ffdee51..8c51c6b3 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ benchmark: # --- Below only needed for releasing new versions -LIB_PG_QUERY_TAG = 43bad3cbcd1a70a30494b64f464c3f60579884ed +LIB_PG_QUERY_TAG = 680f5ee67c6fdae497c8d1edfadd02b9b8eac74f root_dir := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))) LIB_TMPDIR = $(root_dir)/tmp diff --git a/parse_test.go b/parse_test.go index f998f976..c2492839 100644 --- a/parse_test.go +++ b/parse_test.go @@ -680,7 +680,7 @@ var parsePlPgSQLTests = []struct { `END;` + `$$ LANGUAGE plpgsql;`, `[ -{"PLpgSQL_function":{"datums":[{"PLpgSQL_var":{"refname":"v_name","datatype":{"PLpgSQL_type":{"typname":"UNKNOWN"}}}},{"PLpgSQL_var":{"refname":"v_version","datatype":{"PLpgSQL_type":{"typname":"UNKNOWN"}}}},{"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":"v_version IS NULL","parseMode":2}},"then_body":[{"PLpgSQL_stmt_return":{"lineno":1,"expr":{"PLpgSQL_expr":{"query":"v_name","parseMode":2}}}}]}},{"PLpgSQL_stmt_return":{"lineno":1,"expr":{"PLpgSQL_expr":{"query":"v_name || '/' || v_version","parseMode":2}}}}]}}}} +{"PLpgSQL_function":{"datums":[{"PLpgSQL_var":{"refname":"v_name","datatype":{"PLpgSQL_type":{"typname":"pg_catalog.\"varchar\""}}}},{"PLpgSQL_var":{"refname":"v_version","datatype":{"PLpgSQL_type":{"typname":"pg_catalog.\"varchar\""}}}},{"PLpgSQL_var":{"refname":"found","datatype":{"PLpgSQL_type":{"typname":"pg_catalog.\"boolean\""}}}}],"action":{"PLpgSQL_stmt_block":{"lineno":1,"body":[{"PLpgSQL_stmt_if":{"lineno":1,"cond":{"PLpgSQL_expr":{"query":"v_version IS NULL","parseMode":2}},"then_body":[{"PLpgSQL_stmt_return":{"lineno":1,"expr":{"PLpgSQL_expr":{"query":"v_name","parseMode":2}}}}]}},{"PLpgSQL_stmt_return":{"lineno":1,"expr":{"PLpgSQL_expr":{"query":"v_name || '/' || v_version","parseMode":2}}}}]}}}} ]`, }, } diff --git a/parser/pg_query_outfuncs_json.c b/parser/pg_query_outfuncs_json.c index 328b1f82..d4d74bff 100644 --- a/parser/pg_query_outfuncs_json.c +++ b/parser/pg_query_outfuncs_json.c @@ -203,7 +203,9 @@ _outOidList(StringInfo out, const List *node) static void _outInteger(StringInfo out, const Integer *node) { - if (node->ival > 0) + /* Don't output anything if the value is the default (0), to match + * protobuf's behavior. */ + if (node->ival != 0) appendStringInfo(out, "\"ival\":%d", node->ival); } diff --git a/parser/pg_query_parse_plpgsql.c b/parser/pg_query_parse_plpgsql.c index 65139e65..34f72590 100644 --- a/parser/pg_query_parse_plpgsql.c +++ b/parser/pg_query_parse_plpgsql.c @@ -226,7 +226,7 @@ static PLpgSQL_function *compile_create_function_stmt(CreateFunctionStmt* stmt) PLpgSQL_variable *argvariable; PLpgSQL_nsitem_type argitemtype; snprintf(buf, sizeof(buf), "$%d", foreach_current_index(lc) + 1); - argdtype = plpgsql_build_datatype(UNKNOWNOID, -1, InvalidOid, NULL); + argdtype = plpgsql_build_datatype(UNKNOWNOID, -1, InvalidOid, param->argType); argvariable = plpgsql_build_variable(param->name ? param->name : buf, 0, argdtype, false); argitemtype = argvariable->dtype == PLPGSQL_DTYPE_VAR ? PLPGSQL_NSTYPE_VAR : PLPGSQL_NSTYPE_REC; plpgsql_ns_additem(argitemtype, argvariable->dno, buf); diff --git a/parser/src_backend_utils_adt_ruleutils.c b/parser/src_backend_utils_adt_ruleutils.c index 92579913..a35d2250 100644 --- a/parser/src_backend_utils_adt_ruleutils.c +++ b/parser/src_backend_utils_adt_ruleutils.c @@ -2,6 +2,7 @@ * Symbols referenced in this file: * - quote_identifier * - quote_all_identifiers + * - quote_qualified_identifier *-------------------------------------------------------------------- */ @@ -1718,7 +1719,18 @@ quote_identifier(const char *ident) * Return a name of the form qualifier.ident, or just ident if qualifier * is NULL, quoting each component if necessary. The result is palloc'd. */ +char * +quote_qualified_identifier(const char *qualifier, + const char *ident) +{ + StringInfoData buf; + initStringInfo(&buf); + if (qualifier) + appendStringInfo(&buf, "%s.", quote_identifier(qualifier)); + appendStringInfoString(&buf, quote_identifier(ident)); + return buf.data; +} /* * get_relation_name diff --git a/parser/src_pl_plpgsql_src_pl_comp.c b/parser/src_pl_plpgsql_src_pl_comp.c index a79cbd49..f99fab0e 100644 --- a/parser/src_pl_plpgsql_src_pl_comp.c +++ b/parser/src_pl_plpgsql_src_pl_comp.c @@ -879,7 +879,51 @@ plpgsql_build_recfield(PLpgSQL_rec *rec, const char *fldname) * It can be NULL if the type could not be a composite type, or if it was * identified by OID to begin with (e.g., it's a function argument type). */ -PLpgSQL_type * plpgsql_build_datatype(Oid typeOid, int32 typmod, Oid collation, TypeName *origtypname) { PLpgSQL_type *typ; typ = (PLpgSQL_type *) palloc0(sizeof(PLpgSQL_type)); typ->typname = pstrdup("UNKNOWN"); typ->ttype = PLPGSQL_TTYPE_SCALAR; return typ; } + +PLpgSQL_type * plpgsql_build_datatype(Oid typeOid, int32 typmod, Oid collation, TypeName *origtypname) +{ + PLpgSQL_type *typ; + char *ident = NULL, *ns = NULL; + typ = (PLpgSQL_type *) palloc0(sizeof(PLpgSQL_type)); + + typ->ttype = PLPGSQL_TTYPE_SCALAR; + typ->atttypmod = typmod; + typ->collation = collation; + + if (origtypname) { + typ->typoid = origtypname->typeOid; + + if (list_length(origtypname->names) == 1) { + ident = linitial_node(String, origtypname->names)->sval; + } else if (list_length(origtypname->names) == 2) { + ns = linitial_node(String, origtypname->names)->sval; + ident = lsecond_node(String, origtypname->names)->sval; + } + } else { + typ->typoid = typeOid; + ns = "pg_catalog"; + switch(typeOid) + { + case BOOLOID: + ident = "boolean"; + break; + case INT4OID: + ident = "integer"; + break; + case TEXTOID: + ident = "text"; + break; + case REFCURSOROID: + ident = "refcursor"; + break; + } + } + if (ident) { + typ->typname = quote_qualified_identifier(ns, ident); + } + return typ; +} + /* diff --git a/pg_query.pb.go b/pg_query.pb.go index 4a323dd2..86513534 100644 --- a/pg_query.pb.go +++ b/pg_query.pb.go @@ -3,7 +3,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.31.0 -// protoc v4.25.1 +// protoc v5.28.0 // source: pg_query.proto package pg_query From b1fe9758af394383cdb1684cc411e820ca3220a5 Mon Sep 17 00:00:00 2001 From: h3n4l Date: Tue, 24 Sep 2024 14:04:07 +0800 Subject: [PATCH 2/2] chore: add cursor to test Signed-off-by: h3n4l --- parse_test.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/parse_test.go b/parse_test.go index c2492839..becb636e 100644 --- a/parse_test.go +++ b/parse_test.go @@ -672,6 +672,8 @@ var parsePlPgSQLTests = []struct { `CREATE OR REPLACE FUNCTION cs_fmt_browser_version(v_name varchar,` + `v_version varchar) ` + `RETURNS varchar AS $$ ` + + `DECLARE ` + + `CURS1 CURSOR FOR SELECT 1;` + `BEGIN ` + ` IF v_version IS NULL THEN` + ` RETURN v_name;` + @@ -680,7 +682,7 @@ var parsePlPgSQLTests = []struct { `END;` + `$$ LANGUAGE plpgsql;`, `[ -{"PLpgSQL_function":{"datums":[{"PLpgSQL_var":{"refname":"v_name","datatype":{"PLpgSQL_type":{"typname":"pg_catalog.\"varchar\""}}}},{"PLpgSQL_var":{"refname":"v_version","datatype":{"PLpgSQL_type":{"typname":"pg_catalog.\"varchar\""}}}},{"PLpgSQL_var":{"refname":"found","datatype":{"PLpgSQL_type":{"typname":"pg_catalog.\"boolean\""}}}}],"action":{"PLpgSQL_stmt_block":{"lineno":1,"body":[{"PLpgSQL_stmt_if":{"lineno":1,"cond":{"PLpgSQL_expr":{"query":"v_version IS NULL","parseMode":2}},"then_body":[{"PLpgSQL_stmt_return":{"lineno":1,"expr":{"PLpgSQL_expr":{"query":"v_name","parseMode":2}}}}]}},{"PLpgSQL_stmt_return":{"lineno":1,"expr":{"PLpgSQL_expr":{"query":"v_name || '/' || v_version","parseMode":2}}}}]}}}} +{"PLpgSQL_function":{"datums":[{"PLpgSQL_var":{"refname":"v_name","datatype":{"PLpgSQL_type":{"typname":"pg_catalog.\"varchar\""}}}},{"PLpgSQL_var":{"refname":"v_version","datatype":{"PLpgSQL_type":{"typname":"pg_catalog.\"varchar\""}}}},{"PLpgSQL_var":{"refname":"found","datatype":{"PLpgSQL_type":{"typname":"pg_catalog.\"boolean\""}}}},{"PLpgSQL_var":{"refname":"curs1","lineno":1,"datatype":{"PLpgSQL_type":{"typname":"pg_catalog.refcursor"}},"cursor_explicit_expr":{"PLpgSQL_expr":{"query":"SELECT 1","parseMode":0}},"cursor_explicit_argrow":-1,"cursor_options":256}}],"action":{"PLpgSQL_stmt_block":{"lineno":1,"body":[{"PLpgSQL_stmt_if":{"lineno":1,"cond":{"PLpgSQL_expr":{"query":"v_version IS NULL","parseMode":2}},"then_body":[{"PLpgSQL_stmt_return":{"lineno":1,"expr":{"PLpgSQL_expr":{"query":"v_name","parseMode":2}}}}]}},{"PLpgSQL_stmt_return":{"lineno":1,"expr":{"PLpgSQL_expr":{"query":"v_name || '/' || v_version","parseMode":2}}}}]}}}} ]`, }, }