Skip to content

Json sa v7 #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 18 additions & 6 deletions src/backend/executor/execExpr.c
Original file line number Diff line number Diff line change
Expand Up @@ -3328,9 +3328,15 @@ ExecInitSubscriptingRef(ExprEvalStep *scratch, SubscriptingRef *sbsref,
{
sbsrefstate->upperprovided[i] = true;
/* Each subscript is evaluated into appropriate array entry */
ExecInitExprRec(e, state,
&sbsrefstate->upperindex[i],
&sbsrefstate->upperindexnull[i]);
if (IsA(e, String))
{
sbsrefstate->upperindex[i] = CStringGetTextDatum(strVal(e));
sbsrefstate->upperindexnull[i] = false;
}
else
ExecInitExprRec(e, state,
&sbsrefstate->upperindex[i],
&sbsrefstate->upperindexnull[i]);
}
i++;
}
Expand All @@ -3351,9 +3357,15 @@ ExecInitSubscriptingRef(ExprEvalStep *scratch, SubscriptingRef *sbsref,
{
sbsrefstate->lowerprovided[i] = true;
/* Each subscript is evaluated into appropriate array entry */
ExecInitExprRec(e, state,
&sbsrefstate->lowerindex[i],
&sbsrefstate->lowerindexnull[i]);
if (IsA(e, String))
{
sbsrefstate->lowerindex[i] = CStringGetTextDatum(strVal(e));
sbsrefstate->lowerindexnull[i] = false;
}
else
ExecInitExprRec(e, state,
&sbsrefstate->lowerindex[i],
&sbsrefstate->lowerindexnull[i]);
}
i++;
}
Expand Down
73 changes: 64 additions & 9 deletions src/backend/nodes/nodeFuncs.c
Original file line number Diff line number Diff line change
Expand Up @@ -2182,12 +2182,28 @@ expression_tree_walker_impl(Node *node,
case T_SubscriptingRef:
{
SubscriptingRef *sbsref = (SubscriptingRef *) node;
ListCell *lc;

/*
* Recurse directly for upper/lower container index lists,
* skipping String subscripts used for dot notation.
*/
foreach(lc, sbsref->refupperindexpr)
{
Node *expr = lfirst(lc);

if (expr && !IsA(expr, String) && WALK(expr))
return true;
}

foreach(lc, sbsref->reflowerindexpr)
{
Node *expr = lfirst(lc);

if (expr && !IsA(expr, String) && WALK(expr))
return true;
}

/* recurse directly for upper/lower container index lists */
if (LIST_WALK(sbsref->refupperindexpr))
return true;
if (LIST_WALK(sbsref->reflowerindexpr))
return true;
/* walker must see the refexpr and refassgnexpr, however */
if (WALK(sbsref->refexpr))
return true;
Expand Down Expand Up @@ -3082,12 +3098,51 @@ expression_tree_mutator_impl(Node *node,
{
SubscriptingRef *sbsref = (SubscriptingRef *) node;
SubscriptingRef *newnode;
ListCell *lc;
List *exprs = NIL;

FLATCOPY(newnode, sbsref, SubscriptingRef);
MUTATE(newnode->refupperindexpr, sbsref->refupperindexpr,
List *);
MUTATE(newnode->reflowerindexpr, sbsref->reflowerindexpr,
List *);

foreach(lc, sbsref->refupperindexpr)
{
Node *expr = lfirst(lc);

if (expr && IsA(expr, String))
{
String *str;

FLATCOPY(str, expr, String);
expr = (Node *) str;
}
else
expr = mutator(expr, context);

exprs = lappend(exprs, expr);
}

newnode->refupperindexpr = exprs;

exprs = NIL;

foreach(lc, sbsref->reflowerindexpr)
{
Node *expr = lfirst(lc);

if (expr && IsA(expr, String))
{
String *str;

FLATCOPY(str, expr, String);
expr = (Node *) str;
}
else
expr = mutator(expr, context);

exprs = lappend(exprs, expr);
}

newnode->reflowerindexpr = exprs;

MUTATE(newnode->refexpr, sbsref->refexpr,
Expr *);
MUTATE(newnode->refassgnexpr, sbsref->refassgnexpr,
Expand Down
2 changes: 2 additions & 0 deletions src/backend/parser/gram.y
Original file line number Diff line number Diff line change
Expand Up @@ -18968,6 +18968,7 @@ check_func_name(List *names, core_yyscan_t yyscanner)
static List *
check_indirection(List *indirection, core_yyscan_t yyscanner)
{
#if 0
ListCell *l;

foreach(l, indirection)
Expand All @@ -18978,6 +18979,7 @@ check_indirection(List *indirection, core_yyscan_t yyscanner)
parser_yyerror("improper use of \"*\"");
}
}
#endif
return indirection;
}

Expand Down
22 changes: 18 additions & 4 deletions src/backend/parser/parse_collate.c
Original file line number Diff line number Diff line change
Expand Up @@ -680,11 +680,25 @@ assign_collations_walker(Node *node, assign_collations_context *context)
* contribute anything.)
*/
SubscriptingRef *sbsref = (SubscriptingRef *) node;
ListCell *lc;

/* skip String subscripts used for dot notation */
foreach(lc, sbsref->refupperindexpr)
{
Node *expr = lfirst(lc);

if (expr && !IsA(expr, String))
assign_expr_collations(context->pstate, expr);
}

foreach(lc, sbsref->reflowerindexpr)
{
Node *expr = lfirst(lc);

if (expr && !IsA(expr, String))
assign_expr_collations(context->pstate, expr);
}

assign_expr_collations(context->pstate,
(Node *) sbsref->refupperindexpr);
assign_expr_collations(context->pstate,
(Node *) sbsref->reflowerindexpr);
(void) assign_collations_walker((Node *) sbsref->refexpr,
&loccontext);
(void) assign_collations_walker((Node *) sbsref->refassgnexpr,
Expand Down
89 changes: 59 additions & 30 deletions src/backend/parser/parse_expr.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ static Node *transformColumnRef(ParseState *pstate, ColumnRef *cref);
static Node *transformWholeRowRef(ParseState *pstate,
ParseNamespaceItem *nsitem,
int sublevels_up, int location);
static Node *transformIndirection(ParseState *pstate, A_Indirection *ind);
static Node *transformTypeCast(ParseState *pstate, TypeCast *tc);
static Node *transformCollateClause(ParseState *pstate, CollateClause *c);
static Node *transformJsonObjectConstructor(ParseState *pstate,
Expand Down Expand Up @@ -158,7 +157,7 @@ transformExprRecurse(ParseState *pstate, Node *expr)
break;

case T_A_Indirection:
result = transformIndirection(pstate, (A_Indirection *) expr);
result = transformIndirection(pstate, (A_Indirection *) expr, NULL);
break;

case T_A_ArrayExpr:
Expand Down Expand Up @@ -432,8 +431,9 @@ unknown_attribute(ParseState *pstate, Node *relref, const char *attname,
}
}

static Node *
transformIndirection(ParseState *pstate, A_Indirection *ind)
Node *
transformIndirection(ParseState *pstate, A_Indirection *ind,
bool *trailing_star_expansion)
{
Node *last_srf = pstate->p_last_srf;
Node *result = transformExprRecurse(pstate, ind->arg);
Expand All @@ -453,48 +453,77 @@ transformIndirection(ParseState *pstate, A_Indirection *ind)
if (IsA(n, A_Indices))
subscripts = lappend(subscripts, n);
else if (IsA(n, A_Star))
subscripts = lappend(subscripts, n);
else
{
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("row expansion via \"*\" is not supported here"),
parser_errposition(pstate, location)));
Assert(IsA(n, String));
subscripts = lappend(subscripts, n);
}
else
}

/* process trailing subscripts, if any */
while (subscripts)
{
Node *newresult = (Node *)
transformContainerSubscripts(pstate,
result,
exprType(result),
exprTypmod(result),
&subscripts,
false,
true);

if (!newresult)
{
Node *newresult;
/* generic subscripting failed */
Node *n;

Assert(IsA(n, String));
Assert(subscripts);

/* process subscripts before this field selection */
if (subscripts)
result = (Node *) transformContainerSubscripts(pstate,
result,
exprType(result),
exprTypmod(result),
subscripts,
false);
subscripts = NIL;
n = linitial(subscripts);

if (IsA(n, A_Star))
{
/* Success, if trailing star expansion is allowed */
if (trailing_star_expansion && list_length(subscripts) == 1)
{
*trailing_star_expansion = true;
return result;
}

ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("row expansion via \"*\" is not supported here"),
parser_errposition(pstate, location)));
}
else if (!IsA(n, String))
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("cannot subscript type %s because it does not support subscripting",
format_type_be(exprType(result))),
parser_errposition(pstate, exprLocation(result))));

/* try to find function for field selection */
newresult = ParseFuncOrColumn(pstate,
list_make1(n),
list_make1(result),
last_srf,
NULL,
false,
location);
if (newresult == NULL)

if (!newresult)
unknown_attribute(pstate, result, strVal(n), location);
result = newresult;

/* consume field select */
subscripts = list_delete_first(subscripts);
}

result = newresult;
}
/* process trailing subscripts, if any */
if (subscripts)
result = (Node *) transformContainerSubscripts(pstate,
result,
exprType(result),
exprTypmod(result),
subscripts,
false);

if (trailing_star_expansion)
*trailing_star_expansion = false;

return result;
}
Expand Down
43 changes: 38 additions & 5 deletions src/backend/parser/parse_node.c
Original file line number Diff line number Diff line change
Expand Up @@ -244,14 +244,16 @@ transformContainerSubscripts(ParseState *pstate,
Node *containerBase,
Oid containerType,
int32 containerTypMod,
List *indirection,
bool isAssignment)
List **indirection,
bool isAssignment,
bool noError)
{
SubscriptingRef *sbsref;
const SubscriptRoutines *sbsroutines;
Oid elementType;
bool isSlice = false;
ListCell *idx;
int indirection_length = list_length(*indirection);

/*
* Determine the actual container type, smashing any domain. In the
Expand All @@ -267,11 +269,16 @@ transformContainerSubscripts(ParseState *pstate,
*/
sbsroutines = getSubscriptingRoutines(containerType, &elementType);
if (!sbsroutines)
{
if (noError)
return NULL;

ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("cannot subscript type %s because it does not support subscripting",
format_type_be(containerType)),
parser_errposition(pstate, exprLocation(containerBase))));
}

/*
* Detect whether any of the indirection items are slice specifiers.
Expand All @@ -280,11 +287,11 @@ transformContainerSubscripts(ParseState *pstate,
* element. If any of the items are slice specifiers (lower:upper), then
* the subscript expression means a container slice operation.
*/
foreach(idx, indirection)
foreach(idx, *indirection)
{
A_Indices *ai = lfirst_node(A_Indices, idx);
Node *ai = lfirst(idx);

if (ai->is_slice)
if (IsA(ai, A_Indices) && castNode(A_Indices, ai)->is_slice)
{
isSlice = true;
break;
Expand Down Expand Up @@ -312,6 +319,32 @@ transformContainerSubscripts(ParseState *pstate,
sbsroutines->transform(sbsref, indirection, pstate,
isSlice, isAssignment);

/*
* Error out, if datatyoe falied to consume any indirection elements.
*/
if (list_length(*indirection) == indirection_length)
{
Node *ind = linitial(*indirection);

if (noError)
return NULL;

if (IsA(ind, String))
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("type %s does not support column notation",
format_type_be(containerType)),
parser_errposition(pstate, exprLocation(containerBase))));
else if (IsA(ind, A_Indices))
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("type %s does not support array subscripting",
format_type_be(containerType)),
parser_errposition(pstate, exprLocation(containerBase))));
else
elog(ERROR, "invalid indirection operation: %d", nodeTag(ind));
}

/*
* Verify we got a valid type (this defends, for example, against someone
* using array_subscript_handler as typsubscript without setting typelem).
Expand Down
Loading