mirror of
https://github.com/postgres/postgres.git
synced 2025-06-11 20:28:21 +03:00
Code review for XML patch. Instill a bit of sanity in the location of
the XmlExpr code in various lists, use a representation that has some hope of reverse-listing correctly (though it's still a de-escaping function shy of correctness), generally try to make it look more like Postgres coding conventions.
This commit is contained in:
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.201 2006/12/23 00:43:09 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.202 2006/12/24 00:29:18 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -117,11 +117,11 @@ static Datum ExecEvalCoalesce(CoalesceExprState *coalesceExpr,
|
||||
static Datum ExecEvalMinMax(MinMaxExprState *minmaxExpr,
|
||||
ExprContext *econtext,
|
||||
bool *isNull, ExprDoneCond *isDone);
|
||||
static Datum ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
|
||||
bool *isNull, ExprDoneCond *isDone);
|
||||
static Datum ExecEvalNullIf(FuncExprState *nullIfExpr,
|
||||
ExprContext *econtext,
|
||||
bool *isNull, ExprDoneCond *isDone);
|
||||
static Datum ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
|
||||
bool *isNull, ExprDoneCond *isDone);
|
||||
static Datum ExecEvalNullTest(NullTestState *nstate,
|
||||
ExprContext *econtext,
|
||||
bool *isNull, ExprDoneCond *isDone);
|
||||
@ -2638,6 +2638,237 @@ ExecEvalMinMax(MinMaxExprState *minmaxExpr, ExprContext *econtext,
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* ExecEvalXml
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
static Datum
|
||||
ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
|
||||
bool *isNull, ExprDoneCond *isDone)
|
||||
{
|
||||
XmlExpr *xexpr = (XmlExpr *) xmlExpr->xprstate.expr;
|
||||
text *result;
|
||||
StringInfoData buf;
|
||||
Datum value;
|
||||
bool isnull;
|
||||
char *str;
|
||||
ListCell *arg;
|
||||
ListCell *narg;
|
||||
bool found_arg;
|
||||
int i;
|
||||
|
||||
if (isDone)
|
||||
*isDone = ExprSingleResult;
|
||||
*isNull = true; /* until we get a result */
|
||||
|
||||
switch (xexpr->op)
|
||||
{
|
||||
case IS_XMLCONCAT:
|
||||
initStringInfo(&buf);
|
||||
foreach(arg, xmlExpr->args)
|
||||
{
|
||||
ExprState *e = (ExprState *) lfirst(arg);
|
||||
|
||||
value = ExecEvalExpr(e, econtext, &isnull, NULL);
|
||||
if (!isnull)
|
||||
{
|
||||
/* we know the value is XML type */
|
||||
str = DatumGetCString(DirectFunctionCall1(xml_out,
|
||||
value));
|
||||
appendStringInfoString(&buf, str);
|
||||
pfree(str);
|
||||
*isNull = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case IS_XMLELEMENT:
|
||||
initStringInfo(&buf);
|
||||
*isNull = false;
|
||||
appendStringInfo(&buf, "<%s", xexpr->name);
|
||||
i = 0;
|
||||
forboth(arg, xmlExpr->named_args, narg, xexpr->arg_names)
|
||||
{
|
||||
ExprState *e = (ExprState *) lfirst(arg);
|
||||
char *argname = strVal(lfirst(narg));
|
||||
|
||||
value = ExecEvalExpr(e, econtext, &isnull, NULL);
|
||||
if (!isnull)
|
||||
{
|
||||
str = OutputFunctionCall(&xmlExpr->named_outfuncs[i],
|
||||
value);
|
||||
appendStringInfo(&buf, " %s=\"%s\"", argname, str);
|
||||
pfree(str);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
found_arg = false;
|
||||
foreach(arg, xmlExpr->args)
|
||||
{
|
||||
ExprState *e = (ExprState *) lfirst(arg);
|
||||
|
||||
value = ExecEvalExpr(e, econtext, &isnull, NULL);
|
||||
if (!isnull)
|
||||
{
|
||||
if (!found_arg)
|
||||
{
|
||||
appendStringInfoChar(&buf, '>');
|
||||
found_arg = true;
|
||||
}
|
||||
|
||||
/* we know the value is XML type */
|
||||
str = DatumGetCString(DirectFunctionCall1(xml_out,
|
||||
value));
|
||||
appendStringInfoString(&buf, str);
|
||||
pfree(str);
|
||||
}
|
||||
}
|
||||
|
||||
if (!found_arg)
|
||||
appendStringInfo(&buf, "/>");
|
||||
else
|
||||
appendStringInfo(&buf, "</%s>", xexpr->name);
|
||||
break;
|
||||
|
||||
case IS_XMLFOREST:
|
||||
initStringInfo(&buf);
|
||||
i = 0;
|
||||
forboth(arg, xmlExpr->named_args, narg, xexpr->arg_names)
|
||||
{
|
||||
ExprState *e = (ExprState *) lfirst(arg);
|
||||
char *argname = strVal(lfirst(narg));
|
||||
|
||||
value = ExecEvalExpr(e, econtext, &isnull, NULL);
|
||||
if (!isnull)
|
||||
{
|
||||
str = OutputFunctionCall(&xmlExpr->named_outfuncs[i],
|
||||
value);
|
||||
appendStringInfo(&buf, "<%s>%s</%s>",
|
||||
argname, str, argname);
|
||||
pfree(str);
|
||||
*isNull = false;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
break;
|
||||
|
||||
/* The remaining cases don't need to set up buf */
|
||||
case IS_XMLPARSE:
|
||||
{
|
||||
ExprState *e;
|
||||
text *data;
|
||||
bool is_document;
|
||||
bool preserve_whitespace;
|
||||
|
||||
/* arguments are known to be text, bool, bool */
|
||||
Assert(list_length(xmlExpr->args) == 3);
|
||||
|
||||
e = (ExprState *) linitial(xmlExpr->args);
|
||||
value = ExecEvalExpr(e, econtext, &isnull, NULL);
|
||||
if (isnull)
|
||||
return (Datum) 0;
|
||||
data = DatumGetTextP(value);
|
||||
|
||||
e = (ExprState *) lsecond(xmlExpr->args);
|
||||
value = ExecEvalExpr(e, econtext, &isnull, NULL);
|
||||
if (isnull) /* probably can't happen */
|
||||
return (Datum) 0;
|
||||
is_document = DatumGetBool(value);
|
||||
|
||||
e = (ExprState *) lthird(xmlExpr->args);
|
||||
value = ExecEvalExpr(e, econtext, &isnull, NULL);
|
||||
if (isnull) /* probably can't happen */
|
||||
return (Datum) 0;
|
||||
preserve_whitespace = DatumGetBool(value);
|
||||
|
||||
*isNull = false;
|
||||
|
||||
return PointerGetDatum(xmlparse(data,
|
||||
is_document,
|
||||
preserve_whitespace));
|
||||
}
|
||||
break;
|
||||
|
||||
case IS_XMLPI:
|
||||
{
|
||||
ExprState *e;
|
||||
text *arg;
|
||||
|
||||
/* optional argument is known to be text */
|
||||
Assert(list_length(xmlExpr->args) <= 1);
|
||||
|
||||
if (xmlExpr->args)
|
||||
{
|
||||
e = (ExprState *) linitial(xmlExpr->args);
|
||||
value = ExecEvalExpr(e, econtext, &isnull, NULL);
|
||||
if (isnull)
|
||||
return (Datum) 0;
|
||||
arg = DatumGetTextP(value);
|
||||
}
|
||||
else
|
||||
arg = NULL;
|
||||
|
||||
*isNull = false;
|
||||
|
||||
return PointerGetDatum(xmlpi(xexpr->name, arg));
|
||||
}
|
||||
break;
|
||||
|
||||
case IS_XMLROOT:
|
||||
{
|
||||
ExprState *e;
|
||||
xmltype *data;
|
||||
text *version;
|
||||
int standalone;
|
||||
|
||||
/* arguments are known to be xml, text, bool */
|
||||
Assert(list_length(xmlExpr->args) == 3);
|
||||
|
||||
e = (ExprState *) linitial(xmlExpr->args);
|
||||
value = ExecEvalExpr(e, econtext, &isnull, NULL);
|
||||
if (isnull)
|
||||
return (Datum) 0;
|
||||
data = DatumGetXmlP(value);
|
||||
|
||||
e = (ExprState *) lsecond(xmlExpr->args);
|
||||
value = ExecEvalExpr(e, econtext, &isnull, NULL);
|
||||
if (isnull)
|
||||
version = NULL;
|
||||
else
|
||||
version = DatumGetTextP(value);
|
||||
|
||||
e = (ExprState *) lthird(xmlExpr->args);
|
||||
value = ExecEvalExpr(e, econtext, &isnull, NULL);
|
||||
if (isnull)
|
||||
standalone = 0;
|
||||
else
|
||||
standalone = (DatumGetBool(value) ? 1 : -1);
|
||||
|
||||
*isNull = false;
|
||||
|
||||
return PointerGetDatum(xmlroot(data,
|
||||
version,
|
||||
standalone));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (*isNull)
|
||||
result = NULL;
|
||||
else
|
||||
{
|
||||
int len = buf.len + VARHDRSZ;
|
||||
|
||||
result = palloc(len);
|
||||
VARATT_SIZEP(result) = len;
|
||||
memcpy(VARDATA(result), buf.data, buf.len);
|
||||
}
|
||||
|
||||
pfree(buf.data);
|
||||
return PointerGetDatum(result);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* ExecEvalNullIf
|
||||
*
|
||||
@ -2881,120 +3112,6 @@ ExecEvalBooleanTest(GenericExprState *bstate,
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* ExecEvalXml
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static Datum
|
||||
ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
|
||||
bool *isNull, ExprDoneCond *isDone)
|
||||
{
|
||||
StringInfoData buf;
|
||||
bool isnull;
|
||||
ListCell *arg;
|
||||
text *result = NULL;
|
||||
int len;
|
||||
|
||||
initStringInfo(&buf);
|
||||
|
||||
*isNull = false;
|
||||
|
||||
if (isDone)
|
||||
*isDone = ExprSingleResult;
|
||||
|
||||
switch (xmlExpr->op)
|
||||
{
|
||||
case IS_XMLCONCAT:
|
||||
*isNull = true;
|
||||
|
||||
foreach(arg, xmlExpr->args)
|
||||
{
|
||||
ExprState *e = (ExprState *) lfirst(arg);
|
||||
Datum value = ExecEvalExpr(e, econtext, &isnull, NULL);
|
||||
|
||||
if (!isnull)
|
||||
{
|
||||
appendStringInfoString(&buf, DatumGetCString(OidFunctionCall1(xmlExpr->arg_typeout, value)));
|
||||
*isNull = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case IS_XMLELEMENT:
|
||||
{
|
||||
int state = 0, i = 0;
|
||||
appendStringInfo(&buf, "<%s", xmlExpr->name);
|
||||
foreach(arg, xmlExpr->named_args)
|
||||
{
|
||||
GenericExprState *gstate = (GenericExprState *) lfirst(arg);
|
||||
Datum value = ExecEvalExpr(gstate->arg, econtext, &isnull, NULL);
|
||||
if (!isnull)
|
||||
{
|
||||
char *outstr = DatumGetCString(OidFunctionCall1(xmlExpr->named_args_tcache[i], value));
|
||||
appendStringInfo(&buf, " %s=\"%s\"", xmlExpr->named_args_ncache[i], outstr);
|
||||
pfree(outstr);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (xmlExpr->args)
|
||||
{
|
||||
ExprState *expr = linitial(xmlExpr->args);
|
||||
Datum value = ExecEvalExpr(expr, econtext, &isnull, NULL);
|
||||
|
||||
if (!isnull)
|
||||
{
|
||||
char *outstr = DatumGetCString(OidFunctionCall1(xmlExpr->arg_typeout, value));
|
||||
if (state == 0)
|
||||
{
|
||||
appendStringInfoChar(&buf, '>');
|
||||
state = 1;
|
||||
}
|
||||
appendStringInfo(&buf, "%s", outstr);
|
||||
pfree(outstr);
|
||||
}
|
||||
}
|
||||
|
||||
if (state == 0)
|
||||
appendStringInfo(&buf, "/>");
|
||||
else if (state == 1)
|
||||
appendStringInfo(&buf, "</%s>", xmlExpr->name);
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case IS_XMLFOREST:
|
||||
{
|
||||
/* only if all argumets are null returns null */
|
||||
int i = 0;
|
||||
*isNull = true;
|
||||
foreach(arg, xmlExpr->named_args)
|
||||
{
|
||||
GenericExprState *gstate = (GenericExprState *) lfirst(arg);
|
||||
Datum value = ExecEvalExpr(gstate->arg, econtext, &isnull, NULL);
|
||||
if (!isnull)
|
||||
{
|
||||
char *outstr = DatumGetCString(OidFunctionCall1(xmlExpr->named_args_tcache[i], value));
|
||||
appendStringInfo(&buf, "<%s>%s</%s>", xmlExpr->named_args_ncache[i], outstr, xmlExpr->named_args_ncache[i]);
|
||||
pfree(outstr);
|
||||
*isNull = false;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
len = buf.len + VARHDRSZ;
|
||||
result = palloc(len);
|
||||
VARATT_SIZEP(result) = len;
|
||||
memcpy(VARDATA(result), buf.data, buf.len);
|
||||
pfree(buf.data);
|
||||
PG_RETURN_TEXT_P(result);
|
||||
}
|
||||
|
||||
/*
|
||||
* ExecEvalCoerceToDomain
|
||||
*
|
||||
@ -3794,59 +3911,45 @@ ExecInitExpr(Expr *node, PlanState *parent)
|
||||
break;
|
||||
case T_XmlExpr:
|
||||
{
|
||||
List *outlist;
|
||||
ListCell *arg;
|
||||
XmlExpr *xexpr = (XmlExpr *) node;
|
||||
XmlExprState *xstate = makeNode(XmlExprState);
|
||||
int i = 0;
|
||||
Oid typeout;
|
||||
|
||||
xstate->name = xexpr->name;
|
||||
|
||||
List *outlist;
|
||||
ListCell *arg;
|
||||
int i;
|
||||
|
||||
xstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalXml;
|
||||
xstate->op = xexpr->op;
|
||||
|
||||
xstate->named_outfuncs = (FmgrInfo *)
|
||||
palloc0(list_length(xexpr->named_args) * sizeof(FmgrInfo));
|
||||
outlist = NIL;
|
||||
if (xexpr->named_args)
|
||||
i = 0;
|
||||
foreach(arg, xexpr->named_args)
|
||||
{
|
||||
xstate->named_args_tcache = (Oid *) palloc(list_length(xexpr->named_args) * sizeof(int));
|
||||
xstate->named_args_ncache = (char **) palloc(list_length(xexpr->named_args) * sizeof(char *));
|
||||
|
||||
i = 0;
|
||||
foreach(arg, xexpr->named_args)
|
||||
{
|
||||
bool tpisvarlena;
|
||||
Expr *e = (Expr *) lfirst(arg);
|
||||
ExprState *estate = ExecInitExpr(e, parent);
|
||||
TargetEntry *tle;
|
||||
outlist = lappend(outlist, estate);
|
||||
tle = (TargetEntry *) ((GenericExprState *) estate)->xprstate.expr;
|
||||
getTypeOutputInfo(exprType((Node *)tle->expr), &typeout, &tpisvarlena);
|
||||
xstate->named_args_ncache[i] = tle->resname;
|
||||
xstate->named_args_tcache[i] = typeout;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
xstate->named_args_tcache = NULL;
|
||||
xstate->named_args_ncache = NULL;
|
||||
Expr *e = (Expr *) lfirst(arg);
|
||||
ExprState *estate;
|
||||
Oid typOutFunc;
|
||||
bool typIsVarlena;
|
||||
|
||||
estate = ExecInitExpr(e, parent);
|
||||
outlist = lappend(outlist, estate);
|
||||
|
||||
getTypeOutputInfo(exprType((Node *) e),
|
||||
&typOutFunc, &typIsVarlena);
|
||||
fmgr_info(typOutFunc, &xstate->named_outfuncs[i]);
|
||||
i++;
|
||||
}
|
||||
xstate->named_args = outlist;
|
||||
|
||||
outlist = NIL;
|
||||
outlist = NIL;
|
||||
foreach(arg, xexpr->args)
|
||||
{
|
||||
bool tpisvarlena;
|
||||
ExprState *estate;
|
||||
Expr *e = (Expr *) lfirst(arg);
|
||||
getTypeOutputInfo(exprType((Node *)e), &typeout, &tpisvarlena);
|
||||
Expr *e = (Expr *) lfirst(arg);
|
||||
ExprState *estate;
|
||||
|
||||
estate = ExecInitExpr(e, parent);
|
||||
outlist = lappend(outlist, estate);
|
||||
}
|
||||
xstate->arg_typeout = typeout;
|
||||
xstate->args = outlist;
|
||||
|
||||
|
||||
state = (ExprState *) xstate;
|
||||
}
|
||||
break;
|
||||
|
Reference in New Issue
Block a user