/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include "postgres.h" #include "parser/cypher_transform_entity.h" // creates a transform entity transform_entity *make_transform_entity(cypher_parsestate *cpstate, enum transform_entity_type type, Node *node, Expr *expr) { transform_entity *entity; entity = palloc(sizeof(transform_entity)); entity->type = type; if (type == ENT_VERTEX) { entity->entity.node = (cypher_node *)node; } else if (entity->type == ENT_EDGE || entity->type == ENT_VLE_EDGE) { entity->entity.rel = (cypher_relationship *)node; } else if (entity->type == ENT_PATH) { entity->entity.path = (cypher_path *)node; } else { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("unknown entity type"))); } entity->declared_in_current_clause = true; entity->expr = expr; entity->in_join_tree = expr != NULL; return entity; } /* * Finds the transform_entity in the cypher_parstate for a the given name and * type. */ transform_entity *find_transform_entity(cypher_parsestate *cpstate, char *name, enum transform_entity_type type) { ListCell *lc; if (name == NULL) { return NULL; } foreach(lc, cpstate->entities) { transform_entity *entity = lfirst(lc); if (entity->type != type) { continue; } if (type == ENT_VERTEX) { if (entity->entity.node->name != NULL && !strcmp(entity->entity.node->name, name)) { return entity; } } else if (type == ENT_EDGE || type == ENT_VLE_EDGE) { if (entity->entity.rel->name != NULL && !strcmp(entity->entity.rel->name, name)) { return entity; } } else if (type == ENT_PATH) { if (entity->entity.path->var_name != NULL && !strcmp(entity->entity.path->var_name, name)) { return entity; } } } return NULL; } /* * Iterate through the cypher_parsestate's transform_entities and returns * the entity with name passed by name variable. */ transform_entity *find_variable(cypher_parsestate *cpstate, char *name) { ListCell *lc; /* while we have cypher_parsestates to check */ while (cpstate) { foreach (lc, cpstate->entities) { transform_entity *entity = lfirst(lc); char *entity_name = NULL; if (entity->type == ENT_VERTEX) { entity_name = entity->entity.node->name; } else if (entity->type == ENT_EDGE || entity->type == ENT_VLE_EDGE) { entity_name = entity->entity.rel->name; } else if (entity->type == ENT_PATH) { entity_name = entity->entity.path->var_name; } else { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("unknown entity type"))); } if (entity_name != NULL && !strcmp(name, entity_name)) { return entity; } } /* go up to the next parent parse state */ cpstate = (cypher_parsestate*)cpstate->pstate.parentParseState; } return NULL; } // helper function that extracts the name associated with the transform_entity. char *get_entity_name(transform_entity *entity) { if (entity->type == ENT_EDGE || entity->type == ENT_VLE_EDGE) { return entity->entity.rel->name; } else if (entity->type == ENT_VERTEX) { return entity->entity.node->name; } else if (entity->type == ENT_PATH) { return entity->entity.path->var_name; } else { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot get entity name from transform_entity type %i", entity->type))); } return NULL; } /* * Returns entity->expr relative to the current cpstate. * * For example, * If entity is from current cpstate, its levelsup = 0. * If entity is from immediate parent cpstate, its levelsup = 1. * If entity is from parent's parent's cpstate, its levelsup = 2. * * Relative Expr is necessary when entity->expr is a Var and the entity * is not from the current cpstate. In this case, Var->varlevelsup must * reflect the distance between source cpstate of the entity and the * cpstate where the Var is being used. */ Expr *get_relative_expr(transform_entity *entity, Index levelsup) { Var *var; Var *updated_var; if (!IsA(entity->expr, Var)) { return entity->expr; } var = (Var *)entity->expr; updated_var = makeVar(var->varno, var->varattno, var->vartype, var->vartypmod, var->varcollid, var->varlevelsup + levelsup); return (Expr *)updated_var; }