From 127b367f591c87e21c831c8e509b5ce8f48c03c4 Mon Sep 17 00:00:00 2001 From: John Gemignani Date: Wed, 27 Dec 2023 10:30:47 -0800 Subject: [PATCH] Pg16 to master (#1454) * Fix Docker file to reflect PostgreSQL version 15 (#1449) Fixed the following Docker file to reflect running under PostgreSQL version 15. modified: docker/Dockerfile.dev This impacts the development DockerHub builds. * Master to PostgreSQL version 16 (#1451) * Initial PG16 version (#1237) Fixed empty string handling. Previously, the PG 16 outToken emitted NULL for an empty string, but now it emits an empty string "". Consequently, our cypher read function required modification to properly decode the empty string as a plain token, thereby addressing the comparison issue. Compared the branches and added the necessary changes so that the query's rteperminfos variable doesn't stay NULL. Fix missing include varatt.h (causing undefined symbol VARDATA_ANY) & Fixing some test cases of the failings Added missing include varatt.h to fix the undefined symbol while loading age into postgresql because usage of VARDATA_ANY needs to import varatt.h in PG16 Modified initialisation of ResultRelInfo and removed unnecessary RTEs Compared the branches and added the necessary changes so that the query's rteperminfos variable doesn't stay NULL. Modified initialisation of ResultRelInfo and removed unnecessary RTEs One of the problems that we were facing was related to the ResultRelInfo pointing at the wrong RTE via its ri_RangeTableIndex. The create_entity_result_rel_info() function does not have the capability of setting the ri_RootResultRelInfo to the correct ResultRelInfo node because it does not have access to the ModifyTableState node. The solution for this was to set the third argument in InitResultRelInfo() to be zero instead of list_length(estate->es_range_table). In the update_entity_tuple() function, when we call table_tuple_update() and assign the returned value to the result variable, the buffer variable receives the value of 0. Made a workaround so that the original value isn't lost. This is a work in progress for the new field that was added to the struct Var called varnullingrels. According to the documentation, this field is responsible for marking the Vars as nullable, if they are coming from a JOIN, either LEFT JOIN, RIGHT JOIN, or FULL OUTER JOIN. The changes were made following an "optional match" clause which is being treated as a LEFT JOIN from our extension. A function markRelsAsNulledBy is added because its internal in Postgres and doesn't belong in a header file, therefore it can't be exported. This function is added before the creation of the Vars from the make_vertex_expr and make_edge_expr, to correctly mark the specific PNSI as nullable, so later in the planner stage, the Vars will be correctly nulled. Fix incorrect typecasting in agtype_to_graphid function. Fix incorrect returns to the fuction _label_name, _ag_build_vertex and _ag_build_edge. Contributors Panagiotis Foliadis Matheus Farias Mohamed Mokhtar Hannan Aamir John Gemignani Muhammad Taha Naveed Wendel de Lana --------- * Fix Docker files to reflect PostgreSQL version 16 (#1448) Fixed the following Docker files to reflect running under PostgreSQL version 16. modified: docker/Dockerfile modified: docker/Dockerfile.dev This impacts the DockerHub builds. * Mark null-returning RTEs in outer joins as nullable RTEs that appear in the right side of a left join are marked as 'nullable'. The column references to a nullable RTE within the join's RTE are also marked as 'nullable'. This concept is introduced in Postgresql v16. The change in Postgresql v16's pullup_replace_vars_callback() function causes different plans to be generated depending on whether appropriate RTEs are marked nullable. Without marking nullable, in a left join, any function call expression containing right RTE's columns as arguments are not evaluated at the scan level, rather it is evaluated after the join is performed. At that point, the function call may receive null input, which was unexpected in previous Postgresql versions. See: ---- - Postgresql v16's commit: Make Vars be outer-join-aware https://www.postgresql.org/message-id/830269.1656693747@sss.pgh.pa.us - The 'Vars and PlaceHolderVars' section in the Postgresql v16's optimizer/README.md * Fix minor code formatting. --------- Co-authored-by: Shoaib Co-authored-by: Rafsun Masud --------- Co-authored-by: Shoaib Co-authored-by: Rafsun Masud --- .github/workflows/go-driver.yml | 18 ++----- .github/workflows/installcheck.yaml | 4 +- .github/workflows/jdbc-driver.yaml | 18 ++----- .github/workflows/nodejs-driver.yaml | 18 ++----- .github/workflows/python-driver.yaml | 18 ++----- README.md | 10 ++-- src/backend/catalog/ag_catalog.c | 21 ++++---- src/backend/catalog/ag_label.c | 7 +-- src/backend/executor/cypher_set.c | 3 +- src/backend/executor/cypher_utils.c | 43 ++++++++++++---- src/backend/nodes/cypher_readfuncs.c | 24 ++++++--- src/backend/parser/cypher_clause.c | 72 ++++++++++++++++++++++++++- src/backend/parser/cypher_expr.c | 3 +- src/backend/parser/cypher_item.c | 14 +++--- src/backend/parser/cypher_parse_agg.c | 12 ++++- src/backend/utils/adt/agtype.c | 24 ++++++--- 16 files changed, 197 insertions(+), 112 deletions(-) diff --git a/.github/workflows/go-driver.yml b/.github/workflows/go-driver.yml index 10b1abaa6..015ab99f8 100644 --- a/.github/workflows/go-driver.yml +++ b/.github/workflows/go-driver.yml @@ -2,10 +2,10 @@ name: Go Driver Tests on: push: - branches: [ "master", "PG16" ] + branches: [ "PG16" ] pull_request: - branches: [ "master", "PG16" ] + branches: [ "PG16" ] jobs: build: @@ -23,19 +23,7 @@ jobs: - name: Set tag based on branch run: | - if [[ "$GITHUB_EVENT_NAME" == "push" ]]; then - if [[ "$GITHUB_REF" == "refs/heads/master" ]]; then - echo "TAG=latest" >> $GITHUB_ENV - elif [[ "$GITHUB_REF" == "refs/heads/PG16" ]]; then - echo "TAG=PG16_latest" >> $GITHUB_ENV - fi - elif [[ "$GITHUB_EVENT_NAME" == "pull_request" ]]; then - if [[ "$GITHUB_BASE_REF" == "master" ]]; then - echo "TAG=latest" >> $GITHUB_ENV - elif [[ "$GITHUB_BASE_REF" == "PG16" ]]; then - echo "TAG=PG16_latest" >> $GITHUB_ENV - fi - fi + echo "TAG=PG16_latest" >> $GITHUB_ENV - name: Run apache/age docker image run: | diff --git a/.github/workflows/installcheck.yaml b/.github/workflows/installcheck.yaml index a975aeb49..fa8b9a4ef 100644 --- a/.github/workflows/installcheck.yaml +++ b/.github/workflows/installcheck.yaml @@ -2,9 +2,9 @@ name: Build / Regression on: push: - branches: [ 'master', 'PG16' ] + branches: [ 'PG16' ] pull_request: - branches: [ 'master', 'PG16' ] + branches: [ 'PG16' ] jobs: build: diff --git a/.github/workflows/jdbc-driver.yaml b/.github/workflows/jdbc-driver.yaml index 81d2558ae..d91c8c974 100644 --- a/.github/workflows/jdbc-driver.yaml +++ b/.github/workflows/jdbc-driver.yaml @@ -2,10 +2,10 @@ name: JDBC Driver Tests on: push: - branches: [ "master", "PG16" ] + branches: [ "PG16" ] pull_request: - branches: [ "master", "PG16" ] + branches: [ "PG16" ] jobs: build: @@ -25,19 +25,7 @@ jobs: - name: Set tag based on branch run: | - if [[ "$GITHUB_EVENT_NAME" == "push" ]]; then - if [[ "$GITHUB_REF" == "refs/heads/master" ]]; then - echo "TAG=latest" >> $GITHUB_ENV - elif [[ "$GITHUB_REF" == "refs/heads/PG16" ]]; then - echo "TAG=PG16_latest" >> $GITHUB_ENV - fi - elif [[ "$GITHUB_EVENT_NAME" == "pull_request" ]]; then - if [[ "$GITHUB_BASE_REF" == "master" ]]; then - echo "TAG=latest" >> $GITHUB_ENV - elif [[ "$GITHUB_BASE_REF" == "PG16" ]]; then - echo "TAG=PG16_latest" >> $GITHUB_ENV - fi - fi + echo "TAG=PG16_latest" >> $GITHUB_ENV - name: Build and Test run: | diff --git a/.github/workflows/nodejs-driver.yaml b/.github/workflows/nodejs-driver.yaml index bc926e6fd..c64330415 100644 --- a/.github/workflows/nodejs-driver.yaml +++ b/.github/workflows/nodejs-driver.yaml @@ -2,10 +2,10 @@ name: Nodejs Driver Tests on: push: - branches: [ "master", "PG16" ] + branches: [ "PG16" ] pull_request: - branches: [ "master", "PG16" ] + branches: [ "PG16" ] jobs: build: @@ -20,19 +20,7 @@ jobs: - name: Set tag based on branch run: | - if [[ "$GITHUB_EVENT_NAME" == "push" ]]; then - if [[ "$GITHUB_REF" == "refs/heads/master" ]]; then - echo "TAG=latest" >> $GITHUB_ENV - elif [[ "$GITHUB_REF" == "refs/heads/PG16" ]]; then - echo "TAG=PG16_latest" >> $GITHUB_ENV - fi - elif [[ "$GITHUB_EVENT_NAME" == "pull_request" ]]; then - if [[ "$GITHUB_BASE_REF" == "master" ]]; then - echo "TAG=latest" >> $GITHUB_ENV - elif [[ "$GITHUB_BASE_REF" == "PG16" ]]; then - echo "TAG=PG16_latest" >> $GITHUB_ENV - fi - fi + echo "TAG=PG16_latest" >> $GITHUB_ENV - name: Run apache/age docker image run: | diff --git a/.github/workflows/python-driver.yaml b/.github/workflows/python-driver.yaml index 3e7f8ee54..ebff54495 100644 --- a/.github/workflows/python-driver.yaml +++ b/.github/workflows/python-driver.yaml @@ -2,10 +2,10 @@ name: Python Driver Tests on: push: - branches: [ "master", "PG16" ] + branches: [ "PG16" ] pull_request: - branches: [ "master", "PG16" ] + branches: [ "PG16" ] jobs: build: @@ -20,19 +20,7 @@ jobs: - name: Set tag based on branch run: | - if [[ "$GITHUB_EVENT_NAME" == "push" ]]; then - if [[ "$GITHUB_REF" == "refs/heads/master" ]]; then - echo "TAG=latest" >> $GITHUB_ENV - elif [[ "$GITHUB_REF" == "refs/heads/PG16" ]]; then - echo "TAG=PG16_latest" >> $GITHUB_ENV - fi - elif [[ "$GITHUB_EVENT_NAME" == "pull_request" ]]; then - if [[ "$GITHUB_BASE_REF" == "master" ]]; then - echo "TAG=latest" >> $GITHUB_ENV - elif [[ "$GITHUB_BASE_REF" == "PG16" ]]; then - echo "TAG=PG16_latest" >> $GITHUB_ENV - fi - fi + echo "TAG=PG16_latest" >> $GITHUB_ENV - name: Run apache/age docker image run: | diff --git a/README.md b/README.md index a6d2728e3..485512009 100644 --- a/README.md +++ b/README.md @@ -33,8 +33,8 @@   - - + +   @@ -131,7 +131,7 @@ Apache AGE is intended to be simple to install and run. It can be installed with  Install PostgreSQL -You will need to install an AGE compatible version of Postgres, for now AGE supports Postgres 11, 12, 13, 14 & 15. Supporting the latest versions is on AGE roadmap. +You will need to install an AGE compatible version of Postgres, for now AGE supports Postgres 11, 12, 13, 14, 15 & 16. Supporting the latest versions is on AGE roadmap.

 Installation via Package Manager @@ -149,7 +149,7 @@ sudo apt install postgresql  Installation From Source Code

-You can
download the Postgres source code and install your own instance of Postgres. You can read instructions on how to install from source code for different versions on the official Postgres Website. +You can download the Postgres source code and install your own instance of Postgres. You can read instructions on how to install from source code for different versions on the official Postgres Website. @@ -158,7 +158,7 @@ You can download the Postgres Clone the github repository or download the download an official release. -Run the pg_config utility and check the version of PostgreSQL. Currently, only PostgreSQL versions 11, 12, 13, 14 & 15 are supported. If you have any other version of Postgres, you will need to install PostgreSQL version 11, 12, 13, 14, or 15. +Run the pg_config utility and check the version of PostgreSQL. Currently, only PostgreSQL versions 11, 12, 13, 14, 15 & 16 are supported. If you have any other version of Postgres, you will need to install PostgreSQL version 11, 12, 13, 14, 15 or 16.
```bash diff --git a/src/backend/catalog/ag_catalog.c b/src/backend/catalog/ag_catalog.c index ab747ae65..7b8a96c13 100644 --- a/src/backend/catalog/ag_catalog.c +++ b/src/backend/catalog/ag_catalog.c @@ -86,26 +86,29 @@ void process_utility_hook_fini(void) * from being thrown, we need to disable the object_access_hook before dropping * the extension. */ -void ag_ProcessUtility_hook(PlannedStmt *pstmt, const char *queryString, bool readOnlyTree, - ProcessUtilityContext context, ParamListInfo params, - QueryEnvironment *queryEnv, DestReceiver *dest, - QueryCompletion *qc) +void ag_ProcessUtility_hook(PlannedStmt *pstmt, const char *queryString, + bool readOnlyTree, ProcessUtilityContext context, + ParamListInfo params, QueryEnvironment *queryEnv, + DestReceiver *dest, QueryCompletion *qc) { if (is_age_drop(pstmt)) + { drop_age_extension((DropStmt *)pstmt->utilityStmt); + } else if (prev_process_utility_hook) - (*prev_process_utility_hook) (pstmt, queryString, readOnlyTree, context, params, - queryEnv, dest, qc); + { + (*prev_process_utility_hook) (pstmt, queryString, readOnlyTree, context, + params, queryEnv, dest, qc); + } else { Assert(IsA(pstmt, PlannedStmt)); Assert(pstmt->commandType == CMD_UTILITY); Assert(queryString != NULL); /* required as of 8.4 */ Assert(qc == NULL || qc->commandTag == CMDTAG_UNKNOWN); - standard_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, queryEnv, - dest, qc); + standard_ProcessUtility(pstmt, queryString, readOnlyTree, context, + params, queryEnv, dest, qc); } - } static void drop_age_extension(DropStmt *stmt) diff --git a/src/backend/catalog/ag_label.c b/src/backend/catalog/ag_label.c index 09fba1029..563d53489 100644 --- a/src/backend/catalog/ag_label.c +++ b/src/backend/catalog/ag_label.c @@ -188,9 +188,10 @@ Datum _label_name(PG_FUNCTION_ARGS) uint32 label_id; if (PG_ARGISNULL(0) || PG_ARGISNULL(1)) - PG_RETURN_NULL(); - //ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - // errmsg("graph_oid and label_id must not be null"))); + { + ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), + errmsg("graph_oid and label_id must not be null"))); + } graph = PG_GETARG_OID(0); diff --git a/src/backend/executor/cypher_set.c b/src/backend/executor/cypher_set.c index fdfceda14..446131309 100644 --- a/src/backend/executor/cypher_set.c +++ b/src/backend/executor/cypher_set.c @@ -485,7 +485,8 @@ static void process_update_list(CustomScanState *node) } // Alter the properties Agtype value. - if (strcmp(update_item->prop_name, "")) + if (update_item->prop_name != NULL && + strcmp(update_item->prop_name, "") != 0) { altered_properties = alter_property_value(original_properties, update_item->prop_name, diff --git a/src/backend/executor/cypher_utils.c b/src/backend/executor/cypher_utils.c index baccc0282..e649c1136 100644 --- a/src/backend/executor/cypher_utils.c +++ b/src/backend/executor/cypher_utils.c @@ -51,16 +51,20 @@ /* * Given the graph name and the label name, create a ResultRelInfo for the table - * those to variables represent. Open the Indices too. + * those two variables represent. Open the Indices too. */ ResultRelInfo *create_entity_result_rel_info(EState *estate, char *graph_name, char *label_name) { - RangeVar *rv; - Relation label_relation; - ResultRelInfo *resultRelInfo; + RangeVar *rv = NULL; + Relation label_relation = NULL; + ResultRelInfo *resultRelInfo = NULL; + ParseState *pstate = NULL; + RangeTblEntry *rte = NULL; + int pii = 0; - ParseState *pstate = make_parsestate(NULL); + /* create a new parse state for this operation */ + pstate = make_parsestate(NULL); resultRelInfo = palloc(sizeof(ResultRelInfo)); @@ -75,12 +79,33 @@ ResultRelInfo *create_entity_result_rel_info(EState *estate, char *graph_name, label_relation = parserOpenTable(pstate, rv, RowExclusiveLock); - // initialize the resultRelInfo - InitResultRelInfo(resultRelInfo, label_relation, - 0, NULL, + /* + * Get the rte to determine the correct perminfoindex value. Some rtes + * may have it set up, some created here (executor) may not. + * + * Note: The RTEPermissionInfo structure was added in PostgreSQL version 16. + * + * Note: We use the list_length because exec_rt_fetch starts at 1, not 0. + * Doing this gives us the last rte in the es_range_table list, which + * is the rte in question. + * + * If the rte is created here and doesn't have a perminfoindex, we + * need to pass on a 0. Otherwise, later on GetResultRTEPermissionInfo + * will attempt to get the rte's RTEPermissionInfo data, which doesn't + * exist. + * + * TODO: Ideally, we should consider creating the RTEPermissionInfo data, + * but as this is just a read of the label relation, it is likely + * unnecessary. + */ + rte = exec_rt_fetch(list_length(estate->es_range_table), estate); + pii = (rte->perminfoindex == 0) ? 0 : list_length(estate->es_range_table); + + /* initialize the resultRelInfo */ + InitResultRelInfo(resultRelInfo, label_relation, pii, NULL, estate->es_instrument); - // open the parse state + /* open the indices */ ExecOpenIndices(resultRelInfo, false); free_parsestate(pstate); diff --git a/src/backend/nodes/cypher_readfuncs.c b/src/backend/nodes/cypher_readfuncs.c index 1aa763d58..0587229f6 100644 --- a/src/backend/nodes/cypher_readfuncs.c +++ b/src/backend/nodes/cypher_readfuncs.c @@ -24,6 +24,7 @@ #include "nodes/cypher_readfuncs.h" #include "nodes/cypher_nodes.h" +static char *nullable_string(const char *token, int length); /* * Copied From Postgres * @@ -111,7 +112,7 @@ #define READ_STRING_FIELD(fldname) \ token = pg_strtok(&length); \ token = pg_strtok(&length); \ - local_node->fldname = non_nullable_string(token, length) + local_node->fldname = nullable_string(token, length) // Read a parse location field (and throw away the value, per notes above) #define READ_LOCATION_FIELD(fldname) \ @@ -162,11 +163,22 @@ #define strtobool(x) ((*(x) == 't') ? true : false) -#define nullable_string(token,length) \ - ((length) == 0 ? NULL : debackslash(token, length)) - -#define non_nullable_string(token,length) \ - ((length == 2 && token[0] == '"' && token[1] == '"') ? "" : debackslash(token, length)) +/* copied from PG16 function of the same name for consistency */ +static char *nullable_string(const char *token, int length) +{ + /* outToken emits <> for NULL, and pg_strtok makes that an empty string */ + if (length == 0) + { + return NULL; + } + /* outToken emits "" for empty string */ + if (length == 2 && token[0] == '"' && token[1] == '"') + { + return pstrdup(""); + } + /* otherwise, we must remove protective backslashes added by outToken */ + return debackslash(token, length); +} /* * Default read function for cypher nodes. For most nodes, we don't expect diff --git a/src/backend/parser/cypher_clause.c b/src/backend/parser/cypher_clause.c index c4201be23..e89f20b8a 100644 --- a/src/backend/parser/cypher_clause.c +++ b/src/backend/parser/cypher_clause.c @@ -45,6 +45,7 @@ #include "parser/parse_relation.h" #include "parser/parse_target.h" #include "parser/parsetree.h" +#include "parser/parse_relation.h" #include "rewrite/rewriteHandler.h" #include "utils/typcache.h" #include "utils/lsyscache.h" @@ -331,6 +332,8 @@ static List *make_target_list_from_join(ParseState *pstate, RangeTblEntry *rte); static FuncExpr *make_clause_func_expr(char *function_name, Node *clause_information); +static void markRelsAsNulledBy(ParseState *pstate, Node *n, int jindex); + /* for VLE support */ static ParseNamespaceItem *transform_RangeFunction(cypher_parsestate *cpstate, RangeFunction *r); @@ -2472,8 +2475,17 @@ static void get_res_cols(ParseState *pstate, ParseNamespaceItem *l_pnsi, if (var == NULL) { + Var *v; + + /* + * Each join (left) RTE's Var, that references a column of the + * right RTE, needs to be marked 'nullable'. + */ + v = lfirst(r_lvar); + markNullableIfNeeded(pstate, v); + colnames = lappend(colnames, lfirst(r_lname)); - colvars = lappend(colvars, lfirst(r_lvar)); + colvars = lappend(colvars, v); } } @@ -2522,6 +2534,13 @@ static RangeTblEntry *transform_cypher_optional_match_clause(cypher_parsestate * j->rarg = transform_clause_for_join(cpstate, clause, &r_rte, &r_nsitem, r_alias); + /* + * Since this is a left join, we need to mark j->rarg as it may potentially + * emit NULL. The jindex argument holds rtindex of the join's RTE, which is + * created right after j->arg's RTE in this case. + */ + markRelsAsNulledBy(pstate, j->rarg, r_nsitem->p_rtindex + 1); + // we are done transform the lateral left join pstate->p_lateral_active = false; @@ -6377,6 +6396,13 @@ transform_merge_make_lateral_join(cypher_parsestate *cpstate, Query *query, j->rarg = transform_clause_for_join(cpstate, isolated_merge_clause, &r_rte, &r_nsitem, r_alias); + /* + * Since this is a left join, we need to mark j->rarg as it may potentially + * emit NULL. The jindex argument holds rtindex of the join's RTE, which is + * created right after j->arg's RTE in this case. + */ + markRelsAsNulledBy(pstate, j->rarg, r_nsitem->p_rtindex + 1); + // deactivate the lateral flag pstate->p_lateral_active = false; @@ -7095,6 +7121,50 @@ static FuncExpr *make_clause_func_expr(char *function_name, return func_expr; } +/* + * This function is borrowed from PG version 16.1. + * + * It is used in transformations involving left join in Optional Match and + * Merge in a similar way PG16's transformFromClauseItem() uses it. + */ +static void markRelsAsNulledBy(ParseState *pstate, Node *n, int jindex) +{ + int varno; + ListCell *lc; + + /* Note: we can't see FromExpr here */ + if (IsA(n, RangeTblRef)) + { + varno = ((RangeTblRef *) n)->rtindex; + } + else if (IsA(n, JoinExpr)) + { + JoinExpr *j = (JoinExpr *) n; + + /* recurse to children */ + markRelsAsNulledBy(pstate, j->larg, jindex); + markRelsAsNulledBy(pstate, j->rarg, jindex); + varno = j->rtindex; + } + else + { + elog(ERROR, "unrecognized node type: %d", (int) nodeTag(n)); + varno = 0; /* keep compiler quiet */ + } + + /* + * Now add jindex to the p_nullingrels set for relation varno. Since we + * maintain the p_nullingrels list lazily, we might need to extend it to + * make the varno'th entry exist. + */ + while (list_length(pstate->p_nullingrels) < varno) + { + pstate->p_nullingrels = lappend(pstate->p_nullingrels, NULL); + } + lc = list_nth_cell(pstate->p_nullingrels, varno - 1); + lfirst(lc) = bms_add_member((Bitmapset *) lfirst(lc), jindex); +} + /* * Utility function that helps a clause add the information needed to * the query from the previous clause. diff --git a/src/backend/parser/cypher_expr.c b/src/backend/parser/cypher_expr.c index d3ced7116..cd19a5548 100644 --- a/src/backend/parser/cypher_expr.c +++ b/src/backend/parser/cypher_expr.c @@ -249,7 +249,8 @@ static Node *transform_A_Const(cypher_parsestate *cpstate, A_Const *ac) } else { - float8 f = float8in_internal(n, NULL, "double precision", n, NULL); + float8 f = float8in_internal(n, NULL, "double precision", n, + NULL); d = float_to_agtype(f); } diff --git a/src/backend/parser/cypher_item.c b/src/backend/parser/cypher_item.c index 6e489fc5b..d5d088761 100644 --- a/src/backend/parser/cypher_item.c +++ b/src/backend/parser/cypher_item.c @@ -40,7 +40,8 @@ static List *ExpandAllTables(ParseState *pstate, int location); static List *expand_pnsi_attrs(ParseState *pstate, ParseNamespaceItem *pnsi, - int sublevels_up, bool require_col_privs, int location); + int sublevels_up, bool require_col_privs, + int location); // see transformTargetEntry() TargetEntry *transform_cypher_item(cypher_parsestate *cpstate, Node *node, @@ -161,10 +162,8 @@ static List *ExpandAllTables(ParseState *pstate, int location) /* Remember we found a p_cols_visible item */ found_table = true; - target = list_concat(target, expand_pnsi_attrs(pstate, - nsitem, - 0, - true, location)); + target = list_concat(target, expand_pnsi_attrs(pstate, nsitem, 0, true, + location)); } /* Check for "RETURN *;" */ @@ -181,7 +180,8 @@ static List *ExpandAllTables(ParseState *pstate, int location) * Modified to exclude hidden variables and aliases in RETURN * */ static List *expand_pnsi_attrs(ParseState *pstate, ParseNamespaceItem *pnsi, - int sublevels_up, bool require_col_privs, int location) + int sublevels_up, bool require_col_privs, + int location) { RangeTblEntry *rte = pnsi->p_rte; RTEPermissionInfo *perminfo = pnsi->p_perminfo; @@ -190,7 +190,7 @@ static List *expand_pnsi_attrs(ParseState *pstate, ParseNamespaceItem *pnsi, List *te_list = NIL; int var_prefix_len = strlen(AGE_DEFAULT_VARNAME_PREFIX); int alias_prefix_len = strlen(AGE_DEFAULT_ALIAS_PREFIX); - + vars = expandNSItemVars(pstate, pnsi, sublevels_up, location, &names); /* diff --git a/src/backend/parser/cypher_parse_agg.c b/src/backend/parser/cypher_parse_agg.c index 284a07e60..cd743fcc4 100644 --- a/src/backend/parser/cypher_parse_agg.c +++ b/src/backend/parser/cypher_parse_agg.c @@ -236,7 +236,9 @@ void parse_check_aggregates(ParseState *pstate, Query *qry) finalize_grouping_exprs(clause, pstate, qry, groupClauses, root, have_non_var_grouping); if (hasJoinRTEs) + { clause = flatten_join_alias_vars(root, qry, clause); + } check_ungrouped_columns(clause, pstate, qry, groupClauses, groupClauseCommonVars, have_non_var_grouping, &func_grouped_rels); @@ -245,7 +247,9 @@ void parse_check_aggregates(ParseState *pstate, Query *qry) finalize_grouping_exprs(clause, pstate, qry, groupClauses, root, have_non_var_grouping); if (hasJoinRTEs) + { clause = flatten_join_alias_vars(root, qry, clause); + } check_ungrouped_columns(clause, pstate, qry, groupClauses, groupClauseCommonVars, have_non_var_grouping, &func_grouped_rels); @@ -254,10 +258,12 @@ void parse_check_aggregates(ParseState *pstate, Query *qry) * Per spec, aggregates can't appear in a recursive term. */ if (pstate->p_hasAggs && hasSelfRefRTEs) + { ereport(ERROR, (errcode(ERRCODE_INVALID_RECURSION), errmsg("aggregate functions are not allowed in a recursive query's recursive term"), parser_errposition(pstate, locate_agg_of_level((Node *) qry, 0)))); + } } /* @@ -562,7 +568,11 @@ static bool finalize_grouping_exprs_walker(Node *node, Index ref = 0; if (context->root) - expr = flatten_join_alias_vars(context-> root, (Query*)context->root, expr); + { + expr = flatten_join_alias_vars(context->root, + (Query *)context->root, + expr); + } /* * Each expression must match a grouping entry at the current diff --git a/src/backend/utils/adt/agtype.c b/src/backend/utils/adt/agtype.c index 7751f2306..18b9a6abe 100644 --- a/src/backend/utils/adt/agtype.c +++ b/src/backend/utils/adt/agtype.c @@ -4277,8 +4277,11 @@ Datum agtype_hash_cmp(PG_FUNCTION_ARGS) agtype_value *r; uint64 seed = 0xF0F0F0F0; + /* this function returns INTEGER which is 32 bits */ if (PG_ARGISNULL(0)) - PG_RETURN_INT64(0); + { + PG_RETURN_INT32(0); + } agt = AG_GET_ARG_AGTYPE_P(0); @@ -4301,7 +4304,7 @@ Datum agtype_hash_cmp(PG_FUNCTION_ARGS) seed = LEFT_ROTATE(seed, 1); } - PG_RETURN_INT64(hash); + PG_RETURN_INT32(hash); } // Comparison function for btree Indexes @@ -4312,18 +4315,25 @@ Datum agtype_btree_cmp(PG_FUNCTION_ARGS) agtype *agtype_lhs; agtype *agtype_rhs; + /* this function returns INTEGER which is 32bits */ if (PG_ARGISNULL(0) && PG_ARGISNULL(1)) - PG_RETURN_INT16(0); + { + PG_RETURN_INT32(0); + } else if (PG_ARGISNULL(0)) - PG_RETURN_INT16(1); + { + PG_RETURN_INT32(1); + } else if (PG_ARGISNULL(1)) - PG_RETURN_INT16(-1); + { + PG_RETURN_INT32(-1); + } agtype_lhs = AG_GET_ARG_AGTYPE_P(0); agtype_rhs = AG_GET_ARG_AGTYPE_P(1); - PG_RETURN_INT64(compare_agtype_containers_orderability(&agtype_lhs->root, - &agtype_rhs->root)); + PG_RETURN_INT32(compare_agtype_containers_orderability(&agtype_lhs->root, + &agtype_rhs->root)); } PG_FUNCTION_INFO_V1(agtype_typecast_numeric);