blob: b493cebb7b88d419e55421fefd18ed10bf7618f6 [file] [log] [blame]
/*
* For PostgreSQL Database Management System:
* (formerly known as Postgres, then as Postgres95)
*
* Portions Copyright (c) 1996-2010, The PostgreSQL Global Development Group
*
* Portions Copyright (c) 1994, The Regents of the University of California
*
* Permission to use, copy, modify, and distribute this software and its documentation for any purpose,
* without fee, and without a written agreement is hereby granted, provided that the above copyright notice
* and this paragraph and the following two paragraphs appear in all copies.
*
* IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY
* OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA
* HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
#include "postgres.h"
#include "mb/pg_wchar.h"
#include "parser/cypher_parse_node.h"
static void errpos_ecb(void *arg);
/* NOTE: sync the logic with make_parsestate() */
cypher_parsestate *make_cypher_parsestate(cypher_parsestate *parent_cpstate)
{
ParseState *parent_pstate = (ParseState *)parent_cpstate;
cypher_parsestate *cpstate;
ParseState *pstate;
cpstate = palloc0(sizeof(*cpstate));
pstate = (ParseState *)cpstate;
/* Fill in fields that don't start at null/false/zero */
pstate->parentParseState = parent_pstate;
pstate->p_next_resno = 1;
pstate->p_resolve_unknowns = true;
if (parent_cpstate)
{
pstate->p_sourcetext = parent_pstate->p_sourcetext;
pstate->p_queryEnv = parent_pstate->p_queryEnv;
pstate->p_pre_columnref_hook = parent_pstate->p_pre_columnref_hook;
pstate->p_post_columnref_hook = parent_pstate->p_post_columnref_hook;
pstate->p_paramref_hook = parent_pstate->p_paramref_hook;
pstate->p_coerce_param_hook = parent_pstate->p_coerce_param_hook;
pstate->p_ref_hook_state = parent_pstate->p_ref_hook_state;
cpstate->graph_name = parent_cpstate->graph_name;
cpstate->graph_oid = parent_cpstate->graph_oid;
cpstate->params = parent_cpstate->params;
cpstate->subquery_where_flag = parent_cpstate->subquery_where_flag;
}
return cpstate;
}
void free_cypher_parsestate(cypher_parsestate *cpstate)
{
free_parsestate((ParseState *)cpstate);
}
void setup_errpos_ecb(errpos_ecb_state *ecb_state, ParseState *pstate,
int query_loc)
{
ecb_state->ecb.previous = error_context_stack;
ecb_state->ecb.callback = errpos_ecb;
ecb_state->ecb.arg = ecb_state;
ecb_state->pstate = pstate;
ecb_state->query_loc = query_loc;
error_context_stack = &ecb_state->ecb;
}
void cancel_errpos_ecb(errpos_ecb_state *ecb_state)
{
error_context_stack = ecb_state->ecb.previous;
}
/*
* adjust the current error position by adding the position of the current
* query which is a subquery of a parent query
*/
static void errpos_ecb(void *arg)
{
errpos_ecb_state *ecb_state = arg;
int query_pos;
if (geterrcode() == ERRCODE_QUERY_CANCELED)
return;
Assert(ecb_state->query_loc > -1);
query_pos = pg_mbstrlen_with_len(ecb_state->pstate->p_sourcetext,
ecb_state->query_loc);
errposition(query_pos + geterrposition());
}
RangeTblEntry *find_rte(cypher_parsestate *cpstate, char *varname)
{
ParseState *pstate = (ParseState *) cpstate;
ListCell *lc;
foreach (lc, pstate->p_rtable)
{
RangeTblEntry *rte = (RangeTblEntry *)lfirst(lc);
Alias *alias = rte->alias;
if (!alias)
continue;
if (!strcmp(alias->aliasname, varname))
return rte;
}
return NULL;
}
/*
* Generates a default alias name for when a query needs one and the parse
* state does not provide one.
*/
char *get_next_default_alias(cypher_parsestate *cpstate)
{
ParseState *pstate = (ParseState *)cpstate;
cypher_parsestate *parent_cpstate = (cypher_parsestate *)pstate->parentParseState;
char *alias_name;
int nlen = 0;
/*
* Every clause transformed as a subquery has its own cpstate which is being
* freed after it is transformed. The root cpstate is the one that has the
* default alias number initialized. So we need to reach the root cpstate to
* get the next correct default alias number.
*/
if (parent_cpstate)
{
return get_next_default_alias(parent_cpstate);
}
/* get the length of the combined string */
nlen = snprintf(NULL, 0, "%s%d", AGE_DEFAULT_ALIAS_PREFIX,
cpstate->default_alias_num);
/* allocate the space */
alias_name = palloc0(nlen + 1);
/* create the name */
snprintf(alias_name, nlen + 1, "%s%d", AGE_DEFAULT_ALIAS_PREFIX,
cpstate->default_alias_num);
/* increment the default alias number */
cpstate->default_alias_num++;
return alias_name;
}