Header And Logo

PostgreSQL
| The world's most advanced open source database.

Data Structures | Typedefs | Enumerations | Functions

deparse.c File Reference

#include "postgres.h"
#include "postgres_fdw.h"
#include "access/heapam.h"
#include "access/htup_details.h"
#include "access/sysattr.h"
#include "access/transam.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "commands/defrem.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
#include "optimizer/var.h"
#include "parser/parsetree.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
Include dependency graph for deparse.c:

Go to the source code of this file.

Data Structures

struct  foreign_glob_cxt
struct  foreign_loc_cxt
struct  deparse_expr_cxt

Typedefs

typedef struct foreign_glob_cxt foreign_glob_cxt
typedef struct foreign_loc_cxt foreign_loc_cxt
typedef struct deparse_expr_cxt deparse_expr_cxt

Enumerations

enum  FDWCollateState { FDW_COLLATE_NONE, FDW_COLLATE_SAFE, FDW_COLLATE_UNSAFE }

Functions

static bool foreign_expr_walker (Node *node, foreign_glob_cxt *glob_cxt, foreign_loc_cxt *outer_cxt)
static bool is_builtin (Oid procid)
static void deparseTargetList (StringInfo buf, PlannerInfo *root, Index rtindex, Relation rel, Bitmapset *attrs_used, List **retrieved_attrs)
static void deparseReturningList (StringInfo buf, PlannerInfo *root, Index rtindex, Relation rel, List *returningList, List **retrieved_attrs)
static void deparseColumnRef (StringInfo buf, int varno, int varattno, PlannerInfo *root)
static void deparseRelation (StringInfo buf, Relation rel)
static void deparseStringLiteral (StringInfo buf, const char *val)
static void deparseExpr (Expr *expr, deparse_expr_cxt *context)
static void deparseVar (Var *node, deparse_expr_cxt *context)
static void deparseConst (Const *node, deparse_expr_cxt *context)
static void deparseParam (Param *node, deparse_expr_cxt *context)
static void deparseArrayRef (ArrayRef *node, deparse_expr_cxt *context)
static void deparseFuncExpr (FuncExpr *node, deparse_expr_cxt *context)
static void deparseOpExpr (OpExpr *node, deparse_expr_cxt *context)
static void deparseOperatorName (StringInfo buf, Form_pg_operator opform)
static void deparseDistinctExpr (DistinctExpr *node, deparse_expr_cxt *context)
static void deparseScalarArrayOpExpr (ScalarArrayOpExpr *node, deparse_expr_cxt *context)
static void deparseRelabelType (RelabelType *node, deparse_expr_cxt *context)
static void deparseBoolExpr (BoolExpr *node, deparse_expr_cxt *context)
static void deparseNullTest (NullTest *node, deparse_expr_cxt *context)
static void deparseArrayExpr (ArrayExpr *node, deparse_expr_cxt *context)
void classifyConditions (PlannerInfo *root, RelOptInfo *baserel, List **remote_conds, List **local_conds)
bool is_foreign_expr (PlannerInfo *root, RelOptInfo *baserel, Expr *expr)
void deparseSelectSql (StringInfo buf, PlannerInfo *root, RelOptInfo *baserel, Bitmapset *attrs_used, List **retrieved_attrs)
void appendWhereClause (StringInfo buf, PlannerInfo *root, RelOptInfo *baserel, List *exprs, bool is_first, List **params)
void deparseInsertSql (StringInfo buf, PlannerInfo *root, Index rtindex, Relation rel, List *targetAttrs, List *returningList, List **retrieved_attrs)
void deparseUpdateSql (StringInfo buf, PlannerInfo *root, Index rtindex, Relation rel, List *targetAttrs, List *returningList, List **retrieved_attrs)
void deparseDeleteSql (StringInfo buf, PlannerInfo *root, Index rtindex, Relation rel, List *returningList, List **retrieved_attrs)
void deparseAnalyzeSizeSql (StringInfo buf, Relation rel)
void deparseAnalyzeSql (StringInfo buf, Relation rel, List **retrieved_attrs)

Typedef Documentation


Enumeration Type Documentation

Enumerator:
FDW_COLLATE_NONE 
FDW_COLLATE_SAFE 
FDW_COLLATE_UNSAFE 

Definition at line 69 of file deparse.c.

{
    FDW_COLLATE_NONE,           /* expression is of a noncollatable type */
    FDW_COLLATE_SAFE,           /* collation derives from a foreign Var */
    FDW_COLLATE_UNSAFE          /* collation derives from something else */
} FDWCollateState;


Function Documentation

void appendWhereClause ( StringInfo  buf,
PlannerInfo root,
RelOptInfo baserel,
List exprs,
bool  is_first,
List **  params 
)

Definition at line 779 of file deparse.c.

References appendStringInfoChar(), appendStringInfoString(), deparse_expr_cxt::buf, RestrictInfo::clause, deparseExpr(), deparse_expr_cxt::foreignrel, lfirst, deparse_expr_cxt::params_list, reset_transmission_modes(), deparse_expr_cxt::root, and set_transmission_modes().

Referenced by estimate_path_cost_size(), and postgresGetForeignPlan().

{
    deparse_expr_cxt context;
    int         nestlevel;
    ListCell   *lc;

    if (params)
        *params = NIL;          /* initialize result list to empty */

    /* Set up context struct for recursion */
    context.root = root;
    context.foreignrel = baserel;
    context.buf = buf;
    context.params_list = params;

    /* Make sure any constants in the exprs are printed portably */
    nestlevel = set_transmission_modes();

    foreach(lc, exprs)
    {
        RestrictInfo *ri = (RestrictInfo *) lfirst(lc);

        /* Connect expressions with "AND" and parenthesize each condition. */
        if (is_first)
            appendStringInfoString(buf, " WHERE ");
        else
            appendStringInfoString(buf, " AND ");

        appendStringInfoChar(buf, '(');
        deparseExpr(ri->clause, &context);
        appendStringInfoChar(buf, ')');

        is_first = false;
    }

    reset_transmission_modes(nestlevel);
}

void classifyConditions ( PlannerInfo root,
RelOptInfo baserel,
List **  remote_conds,
List **  local_conds 
)

Definition at line 143 of file deparse.c.

References RelOptInfo::baserestrictinfo, RestrictInfo::clause, is_foreign_expr(), lappend(), and lfirst.

Referenced by postgresGetForeignRelSize().

{
    ListCell   *lc;

    *remote_conds = NIL;
    *local_conds = NIL;

    foreach(lc, baserel->baserestrictinfo)
    {
        RestrictInfo *ri = (RestrictInfo *) lfirst(lc);

        if (is_foreign_expr(root, baserel, ri->clause))
            *remote_conds = lappend(*remote_conds, ri);
        else
            *local_conds = lappend(*local_conds, ri);
    }
}

void deparseAnalyzeSizeSql ( StringInfo  buf,
Relation  rel 
)

Definition at line 984 of file deparse.c.

References appendStringInfo(), StringInfoData::data, deparseRelation(), deparseStringLiteral(), and initStringInfo().

Referenced by postgresAnalyzeForeignTable().

{
    StringInfoData relname;

    /* We'll need the remote relation name as a literal. */
    initStringInfo(&relname);
    deparseRelation(&relname, rel);

    appendStringInfo(buf, "SELECT pg_catalog.pg_relation_size(");
    deparseStringLiteral(buf, relname.data);
    appendStringInfo(buf, "::pg_catalog.regclass) / %d", BLCKSZ);
}

void deparseAnalyzeSql ( StringInfo  buf,
Relation  rel,
List **  retrieved_attrs 
)

Definition at line 1004 of file deparse.c.

References appendStringInfoString(), tupleDesc::attrs, defGetString(), DefElem::defname, deparseRelation(), GetForeignColumnOptions(), i, lappend_int(), lfirst, NameStr, tupleDesc::natts, quote_identifier(), RelationGetDescr, and RelationGetRelid.

Referenced by postgresAcquireSampleRowsFunc().

{
    Oid         relid = RelationGetRelid(rel);
    TupleDesc   tupdesc = RelationGetDescr(rel);
    int         i;
    char       *colname;
    List       *options;
    ListCell   *lc;
    bool        first = true;

    *retrieved_attrs = NIL;

    appendStringInfoString(buf, "SELECT ");
    for (i = 0; i < tupdesc->natts; i++)
    {
        /* Ignore dropped columns. */
        if (tupdesc->attrs[i]->attisdropped)
            continue;

        if (!first)
            appendStringInfoString(buf, ", ");
        first = false;

        /* Use attribute name or column_name option. */
        colname = NameStr(tupdesc->attrs[i]->attname);
        options = GetForeignColumnOptions(relid, i + 1);

        foreach(lc, options)
        {
            DefElem    *def = (DefElem *) lfirst(lc);

            if (strcmp(def->defname, "column_name") == 0)
            {
                colname = defGetString(def);
                break;
            }
        }

        appendStringInfoString(buf, quote_identifier(colname));

        *retrieved_attrs = lappend_int(*retrieved_attrs, i + 1);
    }

    /* Don't generate bad syntax for zero-column relation. */
    if (first)
        appendStringInfoString(buf, "NULL");

    /*
     * Construct FROM clause
     */
    appendStringInfoString(buf, " FROM ");
    deparseRelation(buf, rel);
}

static void deparseArrayExpr ( ArrayExpr node,
deparse_expr_cxt context 
) [static]

Definition at line 1794 of file deparse.c.

References appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), ArrayExpr::array_typeid, deparse_expr_cxt::buf, buf, deparseExpr(), ArrayExpr::elements, format_type_with_typemod(), lfirst, and NIL.

Referenced by deparseExpr().

{
    StringInfo  buf = context->buf;
    bool        first = true;
    ListCell   *lc;

    appendStringInfoString(buf, "ARRAY[");
    foreach(lc, node->elements)
    {
        if (!first)
            appendStringInfoString(buf, ", ");
        deparseExpr(lfirst(lc), context);
        first = false;
    }
    appendStringInfoChar(buf, ']');

    /* If the array is empty, we need an explicit cast to the array type. */
    if (node->elements == NIL)
        appendStringInfo(buf, "::%s",
                         format_type_with_typemod(node->array_typeid, -1));
}

static void deparseArrayRef ( ArrayRef node,
deparse_expr_cxt context 
) [static]

Definition at line 1446 of file deparse.c.

References appendStringInfoChar(), deparse_expr_cxt::buf, buf, deparseExpr(), IsA, lfirst, list_head(), lnext, ArrayRef::refexpr, ArrayRef::reflowerindexpr, and ArrayRef::refupperindexpr.

Referenced by deparseExpr().

{
    StringInfo  buf = context->buf;
    ListCell   *lowlist_item;
    ListCell   *uplist_item;

    /* Always parenthesize the expression. */
    appendStringInfoChar(buf, '(');

    /*
     * Deparse referenced array expression first.  If that expression includes
     * a cast, we have to parenthesize to prevent the array subscript from
     * being taken as typename decoration.  We can avoid that in the typical
     * case of subscripting a Var, but otherwise do it.
     */
    if (IsA(node->refexpr, Var))
        deparseExpr(node->refexpr, context);
    else
    {
        appendStringInfoChar(buf, '(');
        deparseExpr(node->refexpr, context);
        appendStringInfoChar(buf, ')');
    }

    /* Deparse subscript expressions. */
    lowlist_item = list_head(node->reflowerindexpr);    /* could be NULL */
    foreach(uplist_item, node->refupperindexpr)
    {
        appendStringInfoChar(buf, '[');
        if (lowlist_item)
        {
            deparseExpr(lfirst(lowlist_item), context);
            appendStringInfoChar(buf, ':');
            lowlist_item = lnext(lowlist_item);
        }
        deparseExpr(lfirst(uplist_item), context);
        appendStringInfoChar(buf, ']');
    }

    appendStringInfoChar(buf, ')');
}

static void deparseBoolExpr ( BoolExpr node,
deparse_expr_cxt context 
) [static]

Definition at line 1740 of file deparse.c.

References AND_EXPR, appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), BoolExpr::args, BoolExpr::boolop, deparse_expr_cxt::buf, buf, deparseExpr(), lfirst, linitial, NOT_EXPR, and OR_EXPR.

Referenced by deparseExpr().

{
    StringInfo  buf = context->buf;
    const char *op = NULL;      /* keep compiler quiet */
    bool        first;
    ListCell   *lc;

    switch (node->boolop)
    {
        case AND_EXPR:
            op = "AND";
            break;
        case OR_EXPR:
            op = "OR";
            break;
        case NOT_EXPR:
            appendStringInfoString(buf, "(NOT ");
            deparseExpr(linitial(node->args), context);
            appendStringInfoChar(buf, ')');
            return;
    }

    appendStringInfoChar(buf, '(');
    first = true;
    foreach(lc, node->args)
    {
        if (!first)
            appendStringInfo(buf, " %s ", op);
        deparseExpr((Expr *) lfirst(lc), context);
        first = false;
    }
    appendStringInfoChar(buf, ')');
}

static void deparseColumnRef ( StringInfo  buf,
int  varno,
int  varattno,
PlannerInfo root 
) [static]

Definition at line 1063 of file deparse.c.

References appendStringInfoString(), Assert, defGetString(), DefElem::defname, get_relid_attribute_name(), GetForeignColumnOptions(), IS_SPECIAL_VARNO, lfirst, NULL, planner_rt_fetch, quote_identifier(), and RangeTblEntry::relid.

Referenced by deparseInsertSql(), deparseTargetList(), deparseUpdateSql(), and deparseVar().

{
    RangeTblEntry *rte;
    char       *colname = NULL;
    List       *options;
    ListCell   *lc;

    /* varno must not be any of OUTER_VAR, INNER_VAR and INDEX_VAR. */
    Assert(!IS_SPECIAL_VARNO(varno));

    /* Get RangeTblEntry from array in PlannerInfo. */
    rte = planner_rt_fetch(varno, root);

    /*
     * If it's a column of a foreign table, and it has the column_name FDW
     * option, use that value.
     */
    options = GetForeignColumnOptions(rte->relid, varattno);
    foreach(lc, options)
    {
        DefElem    *def = (DefElem *) lfirst(lc);

        if (strcmp(def->defname, "column_name") == 0)
        {
            colname = defGetString(def);
            break;
        }
    }

    /*
     * If it's a column of a regular table or it doesn't have column_name FDW
     * option, use attribute name.
     */
    if (colname == NULL)
        colname = get_relid_attribute_name(rte->relid, varattno);

    appendStringInfoString(buf, quote_identifier(colname));
}

static void deparseConst ( Const node,
deparse_expr_cxt context 
) [static]

Definition at line 1294 of file deparse.c.

References appendStringInfo(), appendStringInfoString(), BITOID, BOOLOID, deparse_expr_cxt::buf, buf, Const::constisnull, Const::consttype, Const::consttypmod, Const::constvalue, deparseStringLiteral(), FLOAT4OID, FLOAT8OID, format_type_with_typemod(), getTypeOutputInfo(), INT2OID, INT4OID, INT8OID, NUMERICOID, OIDOID, OidOutputFunctionCall(), UNKNOWNOID, and VARBITOID.

Referenced by deparseExpr().

{
    StringInfo  buf = context->buf;
    Oid         typoutput;
    bool        typIsVarlena;
    char       *extval;
    bool        isfloat = false;
    bool        needlabel;

    if (node->constisnull)
    {
        appendStringInfo(buf, "NULL");
        appendStringInfo(buf, "::%s",
                         format_type_with_typemod(node->consttype,
                                                  node->consttypmod));
        return;
    }

    getTypeOutputInfo(node->consttype,
                      &typoutput, &typIsVarlena);
    extval = OidOutputFunctionCall(typoutput, node->constvalue);

    switch (node->consttype)
    {
        case INT2OID:
        case INT4OID:
        case INT8OID:
        case OIDOID:
        case FLOAT4OID:
        case FLOAT8OID:
        case NUMERICOID:
            {
                /*
                 * No need to quote unless it's a special value such as 'NaN'.
                 * See comments in get_const_expr().
                 */
                if (strspn(extval, "0123456789+-eE.") == strlen(extval))
                {
                    if (extval[0] == '+' || extval[0] == '-')
                        appendStringInfo(buf, "(%s)", extval);
                    else
                        appendStringInfoString(buf, extval);
                    if (strcspn(extval, "eE.") != strlen(extval))
                        isfloat = true; /* it looks like a float */
                }
                else
                    appendStringInfo(buf, "'%s'", extval);
            }
            break;
        case BITOID:
        case VARBITOID:
            appendStringInfo(buf, "B'%s'", extval);
            break;
        case BOOLOID:
            if (strcmp(extval, "t") == 0)
                appendStringInfoString(buf, "true");
            else
                appendStringInfoString(buf, "false");
            break;
        default:
            deparseStringLiteral(buf, extval);
            break;
    }

    /*
     * Append ::typename unless the constant will be implicitly typed as the
     * right type when it is read in.
     *
     * XXX this code has to be kept in sync with the behavior of the parser,
     * especially make_const.
     */
    switch (node->consttype)
    {
        case BOOLOID:
        case INT4OID:
        case UNKNOWNOID:
            needlabel = false;
            break;
        case NUMERICOID:
            needlabel = !isfloat || (node->consttypmod >= 0);
            break;
        default:
            needlabel = true;
            break;
    }
    if (needlabel)
        appendStringInfo(buf, "::%s",
                         format_type_with_typemod(node->consttype,
                                                  node->consttypmod));
}

void deparseDeleteSql ( StringInfo  buf,
PlannerInfo root,
Index  rtindex,
Relation  rel,
List returningList,
List **  retrieved_attrs 
)

Definition at line 936 of file deparse.c.

References appendStringInfoString(), deparseRelation(), and deparseReturningList().

Referenced by postgresPlanForeignModify().

{
    appendStringInfoString(buf, "DELETE FROM ");
    deparseRelation(buf, rel);
    appendStringInfoString(buf, " WHERE ctid = $1");

    if (returningList)
        deparseReturningList(buf, root, rtindex, rel, returningList,
                             retrieved_attrs);
    else
        *retrieved_attrs = NIL;
}

static void deparseDistinctExpr ( DistinctExpr node,
deparse_expr_cxt context 
) [static]

Definition at line 1661 of file deparse.c.

References appendStringInfoChar(), appendStringInfoString(), OpExpr::args, Assert, deparse_expr_cxt::buf, buf, deparseExpr(), linitial, list_length(), and lsecond.

Referenced by deparseExpr().

{
    StringInfo  buf = context->buf;

    Assert(list_length(node->args) == 2);

    appendStringInfoChar(buf, '(');
    deparseExpr(linitial(node->args), context);
    appendStringInfoString(buf, " IS DISTINCT FROM ");
    deparseExpr(lsecond(node->args), context);
    appendStringInfoChar(buf, ')');
}

static void deparseExpr ( Expr expr,
deparse_expr_cxt context 
) [static]

Definition at line 1183 of file deparse.c.

References deparseArrayExpr(), deparseArrayRef(), deparseBoolExpr(), deparseConst(), deparseDistinctExpr(), deparseFuncExpr(), deparseNullTest(), deparseOpExpr(), deparseParam(), deparseRelabelType(), deparseScalarArrayOpExpr(), deparseVar(), elog, ERROR, nodeTag, NULL, T_ArrayExpr, T_ArrayRef, T_BoolExpr, T_Const, T_DistinctExpr, T_FuncExpr, T_NullTest, T_OpExpr, T_Param, T_RelabelType, T_ScalarArrayOpExpr, and T_Var.

Referenced by appendWhereClause(), deparseArrayExpr(), deparseArrayRef(), deparseBoolExpr(), deparseDistinctExpr(), deparseFuncExpr(), deparseNullTest(), deparseOpExpr(), deparseRelabelType(), and deparseScalarArrayOpExpr().

{
    if (node == NULL)
        return;

    switch (nodeTag(node))
    {
        case T_Var:
            deparseVar((Var *) node, context);
            break;
        case T_Const:
            deparseConst((Const *) node, context);
            break;
        case T_Param:
            deparseParam((Param *) node, context);
            break;
        case T_ArrayRef:
            deparseArrayRef((ArrayRef *) node, context);
            break;
        case T_FuncExpr:
            deparseFuncExpr((FuncExpr *) node, context);
            break;
        case T_OpExpr:
            deparseOpExpr((OpExpr *) node, context);
            break;
        case T_DistinctExpr:
            deparseDistinctExpr((DistinctExpr *) node, context);
            break;
        case T_ScalarArrayOpExpr:
            deparseScalarArrayOpExpr((ScalarArrayOpExpr *) node, context);
            break;
        case T_RelabelType:
            deparseRelabelType((RelabelType *) node, context);
            break;
        case T_BoolExpr:
            deparseBoolExpr((BoolExpr *) node, context);
            break;
        case T_NullTest:
            deparseNullTest((NullTest *) node, context);
            break;
        case T_ArrayExpr:
            deparseArrayExpr((ArrayExpr *) node, context);
            break;
        default:
            elog(ERROR, "unsupported expression type for deparse: %d",
                 (int) nodeTag(node));
            break;
    }
}

static void deparseFuncExpr ( FuncExpr node,
deparse_expr_cxt context 
) [static]

Definition at line 1492 of file deparse.c.

References ANYOID, appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), arg, FuncExpr::args, deparse_expr_cxt::buf, buf, COERCE_EXPLICIT_CAST, COERCE_IMPLICIT_CAST, deparseExpr(), elog, ERROR, exprIsLengthCoercion(), format_type_with_typemod(), FuncExpr::funcformat, FuncExpr::funcid, FuncExpr::funcresulttype, FuncExpr::funcvariadic, get_namespace_name(), GETSTRUCT, HeapTupleIsValid, lfirst, linitial, lnext, NameStr, NULL, ObjectIdGetDatum, OidIsValid, PG_CATALOG_NAMESPACE, PROCOID, quote_identifier(), ReleaseSysCache(), and SearchSysCache1.

Referenced by deparseExpr().

{
    StringInfo  buf = context->buf;
    HeapTuple   proctup;
    Form_pg_proc procform;
    const char *proname;
    bool        use_variadic;
    bool        first;
    ListCell   *arg;

    /*
     * If the function call came from an implicit coercion, then just show the
     * first argument.
     */
    if (node->funcformat == COERCE_IMPLICIT_CAST)
    {
        deparseExpr((Expr *) linitial(node->args), context);
        return;
    }

    /*
     * If the function call came from a cast, then show the first argument
     * plus an explicit cast operation.
     */
    if (node->funcformat == COERCE_EXPLICIT_CAST)
    {
        Oid         rettype = node->funcresulttype;
        int32       coercedTypmod;

        /* Get the typmod if this is a length-coercion function */
        (void) exprIsLengthCoercion((Node *) node, &coercedTypmod);

        deparseExpr((Expr *) linitial(node->args), context);
        appendStringInfo(buf, "::%s",
                         format_type_with_typemod(rettype, coercedTypmod));
        return;
    }

    /*
     * Normal function: display as proname(args).
     */
    proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(node->funcid));
    if (!HeapTupleIsValid(proctup))
        elog(ERROR, "cache lookup failed for function %u", node->funcid);
    procform = (Form_pg_proc) GETSTRUCT(proctup);

    /* Check if need to print VARIADIC (cf. ruleutils.c) */
    if (OidIsValid(procform->provariadic))
    {
        if (procform->provariadic != ANYOID)
            use_variadic = true;
        else
            use_variadic = node->funcvariadic;
    }
    else
        use_variadic = false;

    /* Print schema name only if it's not pg_catalog */
    if (procform->pronamespace != PG_CATALOG_NAMESPACE)
    {
        const char *schemaname;

        schemaname = get_namespace_name(procform->pronamespace);
        appendStringInfo(buf, "%s.", quote_identifier(schemaname));
    }

    /* Deparse the function name ... */
    proname = NameStr(procform->proname);
    appendStringInfo(buf, "%s(", quote_identifier(proname));
    /* ... and all the arguments */
    first = true;
    foreach(arg, node->args)
    {
        if (!first)
            appendStringInfoString(buf, ", ");
        if (use_variadic && lnext(arg) == NULL)
            appendStringInfoString(buf, "VARIADIC ");
        deparseExpr((Expr *) lfirst(arg), context);
        first = false;
    }
    appendStringInfoChar(buf, ')');

    ReleaseSysCache(proctup);
}

void deparseInsertSql ( StringInfo  buf,
PlannerInfo root,
Index  rtindex,
Relation  rel,
List targetAttrs,
List returningList,
List **  retrieved_attrs 
)

Definition at line 830 of file deparse.c.

References appendStringInfo(), appendStringInfoString(), deparseColumnRef(), deparseRelation(), deparseReturningList(), and lfirst_int.

Referenced by postgresPlanForeignModify().

{
    AttrNumber  pindex;
    bool        first;
    ListCell   *lc;

    appendStringInfoString(buf, "INSERT INTO ");
    deparseRelation(buf, rel);

    if (targetAttrs)
    {
        appendStringInfoString(buf, "(");

        first = true;
        foreach(lc, targetAttrs)
        {
            int         attnum = lfirst_int(lc);

            if (!first)
                appendStringInfoString(buf, ", ");
            first = false;

            deparseColumnRef(buf, rtindex, attnum, root);
        }

        appendStringInfoString(buf, ") VALUES (");

        pindex = 1;
        first = true;
        foreach(lc, targetAttrs)
        {
            if (!first)
                appendStringInfoString(buf, ", ");
            first = false;

            appendStringInfo(buf, "$%d", pindex);
            pindex++;
        }

        appendStringInfoString(buf, ")");
    }
    else
        appendStringInfoString(buf, " DEFAULT VALUES");

    if (returningList)
        deparseReturningList(buf, root, rtindex, rel, returningList,
                             retrieved_attrs);
    else
        *retrieved_attrs = NIL;
}

static void deparseNullTest ( NullTest node,
deparse_expr_cxt context 
) [static]

Definition at line 1778 of file deparse.c.

References appendStringInfoChar(), appendStringInfoString(), NullTest::arg, deparse_expr_cxt::buf, buf, deparseExpr(), IS_NULL, and NullTest::nulltesttype.

Referenced by deparseExpr().

{
    StringInfo  buf = context->buf;

    appendStringInfoChar(buf, '(');
    deparseExpr(node->arg, context);
    if (node->nulltesttype == IS_NULL)
        appendStringInfoString(buf, " IS NULL)");
    else
        appendStringInfoString(buf, " IS NOT NULL)");
}

static void deparseOperatorName ( StringInfo  buf,
Form_pg_operator  opform 
) [static]

Definition at line 1633 of file deparse.c.

References appendStringInfo(), get_namespace_name(), NameStr, PG_CATALOG_NAMESPACE, and quote_identifier().

Referenced by deparseOpExpr(), and deparseScalarArrayOpExpr().

{
    char       *opname;

    /* opname is not a SQL identifier, so we should not quote it. */
    opname = NameStr(opform->oprname);

    /* Print schema name only if it's not pg_catalog */
    if (opform->oprnamespace != PG_CATALOG_NAMESPACE)
    {
        const char *opnspname;

        opnspname = get_namespace_name(opform->oprnamespace);
        /* Print fully qualified operator name. */
        appendStringInfo(buf, "OPERATOR(%s.%s)",
                         quote_identifier(opnspname), opname);
    }
    else
    {
        /* Just print operator name. */
        appendStringInfo(buf, "%s", opname);
    }
}

static void deparseOpExpr ( OpExpr node,
deparse_expr_cxt context 
) [static]

Definition at line 1582 of file deparse.c.

References appendStringInfoChar(), arg, OpExpr::args, Assert, deparse_expr_cxt::buf, buf, deparseExpr(), deparseOperatorName(), elog, ERROR, GETSTRUCT, HeapTupleIsValid, lfirst, list_head(), list_length(), list_tail(), ObjectIdGetDatum, OPEROID, OpExpr::opno, ReleaseSysCache(), and SearchSysCache1.

Referenced by deparseExpr().

{
    StringInfo  buf = context->buf;
    HeapTuple   tuple;
    Form_pg_operator form;
    char        oprkind;
    ListCell   *arg;

    /* Retrieve information about the operator from system catalog. */
    tuple = SearchSysCache1(OPEROID, ObjectIdGetDatum(node->opno));
    if (!HeapTupleIsValid(tuple))
        elog(ERROR, "cache lookup failed for operator %u", node->opno);
    form = (Form_pg_operator) GETSTRUCT(tuple);
    oprkind = form->oprkind;

    /* Sanity check. */
    Assert((oprkind == 'r' && list_length(node->args) == 1) ||
           (oprkind == 'l' && list_length(node->args) == 1) ||
           (oprkind == 'b' && list_length(node->args) == 2));

    /* Always parenthesize the expression. */
    appendStringInfoChar(buf, '(');

    /* Deparse left operand. */
    if (oprkind == 'r' || oprkind == 'b')
    {
        arg = list_head(node->args);
        deparseExpr(lfirst(arg), context);
        appendStringInfoChar(buf, ' ');
    }

    /* Deparse operator name. */
    deparseOperatorName(buf, form);

    /* Deparse right operand. */
    if (oprkind == 'l' || oprkind == 'b')
    {
        arg = list_tail(node->args);
        appendStringInfoChar(buf, ' ');
        deparseExpr(lfirst(arg), context);
    }

    appendStringInfoChar(buf, ')');

    ReleaseSysCache(tuple);
}

static void deparseParam ( Param node,
deparse_expr_cxt context 
) [static]

Definition at line 1406 of file deparse.c.

References appendStringInfo(), deparse_expr_cxt::buf, buf, equal(), format_type_with_typemod(), lappend(), lfirst, NULL, deparse_expr_cxt::params_list, Param::paramtype, and Param::paramtypmod.

Referenced by deparseExpr().

{
    StringInfo  buf = context->buf;

    if (context->params_list)
    {
        int         pindex = 0;
        ListCell   *lc;

        /* find its index in params_list */
        foreach(lc, *context->params_list)
        {
            pindex++;
            if (equal(node, (Node *) lfirst(lc)))
                break;
        }
        if (lc == NULL)
        {
            /* not in list, so add it */
            pindex++;
            *context->params_list = lappend(*context->params_list, node);
        }

        appendStringInfo(buf, "$%d", pindex);
        appendStringInfo(buf, "::%s",
                         format_type_with_typemod(node->paramtype,
                                                  node->paramtypmod));
    }
    else
    {
        appendStringInfo(buf, "(SELECT null::%s)",
                         format_type_with_typemod(node->paramtype,
                                                  node->paramtypmod));
    }
}

static void deparseRelabelType ( RelabelType node,
deparse_expr_cxt context 
) [static]
static void deparseRelation ( StringInfo  buf,
Relation  rel 
) [static]

Definition at line 1108 of file deparse.c.

References appendStringInfo(), defGetString(), DefElem::defname, get_namespace_name(), GetForeignTable(), lfirst, NULL, ForeignTable::options, quote_identifier(), RelationGetNamespace, RelationGetRelationName, and RelationGetRelid.

Referenced by deparseAnalyzeSizeSql(), deparseAnalyzeSql(), deparseDeleteSql(), deparseInsertSql(), deparseSelectSql(), and deparseUpdateSql().

{
    ForeignTable *table;
    const char *nspname = NULL;
    const char *relname = NULL;
    ListCell   *lc;

    /* obtain additional catalog information. */
    table = GetForeignTable(RelationGetRelid(rel));

    /*
     * Use value of FDW options if any, instead of the name of object itself.
     */
    foreach(lc, table->options)
    {
        DefElem    *def = (DefElem *) lfirst(lc);

        if (strcmp(def->defname, "schema_name") == 0)
            nspname = defGetString(def);
        else if (strcmp(def->defname, "table_name") == 0)
            relname = defGetString(def);
    }

    /*
     * Note: we could skip printing the schema name if it's pg_catalog, but
     * that doesn't seem worth the trouble.
     */
    if (nspname == NULL)
        nspname = get_namespace_name(RelationGetNamespace(rel));
    if (relname == NULL)
        relname = RelationGetRelationName(rel);

    appendStringInfo(buf, "%s.%s",
                     quote_identifier(nspname), quote_identifier(relname));
}

static void deparseReturningList ( StringInfo  buf,
PlannerInfo root,
Index  rtindex,
Relation  rel,
List returningList,
List **  retrieved_attrs 
) [static]

Definition at line 956 of file deparse.c.

References appendStringInfoString(), deparseTargetList(), and pull_varattnos().

Referenced by deparseDeleteSql(), deparseInsertSql(), and deparseUpdateSql().

{
    Bitmapset  *attrs_used;

    /*
     * We need the attrs mentioned in the query's RETURNING list.
     */
    attrs_used = NULL;
    pull_varattnos((Node *) returningList, rtindex,
                   &attrs_used);

    appendStringInfoString(buf, " RETURNING ");
    deparseTargetList(buf, root, rtindex, rel, attrs_used,
                      retrieved_attrs);
}

static void deparseScalarArrayOpExpr ( ScalarArrayOpExpr node,
deparse_expr_cxt context 
) [static]

Definition at line 1679 of file deparse.c.

References appendStringInfo(), appendStringInfoChar(), ScalarArrayOpExpr::args, Assert, deparse_expr_cxt::buf, buf, deparseExpr(), deparseOperatorName(), elog, ERROR, GETSTRUCT, HeapTupleIsValid, linitial, list_length(), lsecond, ObjectIdGetDatum, OPEROID, ScalarArrayOpExpr::opno, ReleaseSysCache(), SearchSysCache1, and ScalarArrayOpExpr::useOr.

Referenced by deparseExpr().

{
    StringInfo  buf = context->buf;
    HeapTuple   tuple;
    Form_pg_operator form;
    Expr       *arg1;
    Expr       *arg2;

    /* Retrieve information about the operator from system catalog. */
    tuple = SearchSysCache1(OPEROID, ObjectIdGetDatum(node->opno));
    if (!HeapTupleIsValid(tuple))
        elog(ERROR, "cache lookup failed for operator %u", node->opno);
    form = (Form_pg_operator) GETSTRUCT(tuple);

    /* Sanity check. */
    Assert(list_length(node->args) == 2);

    /* Always parenthesize the expression. */
    appendStringInfoChar(buf, '(');

    /* Deparse left operand. */
    arg1 = linitial(node->args);
    deparseExpr(arg1, context);
    appendStringInfoChar(buf, ' ');

    /* Deparse operator name plus decoration. */
    deparseOperatorName(buf, form);
    appendStringInfo(buf, " %s (", node->useOr ? "ANY" : "ALL");

    /* Deparse right operand. */
    arg2 = lsecond(node->args);
    deparseExpr(arg2, context);

    appendStringInfoChar(buf, ')');

    /* Always parenthesize the expression. */
    appendStringInfoChar(buf, ')');

    ReleaseSysCache(tuple);
}

void deparseSelectSql ( StringInfo  buf,
PlannerInfo root,
RelOptInfo baserel,
Bitmapset attrs_used,
List **  retrieved_attrs 
)

Definition at line 662 of file deparse.c.

References appendStringInfoString(), deparseRelation(), deparseTargetList(), heap_close, heap_open(), NoLock, planner_rt_fetch, RangeTblEntry::relid, and RelOptInfo::relid.

Referenced by estimate_path_cost_size(), and postgresGetForeignPlan().

{
    RangeTblEntry *rte = planner_rt_fetch(baserel->relid, root);
    Relation    rel;

    /*
     * Core code already has some lock on each rel being planned, so we can
     * use NoLock here.
     */
    rel = heap_open(rte->relid, NoLock);

    /*
     * Construct SELECT list
     */
    appendStringInfoString(buf, "SELECT ");
    deparseTargetList(buf, root, baserel->relid, rel, attrs_used,
                      retrieved_attrs);

    /*
     * Construct FROM clause
     */
    appendStringInfoString(buf, " FROM ");
    deparseRelation(buf, rel);

    heap_close(rel, NoLock);
}

static void deparseStringLiteral ( StringInfo  buf,
const char *  val 
) [static]

Definition at line 1148 of file deparse.c.

References appendStringInfoChar(), ESCAPE_STRING_SYNTAX, NULL, and SQL_STR_DOUBLE.

Referenced by deparseAnalyzeSizeSql(), and deparseConst().

{
    const char *valptr;

    /*
     * Rather than making assumptions about the remote server's value of
     * standard_conforming_strings, always use E'foo' syntax if there are any
     * backslashes.  This will fail on remote servers before 8.1, but those
     * are long out of support.
     */
    if (strchr(val, '\\') != NULL)
        appendStringInfoChar(buf, ESCAPE_STRING_SYNTAX);
    appendStringInfoChar(buf, '\'');
    for (valptr = val; *valptr; valptr++)
    {
        char        ch = *valptr;

        if (SQL_STR_DOUBLE(ch, true))
            appendStringInfoChar(buf, ch);
        appendStringInfoChar(buf, ch);
    }
    appendStringInfoChar(buf, '\'');
}

static void deparseTargetList ( StringInfo  buf,
PlannerInfo root,
Index  rtindex,
Relation  rel,
Bitmapset attrs_used,
List **  retrieved_attrs 
) [static]

Definition at line 701 of file deparse.c.

References appendStringInfoString(), tupleDesc::attrs, bms_is_member(), deparseColumnRef(), FirstLowInvalidHeapAttributeNumber, i, lappend_int(), tupleDesc::natts, RelationGetDescr, and SelfItemPointerAttributeNumber.

Referenced by deparseReturningList(), and deparseSelectSql().

{
    TupleDesc   tupdesc = RelationGetDescr(rel);
    bool        have_wholerow;
    bool        first;
    int         i;

    *retrieved_attrs = NIL;

    /* If there's a whole-row reference, we'll need all the columns. */
    have_wholerow = bms_is_member(0 - FirstLowInvalidHeapAttributeNumber,
                                  attrs_used);

    first = true;
    for (i = 1; i <= tupdesc->natts; i++)
    {
        Form_pg_attribute attr = tupdesc->attrs[i - 1];

        /* Ignore dropped attributes. */
        if (attr->attisdropped)
            continue;

        if (have_wholerow ||
            bms_is_member(i - FirstLowInvalidHeapAttributeNumber,
                          attrs_used))
        {
            if (!first)
                appendStringInfoString(buf, ", ");
            first = false;

            deparseColumnRef(buf, rtindex, i, root);

            *retrieved_attrs = lappend_int(*retrieved_attrs, i);
        }
    }

    /*
     * Add ctid if needed.  We currently don't support retrieving any other
     * system columns.
     */
    if (bms_is_member(SelfItemPointerAttributeNumber - FirstLowInvalidHeapAttributeNumber,
                      attrs_used))
    {
        if (!first)
            appendStringInfoString(buf, ", ");
        first = false;

        appendStringInfoString(buf, "ctid");

        *retrieved_attrs = lappend_int(*retrieved_attrs,
                                       SelfItemPointerAttributeNumber);
    }

    /* Don't generate bad syntax if no undropped columns */
    if (first)
        appendStringInfoString(buf, "NULL");
}

void deparseUpdateSql ( StringInfo  buf,
PlannerInfo root,
Index  rtindex,
Relation  rel,
List targetAttrs,
List returningList,
List **  retrieved_attrs 
)

Definition at line 892 of file deparse.c.

References appendStringInfo(), appendStringInfoString(), deparseColumnRef(), deparseRelation(), deparseReturningList(), and lfirst_int.

Referenced by postgresPlanForeignModify().

{
    AttrNumber  pindex;
    bool        first;
    ListCell   *lc;

    appendStringInfoString(buf, "UPDATE ");
    deparseRelation(buf, rel);
    appendStringInfoString(buf, " SET ");

    pindex = 2;                 /* ctid is always the first param */
    first = true;
    foreach(lc, targetAttrs)
    {
        int         attnum = lfirst_int(lc);

        if (!first)
            appendStringInfoString(buf, ", ");
        first = false;

        deparseColumnRef(buf, rtindex, attnum, root);
        appendStringInfo(buf, " = $%d", pindex);
        pindex++;
    }
    appendStringInfoString(buf, " WHERE ctid = $1");

    if (returningList)
        deparseReturningList(buf, root, rtindex, rel, returningList,
                             retrieved_attrs);
    else
        *retrieved_attrs = NIL;
}

static void deparseVar ( Var node,
deparse_expr_cxt context 
) [static]

Definition at line 1242 of file deparse.c.

References appendStringInfo(), deparse_expr_cxt::buf, buf, deparseColumnRef(), equal(), deparse_expr_cxt::foreignrel, format_type_with_typemod(), lappend(), lfirst, NULL, deparse_expr_cxt::params_list, RelOptInfo::relid, deparse_expr_cxt::root, Var::varattno, Var::varlevelsup, Var::varno, Var::vartype, and Var::vartypmod.

Referenced by deparseExpr().

{
    StringInfo  buf = context->buf;

    if (node->varno == context->foreignrel->relid &&
        node->varlevelsup == 0)
    {
        /* Var belongs to foreign table */
        deparseColumnRef(buf, node->varno, node->varattno, context->root);
    }
    else
    {
        /* Treat like a Param */
        if (context->params_list)
        {
            int         pindex = 0;
            ListCell   *lc;

            /* find its index in params_list */
            foreach(lc, *context->params_list)
            {
                pindex++;
                if (equal(node, (Node *) lfirst(lc)))
                    break;
            }
            if (lc == NULL)
            {
                /* not in list, so add it */
                pindex++;
                *context->params_list = lappend(*context->params_list, node);
            }

            appendStringInfo(buf, "$%d", pindex);
            appendStringInfo(buf, "::%s",
                             format_type_with_typemod(node->vartype,
                                                      node->vartypmod));
        }
        else
        {
            appendStringInfo(buf, "(SELECT null::%s)",
                             format_type_with_typemod(node->vartype,
                                                      node->vartypmod));
        }
    }
}

static bool foreign_expr_walker ( Node node,
foreign_glob_cxt glob_cxt,
foreign_loc_cxt outer_cxt 
) [static]

Definition at line 217 of file deparse.c.

References NullTest::arg, RelabelType::arg, BoolExpr::args, ScalarArrayOpExpr::args, OpExpr::args, FuncExpr::args, ArrayExpr::array_collid, foreign_loc_cxt::collation, Const::constcollid, DEFAULT_COLLATION_OID, ArrayExpr::elements, exprType(), FDW_COLLATE_NONE, FDW_COLLATE_SAFE, FDW_COLLATE_UNSAFE, fe(), foreign_glob_cxt::foreignrel, FuncExpr::funccollid, FuncExpr::funcid, ScalarArrayOpExpr::inputcollid, OpExpr::inputcollid, FuncExpr::inputcollid, InvalidOid, is_builtin(), lfirst, nodeTag, NULL, OidIsValid, OpExpr::opcollid, ScalarArrayOpExpr::opno, OpExpr::opno, Param::paramcollid, ArrayRef::refassgnexpr, ArrayRef::refcollid, ArrayRef::refexpr, ArrayRef::reflowerindexpr, ArrayRef::refupperindexpr, RelOptInfo::relid, RelabelType::resultcollid, foreign_loc_cxt::state, T_ArrayExpr, T_ArrayRef, T_BoolExpr, T_Const, T_DistinctExpr, T_FuncExpr, T_List, T_NullTest, T_OpExpr, T_Param, T_RelabelType, T_ScalarArrayOpExpr, T_Var, Var::varcollid, Var::varlevelsup, and Var::varno.

Referenced by is_foreign_expr().

{
    bool        check_type = true;
    foreign_loc_cxt inner_cxt;
    Oid         collation;
    FDWCollateState state;

    /* Need do nothing for empty subexpressions */
    if (node == NULL)
        return true;

    /* Set up inner_cxt for possible recursion to child nodes */
    inner_cxt.collation = InvalidOid;
    inner_cxt.state = FDW_COLLATE_NONE;

    switch (nodeTag(node))
    {
        case T_Var:
            {
                Var        *var = (Var *) node;

                /*
                 * If the Var is from the foreign table, we consider its
                 * collation (if any) safe to use.  If it is from another
                 * table, we treat its collation the same way as we would a
                 * Param's collation, ie it's not safe for it to have a
                 * non-default collation.
                 */
                if (var->varno == glob_cxt->foreignrel->relid &&
                    var->varlevelsup == 0)
                {
                    /* Var belongs to foreign table */
                    collation = var->varcollid;
                    state = OidIsValid(collation) ? FDW_COLLATE_SAFE : FDW_COLLATE_NONE;
                }
                else
                {
                    /* Var belongs to some other table */
                    if (var->varcollid != InvalidOid &&
                        var->varcollid != DEFAULT_COLLATION_OID)
                        return false;

                    /* We can consider that it doesn't set collation */
                    collation = InvalidOid;
                    state = FDW_COLLATE_NONE;
                }
            }
            break;
        case T_Const:
            {
                Const      *c = (Const *) node;

                /*
                 * If the constant has nondefault collation, either it's of a
                 * non-builtin type, or it reflects folding of a CollateExpr;
                 * either way, it's unsafe to send to the remote.
                 */
                if (c->constcollid != InvalidOid &&
                    c->constcollid != DEFAULT_COLLATION_OID)
                    return false;

                /* Otherwise, we can consider that it doesn't set collation */
                collation = InvalidOid;
                state = FDW_COLLATE_NONE;
            }
            break;
        case T_Param:
            {
                Param      *p = (Param *) node;

                /*
                 * Collation handling is same as for Consts.
                 */
                if (p->paramcollid != InvalidOid &&
                    p->paramcollid != DEFAULT_COLLATION_OID)
                    return false;

                collation = InvalidOid;
                state = FDW_COLLATE_NONE;
            }
            break;
        case T_ArrayRef:
            {
                ArrayRef   *ar = (ArrayRef *) node;;

                /* Assignment should not be in restrictions. */
                if (ar->refassgnexpr != NULL)
                    return false;

                /*
                 * Recurse to remaining subexpressions.  Since the array
                 * subscripts must yield (noncollatable) integers, they won't
                 * affect the inner_cxt state.
                 */
                if (!foreign_expr_walker((Node *) ar->refupperindexpr,
                                         glob_cxt, &inner_cxt))
                    return false;
                if (!foreign_expr_walker((Node *) ar->reflowerindexpr,
                                         glob_cxt, &inner_cxt))
                    return false;
                if (!foreign_expr_walker((Node *) ar->refexpr,
                                         glob_cxt, &inner_cxt))
                    return false;

                /*
                 * Array subscripting should yield same collation as input,
                 * but for safety use same logic as for function nodes.
                 */
                collation = ar->refcollid;
                if (collation == InvalidOid)
                    state = FDW_COLLATE_NONE;
                else if (inner_cxt.state == FDW_COLLATE_SAFE &&
                         collation == inner_cxt.collation)
                    state = FDW_COLLATE_SAFE;
                else
                    state = FDW_COLLATE_UNSAFE;
            }
            break;
        case T_FuncExpr:
            {
                FuncExpr   *fe = (FuncExpr *) node;

                /*
                 * If function used by the expression is not built-in, it
                 * can't be sent to remote because it might have incompatible
                 * semantics on remote side.
                 */
                if (!is_builtin(fe->funcid))
                    return false;

                /*
                 * Recurse to input subexpressions.
                 */
                if (!foreign_expr_walker((Node *) fe->args,
                                         glob_cxt, &inner_cxt))
                    return false;

                /*
                 * If function's input collation is not derived from a foreign
                 * Var, it can't be sent to remote.
                 */
                if (fe->inputcollid == InvalidOid)
                     /* OK, inputs are all noncollatable */ ;
                else if (inner_cxt.state != FDW_COLLATE_SAFE ||
                         fe->inputcollid != inner_cxt.collation)
                    return false;

                /*
                 * Detect whether node is introducing a collation not derived
                 * from a foreign Var.  (If so, we just mark it unsafe for now
                 * rather than immediately returning false, since the parent
                 * node might not care.)
                 */
                collation = fe->funccollid;
                if (collation == InvalidOid)
                    state = FDW_COLLATE_NONE;
                else if (inner_cxt.state == FDW_COLLATE_SAFE &&
                         collation == inner_cxt.collation)
                    state = FDW_COLLATE_SAFE;
                else
                    state = FDW_COLLATE_UNSAFE;
            }
            break;
        case T_OpExpr:
        case T_DistinctExpr:    /* struct-equivalent to OpExpr */
            {
                OpExpr     *oe = (OpExpr *) node;

                /*
                 * Similarly, only built-in operators can be sent to remote.
                 * (If the operator is, surely its underlying function is
                 * too.)
                 */
                if (!is_builtin(oe->opno))
                    return false;

                /*
                 * Recurse to input subexpressions.
                 */
                if (!foreign_expr_walker((Node *) oe->args,
                                         glob_cxt, &inner_cxt))
                    return false;

                /*
                 * If operator's input collation is not derived from a foreign
                 * Var, it can't be sent to remote.
                 */
                if (oe->inputcollid == InvalidOid)
                     /* OK, inputs are all noncollatable */ ;
                else if (inner_cxt.state != FDW_COLLATE_SAFE ||
                         oe->inputcollid != inner_cxt.collation)
                    return false;

                /* Result-collation handling is same as for functions */
                collation = oe->opcollid;
                if (collation == InvalidOid)
                    state = FDW_COLLATE_NONE;
                else if (inner_cxt.state == FDW_COLLATE_SAFE &&
                         collation == inner_cxt.collation)
                    state = FDW_COLLATE_SAFE;
                else
                    state = FDW_COLLATE_UNSAFE;
            }
            break;
        case T_ScalarArrayOpExpr:
            {
                ScalarArrayOpExpr *oe = (ScalarArrayOpExpr *) node;

                /*
                 * Again, only built-in operators can be sent to remote.
                 */
                if (!is_builtin(oe->opno))
                    return false;

                /*
                 * Recurse to input subexpressions.
                 */
                if (!foreign_expr_walker((Node *) oe->args,
                                         glob_cxt, &inner_cxt))
                    return false;

                /*
                 * If operator's input collation is not derived from a foreign
                 * Var, it can't be sent to remote.
                 */
                if (oe->inputcollid == InvalidOid)
                     /* OK, inputs are all noncollatable */ ;
                else if (inner_cxt.state != FDW_COLLATE_SAFE ||
                         oe->inputcollid != inner_cxt.collation)
                    return false;

                /* Output is always boolean and so noncollatable. */
                collation = InvalidOid;
                state = FDW_COLLATE_NONE;
            }
            break;
        case T_RelabelType:
            {
                RelabelType *r = (RelabelType *) node;

                /*
                 * Recurse to input subexpression.
                 */
                if (!foreign_expr_walker((Node *) r->arg,
                                         glob_cxt, &inner_cxt))
                    return false;

                /*
                 * RelabelType must not introduce a collation not derived from
                 * an input foreign Var.
                 */
                collation = r->resultcollid;
                if (collation == InvalidOid)
                    state = FDW_COLLATE_NONE;
                else if (inner_cxt.state == FDW_COLLATE_SAFE &&
                         collation == inner_cxt.collation)
                    state = FDW_COLLATE_SAFE;
                else
                    state = FDW_COLLATE_UNSAFE;
            }
            break;
        case T_BoolExpr:
            {
                BoolExpr   *b = (BoolExpr *) node;

                /*
                 * Recurse to input subexpressions.
                 */
                if (!foreign_expr_walker((Node *) b->args,
                                         glob_cxt, &inner_cxt))
                    return false;

                /* Output is always boolean and so noncollatable. */
                collation = InvalidOid;
                state = FDW_COLLATE_NONE;
            }
            break;
        case T_NullTest:
            {
                NullTest   *nt = (NullTest *) node;

                /*
                 * Recurse to input subexpressions.
                 */
                if (!foreign_expr_walker((Node *) nt->arg,
                                         glob_cxt, &inner_cxt))
                    return false;

                /* Output is always boolean and so noncollatable. */
                collation = InvalidOid;
                state = FDW_COLLATE_NONE;
            }
            break;
        case T_ArrayExpr:
            {
                ArrayExpr  *a = (ArrayExpr *) node;

                /*
                 * Recurse to input subexpressions.
                 */
                if (!foreign_expr_walker((Node *) a->elements,
                                         glob_cxt, &inner_cxt))
                    return false;

                /*
                 * ArrayExpr must not introduce a collation not derived from
                 * an input foreign Var.
                 */
                collation = a->array_collid;
                if (collation == InvalidOid)
                    state = FDW_COLLATE_NONE;
                else if (inner_cxt.state == FDW_COLLATE_SAFE &&
                         collation == inner_cxt.collation)
                    state = FDW_COLLATE_SAFE;
                else
                    state = FDW_COLLATE_UNSAFE;
            }
            break;
        case T_List:
            {
                List       *l = (List *) node;
                ListCell   *lc;

                /*
                 * Recurse to component subexpressions.
                 */
                foreach(lc, l)
                {
                    if (!foreign_expr_walker((Node *) lfirst(lc),
                                             glob_cxt, &inner_cxt))
                        return false;
                }

                /*
                 * When processing a list, collation state just bubbles up
                 * from the list elements.
                 */
                collation = inner_cxt.collation;
                state = inner_cxt.state;

                /* Don't apply exprType() to the list. */
                check_type = false;
            }
            break;
        default:

            /*
             * If it's anything else, assume it's unsafe.  This list can be
             * expanded later, but don't forget to add deparse support below.
             */
            return false;
    }

    /*
     * If result type of given expression is not built-in, it can't be sent to
     * remote because it might have incompatible semantics on remote side.
     */
    if (check_type && !is_builtin(exprType(node)))
        return false;

    /*
     * Now, merge my collation information into my parent's state.
     */
    if (state > outer_cxt->state)
    {
        /* Override previous parent state */
        outer_cxt->collation = collation;
        outer_cxt->state = state;
    }
    else if (state == outer_cxt->state)
    {
        /* Merge, or detect error if there's a collation conflict */
        switch (state)
        {
            case FDW_COLLATE_NONE:
                /* Nothing + nothing is still nothing */
                break;
            case FDW_COLLATE_SAFE:
                if (collation != outer_cxt->collation)
                {
                    /*
                     * Non-default collation always beats default.
                     */
                    if (outer_cxt->collation == DEFAULT_COLLATION_OID)
                    {
                        /* Override previous parent state */
                        outer_cxt->collation = collation;
                    }
                    else if (collation != DEFAULT_COLLATION_OID)
                    {
                        /*
                         * Conflict; show state as indeterminate.  We don't
                         * want to "return false" right away, since parent
                         * node might not care about collation.
                         */
                        outer_cxt->state = FDW_COLLATE_UNSAFE;
                    }
                }
                break;
            case FDW_COLLATE_UNSAFE:
                /* We're still conflicted ... */
                break;
        }
    }

    /* It looks OK */
    return true;
}

static bool is_builtin ( Oid  procid  )  [static]

Definition at line 647 of file deparse.c.

References FirstBootstrapObjectId.

Referenced by foreign_expr_walker().

{
    return (oid < FirstBootstrapObjectId);
}

bool is_foreign_expr ( PlannerInfo root,
RelOptInfo baserel,
Expr expr 
)

Definition at line 168 of file deparse.c.

References Assert, foreign_loc_cxt::collation, contain_mutable_functions(), FDW_COLLATE_NONE, foreign_expr_walker(), foreign_glob_cxt::foreignrel, InvalidOid, foreign_glob_cxt::root, and foreign_loc_cxt::state.

Referenced by classifyConditions(), postgresGetForeignPaths(), and postgresGetForeignPlan().

{
    foreign_glob_cxt glob_cxt;
    foreign_loc_cxt loc_cxt;

    /*
     * Check that the expression consists of nodes that are safe to execute
     * remotely.
     */
    glob_cxt.root = root;
    glob_cxt.foreignrel = baserel;
    loc_cxt.collation = InvalidOid;
    loc_cxt.state = FDW_COLLATE_NONE;
    if (!foreign_expr_walker((Node *) expr, &glob_cxt, &loc_cxt))
        return false;

    /* Expressions examined here should be boolean, ie noncollatable */
    Assert(loc_cxt.collation == InvalidOid);
    Assert(loc_cxt.state == FDW_COLLATE_NONE);

    /*
     * An expression which includes any mutable functions can't be sent over
     * because its result is not stable.  For example, sending now() remote
     * side could cause confusion from clock offsets.  Future versions might
     * be able to make this choice with more granularity.  (We check this last
     * because it requires a lot of expensive catalog lookups.)
     */
    if (contain_mutable_functions((Node *) expr))
        return false;

    /* OK to evaluate on the remote server */
    return true;
}