diff --git a/README.md b/README.md index 60b3347cb..821b968a4 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@   - +   diff --git a/RELEASE b/RELEASE index 329a93076..66da63878 100644 --- a/RELEASE +++ b/RELEASE @@ -15,7 +15,7 @@ # specific language governing permissions and limitations # under the License. -Release Notes for Apache AGE release 0.0.0 for PG 14 +Release Notes for Apache AGE release 0.0.0 for PG 15 Apache AGE 0.0.0 - Release Notes diff --git a/docker/Dockerfile b/docker/Dockerfile index c30d69313..45298538e 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -16,17 +16,29 @@ # limitations under the License. # -FROM postgres:14 +FROM postgres:15 -RUN apt-get update -RUN apt-get install --assume-yes --no-install-recommends --no-install-suggests \ - bison \ - build-essential \ - flex \ - postgresql-server-dev-14 +RUN apt-get update \ + && apt-get install -y --no-install-recommends --no-install-suggests \ + bison \ + build-essential \ + flex \ + postgresql-server-dev-15 \ + locales + +ENV LANG=en_US.UTF-8 +ENV LC_COLLATE=en_US.UTF-8 +ENV LC_CTYPE=en_US.UTF-8 + +RUN echo "en_US.UTF-8 UTF-8" > /etc/locale.gen \ + && locale-gen \ + && update-locale LANG=en_US.UTF-8 COPY . /age -RUN cd /age && make install + +WORKDIR /age + +RUN make && make install COPY docker/docker-entrypoint-initdb.d/00-create-extension-age.sql /docker-entrypoint-initdb.d/00-create-extension-age.sql diff --git a/docker/Dockerfile.dev b/docker/Dockerfile.dev index 5e47d49b7..8d5c0000c 100644 --- a/docker/Dockerfile.dev +++ b/docker/Dockerfile.dev @@ -17,15 +17,23 @@ # -FROM postgres:14-buster +FROM postgres:14 RUN apt-get update RUN apt-get install --assume-yes --no-install-recommends --no-install-suggests \ bison \ build-essential \ flex \ - postgresql-server-dev-14 + postgresql-server-dev-15 \ + locales +ENV LANG=en_US.UTF-8 +ENV LC_COLLATE=en_US.UTF-8 +ENV LC_CTYPE=en_US.UTF-8 + +RUN echo "en_US.UTF-8 UTF-8" > /etc/locale.gen \ + && locale-gen \ + && update-locale LANG=en_US.UTF-8 COPY . /age # Set current working directory to /age/ and build. diff --git a/src/backend/catalog/ag_catalog.c b/src/backend/catalog/ag_catalog.c index f7ed249ce..60a576a9e 100644 --- a/src/backend/catalog/ag_catalog.c +++ b/src/backend/catalog/ag_catalog.c @@ -137,8 +137,8 @@ static bool is_age_drop(PlannedStmt *pstmt) if (IsA(obj, String)) { - Value *val = (Value *)obj; - char *str = val->val.str; + String *val = (String *)obj; + char *str = val->sval; if (!pg_strcasecmp(str, "age")) return true; diff --git a/src/backend/commands/graph_commands.c b/src/backend/commands/graph_commands.c index 7df40b948..2d70e65a5 100644 --- a/src/backend/commands/graph_commands.c +++ b/src/backend/commands/graph_commands.c @@ -148,7 +148,7 @@ static Oid create_schema_for_graph(const Name graph_name) integer = SystemTypeName("int4"); data_type = makeDefElem("as", (Node *)integer, -1); maxvalue = makeDefElem("maxvalue", (Node *)makeInteger(LABEL_ID_MAX), -1); - cycle = makeDefElem("cycle", (Node *)makeInteger(true), -1); + cycle = makeDefElem("cycle", (Node *)makeBoolean(true), -1); seq_stmt->options = list_make3(data_type, maxvalue, cycle); seq_stmt->ownerId = InvalidOid; seq_stmt->for_identity = false; @@ -198,7 +198,7 @@ Datum drop_graph(PG_FUNCTION_ARGS) static void drop_schema_for_graph(char *graph_name_str, const bool cascade) { DropStmt *drop_stmt; - Value *schema_name; + String *schema_name; List *label_id_seq_name; DropBehavior behavior; diff --git a/src/backend/commands/label_commands.c b/src/backend/commands/label_commands.c index 6eb991da4..b2e078702 100644 --- a/src/backend/commands/label_commands.c +++ b/src/backend/commands/label_commands.c @@ -516,12 +516,12 @@ static FuncCall *build_id_default_func_expr(char *graph_name, char *label_name, label_id_func_name = list_make2(makeString("ag_catalog"), makeString("_label_id")); graph_name_const = makeNode(A_Const); - graph_name_const->val.type = T_String; - graph_name_const->val.val.str = graph_name; + graph_name_const->val.sval.type = T_String; + graph_name_const->val.sval.sval = graph_name; graph_name_const->location = -1; label_name_const = makeNode(A_Const); - label_name_const->val.type = T_String; - label_name_const->val.val.str = label_name; + label_name_const->val.sval.type = T_String; + label_name_const->val.sval.sval = label_name; label_name_const->location = -1; label_id_func_args = list_make2(graph_name_const, label_name_const); label_id_func = makeFuncCall(label_id_func_name, label_id_func_args, COERCE_SQL_SYNTAX, -1); @@ -530,8 +530,8 @@ static FuncCall *build_id_default_func_expr(char *graph_name, char *label_name, nextval_func_name = SystemFuncName("nextval"); qualified_seq_name = quote_qualified_identifier(schema_name, seq_name); qualified_seq_name_const = makeNode(A_Const); - qualified_seq_name_const->val.type = T_String; - qualified_seq_name_const->val.val.str = qualified_seq_name; + qualified_seq_name_const->val.sval.type = T_String; + qualified_seq_name_const->val.sval.sval = qualified_seq_name; qualified_seq_name_const->location = -1; regclass_cast = makeNode(TypeCast); regclass_cast->typeName = SystemTypeName("regclass"); diff --git a/src/backend/executor/cypher_delete.c b/src/backend/executor/cypher_delete.c index 68fafae77..795d4c0ec 100644 --- a/src/backend/executor/cypher_delete.c +++ b/src/backend/executor/cypher_delete.c @@ -377,13 +377,13 @@ static void process_delete_list(CustomScanState *node) ResultRelInfo *resultRelInfo; HeapTuple heap_tuple; char *label_name; - Value *pos; + Integer *pos; int entity_position; item = lfirst(lc); pos = item->entity_position; - entity_position = pos->val.ival; + entity_position = pos->ival; /* skip if the entity is null */ if (scanTupleSlot->tts_isnull[entity_position - 1]) diff --git a/src/backend/parser/cypher_analyze.c b/src/backend/parser/cypher_analyze.c index f1c481c85..a154960c1 100644 --- a/src/backend/parser/cypher_analyze.c +++ b/src/backend/parser/cypher_analyze.c @@ -756,11 +756,19 @@ static Query *analyze_cypher_and_coerce(List *stmt, RangeTblFunction *rtfunc, pnsi = addRangeTableEntryForSubquery(pstate, subquery, makeAlias("_", NIL), lateral, true); + rtindex = list_length(pstate->p_rtable); Assert(rtindex == 1); // rte is the only RangeTblEntry in pstate + if (rtindex !=1 ) + { + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("invalid value for rtindex"))); + } + addNSItemToQuery(pstate, pnsi, true, true, true); - query->targetList = expandNSItemAttrs(pstate, pnsi, 0, -1); + query->targetList = expandNSItemAttrs(pstate, pnsi, 0, true, -1); markTargetListOrigins(pstate, query->targetList); diff --git a/src/backend/parser/cypher_clause.c b/src/backend/parser/cypher_clause.c index cb1c48bf0..ba74db062 100644 --- a/src/backend/parser/cypher_clause.c +++ b/src/backend/parser/cypher_clause.c @@ -1334,7 +1334,14 @@ static Query *transform_cypher_unwind(cypher_parsestate *cpstate, pnsi = transform_prev_cypher_clause(cpstate, clause->prev, true); rtindex = list_length(pstate->p_rtable); Assert(rtindex == 1); // rte is the first RangeTblEntry in pstate - query->targetList = expandNSItemAttrs(pstate, pnsi, 0, -1); + if (rtindex != 1) + { + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("invalid value for rtindex"))); + } + + query->targetList = expandNSItemAttrs(pstate, pnsi, 0, true, -1); } target_syntax_loc = exprLocation((const Node *) self->target); @@ -1393,7 +1400,8 @@ static List *transform_cypher_delete_item_list(cypher_parsestate *cpstate, { Node *expr = lfirst(lc); ColumnRef *col; - Value *val, *pos; + String *val; + Integer *pos; int resno; cypher_delete_item *item = make_ag_node(cypher_delete_item); @@ -1420,13 +1428,13 @@ static List *transform_cypher_delete_item_list(cypher_parsestate *cpstate, (errmsg_internal("unexpected Node for cypher_clause"))); } - resno = get_target_entry_resno(query->targetList, val->val.str); + resno = get_target_entry_resno(query->targetList, val->sval); if (resno == -1) { ereport(ERROR, (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), errmsg("undefined reference to variable %s in DELETE clause", - val->val.str), + val->sval), parser_errposition(pstate, col->location))); } @@ -1434,7 +1442,7 @@ static List *transform_cypher_delete_item_list(cypher_parsestate *cpstate, pos = makeInteger(resno); - item->var_name = val->val.str; + item->var_name = val->sval; item->entity_position = pos; items = lappend(items, item); @@ -1532,7 +1540,7 @@ cypher_update_information *transform_cypher_remove_item_list( ColumnRef *ref; A_Indirection *ind; char *variable_name, *property_name; - Value *property_node, *variable_node; + String *property_node, *variable_node; item = make_ag_node(cypher_update_item); @@ -1578,7 +1586,7 @@ cypher_update_information *transform_cypher_remove_item_list( variable_node = linitial(ref->fields); - variable_name = variable_node->val.str; + variable_name = variable_node->sval; item->var_name = variable_name; item->entity_position = get_target_entry_resno(query->targetList, @@ -1613,7 +1621,7 @@ cypher_update_information *transform_cypher_remove_item_list( errmsg("REMOVE clause expects a property name"), parser_errposition(pstate, set_item->location))); } - property_name = property_node->val.str; + property_name = property_node->sval; item->prop_name = property_name; info->set_items = lappend(info->set_items, item); @@ -1641,7 +1649,7 @@ cypher_update_information *transform_cypher_set_item_list( ColumnRef *ref; A_Indirection *ind; char *variable_name, *property_name; - Value *property_node, *variable_node; + String *property_node, *variable_node; int is_entire_prop_update = 0; // true if a map is assigned to variable // LHS of set_item must be a variable or an indirection. @@ -1741,7 +1749,7 @@ cypher_update_information *transform_cypher_set_item_list( parser_errposition(pstate, set_item->location))); } - property_name = property_node->val.str; + property_name = property_node->sval; item->prop_name = property_name; } @@ -1755,7 +1763,7 @@ cypher_update_information *transform_cypher_set_item_list( parser_errposition(pstate, set_item->location))); } - variable_name = variable_node->val.str; + variable_name = variable_node->sval; item->var_name = variable_name; item->entity_position = get_target_entry_resno(query->targetList, @@ -2311,13 +2319,19 @@ static Query *transform_cypher_clause_with_where(cypher_parsestate *cpstate, Assert(pnsi != NULL); rtindex = list_length(pstate->p_rtable); Assert(rtindex == 1); // rte is the only RangeTblEntry in pstate + if (rtindex != 1) + { + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("invalid value for rtindex"))); + } /* * add all the target entries in pnsi to the current target list to pass * all the variables that are introduced in the previous clause to the * next clause */ - query->targetList = expandNSItemAttrs(pstate, pnsi, 0, -1); + query->targetList = expandNSItemAttrs(pstate, pnsi, 0, true, -1); markTargetListOrigins(pstate, query->targetList); @@ -2585,6 +2599,12 @@ static Query *transform_cypher_match_pattern(cypher_parsestate *cpstate, rte = pnsi->p_rte; rtindex = list_length(pstate->p_rtable); Assert(rtindex == 1); // rte is the first RangeTblEntry in pstate + if (rtindex != 1) + { + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("invalid value for rtindex"))); + } /* * add all the target entries in rte to the current target list to pass @@ -2592,7 +2612,7 @@ static Query *transform_cypher_match_pattern(cypher_parsestate *cpstate, * next clause */ pnsi = get_namespace_item(pstate, rte); - query->targetList = expandNSItemAttrs(pstate, pnsi, 0, -1); + query->targetList = expandNSItemAttrs(pstate, pnsi, 0, true, -1); } transform_match_pattern(cpstate, query, self->pattern, where); @@ -3030,7 +3050,7 @@ static FuncCall *prevent_duplicate_edges(cypher_parsestate *cpstate, List *edges = NIL; ListCell *lc; List *qualified_function_name; - Value *ag_catalog, *edge_fn; + String *ag_catalog, *edge_fn; ag_catalog = makeString("ag_catalog"); edge_fn = makeString("_ag_enforce_edge_uniqueness"); @@ -3135,8 +3155,8 @@ static List *make_join_condition_for_edge(cypher_parsestate *cpstate, { Node *left_id = NULL; Node *right_id = NULL; - Value *ag_catalog = makeString("ag_catalog"); - Value *func_name; + String *ag_catalog = makeString("ag_catalog"); + String *func_name; List *qualified_func_name; List *args = NIL; List *quals = NIL; @@ -3186,7 +3206,7 @@ static List *make_join_condition_for_edge(cypher_parsestate *cpstate, prev_edge->type == ENT_VLE_EDGE) { List *qualified_name, *args; - Value *match_qual; + String *match_qual; FuncCall *fc; match_qual = makeString("age_match_two_vle_edges"); @@ -3329,8 +3349,8 @@ static List *make_join_condition_for_edge(cypher_parsestate *cpstate, static Node *make_type_cast_to_agtype(Node *arg) { TypeCast *n = makeNode(TypeCast); - Value *ag_catalog = makeString("ag_catalog"); - Value *agtype_str = makeString("agtype"); + String *ag_catalog = makeString("ag_catalog"); + String *agtype_str = makeString("agtype"); List *qualified_name = list_make2(ag_catalog, agtype_str); n->arg = arg; @@ -3347,8 +3367,8 @@ static Node *make_bool_a_const(bool state) { A_Const *n = makeNode(A_Const); - n->val.type = T_String; - n->val.val.str = (state ? "true" : "false"); + n->val.sval.type = T_String; + n->val.sval.sval = (state ? "true" : "false"); n->location = -1; // typecast to agtype @@ -3397,7 +3417,7 @@ static List *join_to_entity(cypher_parsestate *cpstate, else if (entity->type == ENT_VLE_EDGE) { List *qualified_name, *args; - Value *ag_catalog, *match_qual; + String *ag_catalog, *match_qual; bool is_left_side; FuncCall *fc; @@ -3520,12 +3540,12 @@ static A_Expr *filter_vertices_on_label_id(cypher_parsestate *cpstate, cpstate->graph_oid); A_Const *n; FuncCall *fc; - Value *ag_catalog, *extract_label_id; + String *ag_catalog, *extract_label_id; int32 label_id = lcd->id; n = makeNode(A_Const); - n->val.type = T_Integer; - n->val.val.ival = label_id; + n->val.ival.type = T_Integer; + n->val.ival.ival = label_id; n->location = -1; ag_catalog = makeString("ag_catalog"); @@ -6775,10 +6795,16 @@ static void handle_prev_clause(cypher_parsestate *cpstate, Query *query, if (first_rte) { Assert(rtindex == 1); + if (rtindex != 1) + { + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("invalid value for rtindex"))); + } } // add all the rte's attributes to the current queries targetlist - query->targetList = expandNSItemAttrs(pstate, pnsi, 0, -1); + query->targetList = expandNSItemAttrs(pstate, pnsi, 0, true, -1); } ParseNamespaceItem *find_pnsi(cypher_parsestate *cpstate, char *varname) diff --git a/src/backend/parser/cypher_expr.c b/src/backend/parser/cypher_expr.c index a54652303..646ac9e2f 100644 --- a/src/backend/parser/cypher_expr.c +++ b/src/backend/parser/cypher_expr.c @@ -42,7 +42,6 @@ #include "parser/parse_relation.h" #include "utils/builtins.h" #include "utils/float.h" -#include "utils/int8.h" #include "utils/lsyscache.h" #include "utils/syscache.h" @@ -211,23 +210,27 @@ static Node *transform_A_Const(cypher_parsestate *cpstate, A_Const *ac) { ParseState *pstate = (ParseState *)cpstate; ParseCallbackState pcbstate; - Value *v = &ac->val; + Datum d = (Datum)0; bool is_null = false; Const *c; setup_parser_errposition_callback(&pcbstate, pstate, ac->location); - switch (nodeTag(v)) + switch (nodeTag(&ac->val)) { case T_Integer: - d = integer_to_agtype((int64)intVal(v)); + d = integer_to_agtype((int64)intVal(&ac->val)); break; case T_Float: { - char *n = strVal(v); + char *n = ac->val.sval.sval; + char *endptr; int64 i; + errno = 0; + + i = strtoi64(ac->val.fval.fval, &endptr, 10); - if (scanint8(n, true, &i)) + if (errno == 0 && *endptr == '\0') { d = integer_to_agtype(i); } @@ -240,15 +243,19 @@ static Node *transform_A_Const(cypher_parsestate *cpstate, A_Const *ac) } break; case T_String: - d = string_to_agtype(strVal(v)); + d = string_to_agtype(strVal(&ac->val)); break; - case T_Null: - is_null = true; + case T_Boolean: + d = boolean_to_agtype(boolVal(&ac->val)); break; default: - ereport(ERROR, - (errmsg_internal("unrecognized node type: %d", nodeTag(v)))); - return NULL; + if (ac->isnull) { + is_null = true; + } else { + ereport(ERROR, + (errmsg_internal("unrecognized node type: %d", nodeTag(&ac->val)))); + return NULL; + } } cancel_parser_errposition_callback(&pcbstate); @@ -865,7 +872,7 @@ static Node *transform_A_Indirection(cypher_parsestate *cpstate, if (!indices->lidx) { A_Const *n = makeNode(A_Const); - n->val.type = T_Null; + n->isnull = true; n->location = -1; node = transform_cypher_expr_recurse(cpstate, (Node *)n); } @@ -879,7 +886,7 @@ static Node *transform_A_Indirection(cypher_parsestate *cpstate, if (!indices->uidx) { A_Const *n = makeNode(A_Const); - n->val.type = T_Null; + n->isnull = true; n->location = -1; node = transform_cypher_expr_recurse(cpstate, (Node *)n); } @@ -1092,7 +1099,7 @@ static Node *transform_FuncCall(cypher_parsestate *cpstate, FuncCall *fn) if (list_length(fn->funcname) == 1) { /* get the name, size, and the ag name allocated */ - char *name = ((Value*)linitial(fn->funcname))->val.str; + char *name = ((String*)linitial(fn->funcname))->sval; int pnlen = strlen(name); char *ag_name = palloc(pnlen + 5); int i; @@ -1286,7 +1293,7 @@ static Node *transform_CaseExpr(cypher_parsestate *cpstate, CaseExpr { A_Const *n = makeNode(A_Const); - n->val.type = T_Null; + n->isnull = true; n->location = -1; defresult = (Node *) n; } diff --git a/src/backend/parser/cypher_gram.y b/src/backend/parser/cypher_gram.y index 26908122c..846e02010 100644 --- a/src/backend/parser/cypher_gram.y +++ b/src/backend/parser/cypher_gram.y @@ -200,7 +200,7 @@ static Node *make_not_expr(Node *expr, int location); // arithmetic operators static Node *do_negate(Node *n, int location); -static void do_negate_float(Value *v); +static void do_negate_float(Float *v); // indirection static Node *append_indirection(Node *expr, Node *selector); @@ -349,7 +349,7 @@ call_stmt: FuncCall *fc = (FuncCall*)$4; ColumnRef *cr = (ColumnRef*)$2; List *fields = cr->fields; - Value *string = linitial(fields); + String *string = linitial(fields); /* * A function can only be qualified with a single schema. So, we @@ -396,7 +396,7 @@ call_stmt: FuncCall *fc = (FuncCall*)$4; ColumnRef *cr = (ColumnRef*)$2; List *fields = cr->fields; - Value *string = linitial(fields); + String *string = linitial(fields); /* * A function can only be qualified with a single schema. So, we @@ -584,7 +584,7 @@ cypher_varlen_opt: A_Const *lidx = (A_Const *) n->lidx; A_Const *uidx = (A_Const *) n->uidx; - if (lidx->val.val.ival > uidx->val.val.ival) + if (lidx->val.ival.ival > uidx->val.ival.ival) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("invalid range"), ag_scanner_errposition(@2, scanner))); @@ -1466,7 +1466,7 @@ expr: { ColumnRef *cr = (ColumnRef*)$3; List *fields = cr->fields; - Value *string = linitial(fields); + String *string = linitial(fields); $$ = append_indirection($1, (Node*)string); } @@ -1481,7 +1481,7 @@ expr: FuncCall *fc = (FuncCall*)$3; ColumnRef *cr = (ColumnRef*)$1; List *fields = cr->fields; - Value *string = linitial(fields); + String *string = linitial(fields); /* * A function can only be qualified with a single schema. So, we @@ -1505,7 +1505,7 @@ expr: { ColumnRef *cr = (ColumnRef*)$3; List *fields = cr->fields; - Value *string = linitial(fields); + String *string = linitial(fields); $$ = append_indirection($1, (Node*)string); } @@ -2008,14 +2008,14 @@ static Node *do_negate(Node *n, int location) // report the constant's location as that of the '-' sign c->location = location; - if (c->val.type == T_Integer) + if (c->val.ival.type == T_Integer) { - c->val.val.ival = -c->val.val.ival; + c->val.ival.ival = -c->val.ival.ival; return n; } - else if (c->val.type == T_Float) + else if (c->val.fval.type == T_Float) { - do_negate_float(&c->val); + do_negate_float(&c->val.fval); return n; } } @@ -2023,14 +2023,16 @@ static Node *do_negate(Node *n, int location) return (Node *)makeSimpleA_Expr(AEXPR_OP, "-", NULL, n, location); } -static void do_negate_float(Value *v) +static void do_negate_float(Float *v) { - Assert(IsA(v, Float)); - - if (v->val.str[0] == '-') - v->val.str = v->val.str + 1; // just strip the '-' - else - v->val.str = psprintf("-%s", v->val.str); + char *oldval = v->fval; + + if (*oldval == '+') + oldval++; + if (*oldval == '-') + v->fval = oldval+1; /* just strip the '-' */ + else + v->fval = psprintf("-%s", oldval); } /* @@ -2064,60 +2066,56 @@ static Node *append_indirection(Node *expr, Node *selector) static Node *make_int_const(int i, int location) { - A_Const *n; + A_Const *n = makeNode(A_Const); - n = makeNode(A_Const); - n->val.type = T_Integer; - n->val.val.ival = i; + n->val.ival.type = T_Integer; + n->val.ival.ival = i; n->location = location; - return (Node *)n; + return (Node *) n; } static Node *make_float_const(char *s, int location) { - A_Const *n; + A_Const *n = makeNode(A_Const); - n = makeNode(A_Const); - n->val.type = T_Float; - n->val.val.str = s; + n->val.fval.type = T_Float; + n->val.fval.fval = s; n->location = location; - return (Node *)n; + return (Node *) n; } static Node *make_string_const(char *s, int location) { - A_Const *n; + A_Const *n = makeNode(A_Const); - n = makeNode(A_Const); - n->val.type = T_String; - n->val.val.str = s; + n->val.sval.type = T_String; + n->val.sval.sval = s; n->location = location; - return (Node *)n; + return (Node *) n; } static Node *make_bool_const(bool b, int location) { - cypher_bool_const *n; + A_Const *n = makeNode(A_Const); - n = make_ag_node(cypher_bool_const); - n->boolean = b; + n->val.boolval.type = T_Boolean; + n->val.boolval.boolval = b; n->location = location; - return (Node *)n; + return (Node *) n; } static Node *make_null_const(int location) { - A_Const *n; - - n = makeNode(A_Const); - n->val.type = T_Null; + A_Const *n = makeNode(A_Const); + + n->isnull = true; n->location = location; - return (Node *)n; + return (Node *) n; } /* @@ -2149,7 +2147,7 @@ static Node *make_function_expr(List *func_name, List *exprs, int location) char *name; /* get the name of the function */ - name = ((Value*)linitial(func_name))->val.str; + name = ((String*)linitial(func_name))->sval; /* * Check for openCypher functions that are directly mapped to PG @@ -2247,7 +2245,7 @@ static Node *make_set_op(SetOperation op, bool all_or_distinct, List *larg, /* check if A_Expr is a comparison expression */ static bool is_A_Expr_a_comparison_operation(A_Expr *a) { - Value *v = NULL; + String *v = NULL; char *opr_name = NULL; /* we don't support qualified comparison operators */ @@ -2263,7 +2261,7 @@ static bool is_A_Expr_a_comparison_operation(A_Expr *a) Assert(v->type == T_String); /* get the string value */ - opr_name = v->val.str; + opr_name = v->sval; /* verify it is a comparison operation */ if (strcmp(opr_name, "<") == 0) diff --git a/src/backend/utils/adt/agtype.c b/src/backend/utils/adt/agtype.c index 376137aba..242a951e2 100644 --- a/src/backend/utils/adt/agtype.c +++ b/src/backend/utils/adt/agtype.c @@ -54,7 +54,6 @@ #include "utils/builtins.h" #include "utils/float.h" #include "utils/fmgroids.h" -#include "utils/int8.h" #include "utils/lsyscache.h" #include "utils/rel.h" #include "utils/snapmgr.h" @@ -182,7 +181,7 @@ static int extract_variadic_args_min(FunctionCallInfo fcinfo, int variadic_start, bool convert_unknown, Datum **args, Oid **types, bool **nulls, int min_num_args); -static agtype_value* agtype_build_map_as_agtype_value(FunctionCallInfo fcinfo); +static agtype_value *agtype_build_map_as_agtype_value(FunctionCallInfo fcinfo); agtype_value *agtype_composite_to_agtype_value_binary(agtype *a); /* global storage of OID for agtype and _agtype */ @@ -959,7 +958,7 @@ static void agtype_in_scalar(void *pstate, char *token, case AGTYPE_TOKEN_INTEGER: Assert(token != NULL); v.type = AGTV_INTEGER; - scanint8(token, false, &v.val.int_value); + v.val.int_value = pg_strtoint64(token); break; case AGTYPE_TOKEN_FLOAT: Assert(token != NULL); @@ -2364,7 +2363,7 @@ Datum make_edge(Datum id, Datum startid, Datum endid, Datum label, properties); } -static agtype_value* agtype_build_map_as_agtype_value(FunctionCallInfo fcinfo) +static agtype_value *agtype_build_map_as_agtype_value(FunctionCallInfo fcinfo) { int nargs; int i; @@ -2377,7 +2376,9 @@ static agtype_value* agtype_build_map_as_agtype_value(FunctionCallInfo fcinfo) nargs = extract_variadic_args(fcinfo, 0, true, &args, &types, &nulls); if (nargs < 0) - PG_RETURN_NULL(); + { + return NULL; + } if (nargs % 2 != 0) { @@ -2420,7 +2421,14 @@ PG_FUNCTION_INFO_V1(agtype_build_map); */ Datum agtype_build_map(PG_FUNCTION_ARGS) { - agtype_value *result= agtype_build_map_as_agtype_value(fcinfo); + agtype_value *result = NULL; + + result = agtype_build_map_as_agtype_value(fcinfo); + if (result == NULL) + { + PG_RETURN_NULL(); + } + PG_RETURN_POINTER(agtype_value_to_agtype(result)); } @@ -2448,8 +2456,16 @@ PG_FUNCTION_INFO_V1(agtype_build_map_nonull); */ Datum agtype_build_map_nonull(PG_FUNCTION_ARGS) { - agtype_value *result= agtype_build_map_as_agtype_value(fcinfo); + agtype_value *result = NULL; + + result = agtype_build_map_as_agtype_value(fcinfo); + if (result == NULL) + { + PG_RETURN_NULL(); + } + remove_null_from_agtype_object(result); + PG_RETURN_POINTER(agtype_value_to_agtype(result)); } @@ -5446,18 +5462,26 @@ Datum age_tointeger(PG_FUNCTION_ARGS) if (type != AGTYPEOID) { if (type == INT2OID) + { result = (int64) DatumGetInt16(arg); + } else if (type == INT4OID) + { result = (int64) DatumGetInt32(arg); + } else if (type == INT8OID) + { result = (int64) DatumGetInt64(arg); + } else if (type == FLOAT4OID) { float4 f = DatumGetFloat4(arg); if (isnan(f) || isinf(f) || - f < PG_INT64_MIN || f > PG_INT64_MAX) + f < (float4)PG_INT64_MIN || f > (float4)PG_INT64_MAX) + { PG_RETURN_NULL(); + } result = (int64) f; } @@ -5466,8 +5490,10 @@ Datum age_tointeger(PG_FUNCTION_ARGS) float8 f = DatumGetFloat8(arg); if (isnan(f) || isinf(f) || - f < PG_INT64_MIN || f > PG_INT64_MAX) + f < (float8)PG_INT64_MIN || f > (float8)PG_INT64_MAX) + { PG_RETURN_NULL(); + } result = (int64) f; } @@ -5479,25 +5505,36 @@ Datum age_tointeger(PG_FUNCTION_ARGS) numeric_float8_no_overflow, arg)); if (isnan(f) || isinf(f) || - f < PG_INT64_MIN || f > PG_INT64_MAX) + f < (float8)PG_INT64_MIN || f > (float8)PG_INT64_MAX) + { PG_RETURN_NULL(); + } result = (int64) f; } else if (type == CSTRINGOID || type == TEXTOID) { + char *endptr; if (type == CSTRINGOID) + { string = DatumGetCString(arg); + } else + { string = text_to_cstring(DatumGetTextPP(arg)); + } /* convert it if it is a regular integer string */ - is_valid = scanint8(string, true, &result); + result = strtoi64(string, &endptr, 10); + /* * If it isn't an integer string, try converting it as a float * string. */ - if (!is_valid) + result = float8in_internal_null(string, NULL, "double precision", + string, &is_valid); + + if (*endptr != '\0') { float f; @@ -5508,16 +5545,18 @@ Datum age_tointeger(PG_FUNCTION_ARGS) * return null. */ if (!is_valid || isnan(f) || isinf(f) || - f < PG_INT64_MIN || f > PG_INT64_MAX) + f < PG_INT64_MIN || f > (double)PG_INT64_MAX) PG_RETURN_NULL(); result = (int64) f; } } else + { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("toInteger() unsupported argument type %d", type))); + } } else { @@ -5537,11 +5576,13 @@ Datum age_tointeger(PG_FUNCTION_ARGS) result = agtv_value->val.int_value; else if (agtv_value->type == AGTV_FLOAT) { - float f = agtv_value->val.float_value; + float8 f = agtv_value->val.float_value; if (isnan(f) || isinf(f) || - f < PG_INT64_MIN || f > PG_INT64_MAX) + f < (float8)PG_INT64_MIN || f > (float8)PG_INT64_MAX) + { PG_RETURN_NULL(); + } result = (int64) f; } @@ -5554,25 +5595,29 @@ Datum age_tointeger(PG_FUNCTION_ARGS) numeric_float8_no_overflow, num)); if (isnan(f) || isinf(f) || - f < PG_INT64_MIN || f > PG_INT64_MAX) + f < (float8)PG_INT64_MIN || f > (float8)PG_INT64_MAX) + { PG_RETURN_NULL(); + } result = (int64) f; } else if (agtv_value->type == AGTV_STRING) { + char *endptr; /* we need a null terminated cstring */ string = strndup(agtv_value->val.string.val, agtv_value->val.string.len); /* convert it if it is a regular integer string */ - is_valid = scanint8(string, true, &result); + result = strtoi64(string, &endptr, 10); + /* * If it isn't an integer string, try converting it as a float * string. */ - if (!is_valid) + if (*endptr != '\0') { - float f; + float8 f; f = float8in_internal_null(string, NULL, "double precision", string, &is_valid); @@ -5582,18 +5627,24 @@ Datum age_tointeger(PG_FUNCTION_ARGS) * return null. */ if (!is_valid || isnan(f) || isinf(f) || - f < PG_INT64_MIN || f > PG_INT64_MAX) + f < (float8)PG_INT64_MIN || f > (float8)PG_INT64_MAX) + { PG_RETURN_NULL(); + } result = (int64) f; } else + { free(string); + } } else + { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("toInteger() unsupported argument agtype %d", agtv_value->type))); + } } /* build the result */ diff --git a/src/backend/utils/graph_generation.c b/src/backend/utils/graph_generation.c index 9b507e11a..0f58fbc36 100644 --- a/src/backend/utils/graph_generation.c +++ b/src/backend/utils/graph_generation.c @@ -83,7 +83,7 @@ Datum create_complete_graph(PG_FUNCTION_ARGS) int64 no_vertices; int64 i,j,vid = 1, eid, start_vid, end_vid; - Name vtx_label_name; + Name vtx_label_name = NULL; Name edge_label_name; int32 vtx_label_id; int32 edge_label_id; diff --git a/src/include/nodes/cypher_nodes.h b/src/include/nodes/cypher_nodes.h index 64318eb5d..0b2f65349 100644 --- a/src/include/nodes/cypher_nodes.h +++ b/src/include/nodes/cypher_nodes.h @@ -393,7 +393,7 @@ typedef struct cypher_delete_information typedef struct cypher_delete_item { ExtensibleNode extensible; - Value *entity_position; + Integer *entity_position; char *var_name; } cypher_delete_item;