/*------------------------------------------------------------------------- * * decode.c * * * Copyright (c) 2008-2009, PostgreSQL Global Developent Group * * IDENTIFICATION * $PostgreSQL: pgsql/contrib/auto_explain/auto_explain.c,v 1.4 2009/01/05 13:35:38 tgl Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" #include "fmgr.h" #include "catalog/namespace.h" #include "nodes/makefuncs.h" #include "nodes/nodeFuncs.h" #include "catalog/pg_type.h" #include "parser/parse_coerce.h" #include "parser/parse_expr.h" PG_MODULE_MAGIC; /* Saved hook value */ static ParseExprTransform_hook_type prev_transformExpr = NULL; void _PG_init(void); void _PG_fini(void); static Node * transformDecode(ParseState *pstate, Node *expr); /* * Module load callback */ void _PG_init(void) { /* Install hooks. */ prev_transformExpr = ParseExprTransform_hook; ParseExprTransform_hook = transformDecode; } /* * Module unload callback */ void _PG_fini(void) { /* Uninstall hooks. */ ParseExprTransform_hook = prev_transformExpr; } /* * Decode transform hook. When I diagnose decode func call, I transform it. */ Node * transformDecode(ParseState *pstate, Node *expr) { if (IsA(expr, FuncCall)) { FuncCall *fnc = (FuncCall *) expr; char *schemaname; char *funcname; DeconstructQualifiedName(fnc->funcname, &schemaname, &funcname); if (schemaname != NULL && strncmp(schemaname, "pg_catalog", 10) != 0) goto not_decode_func; if (strncmp(funcname, "decode", 6) == 0) { CaseExpr *newc = makeNode(CaseExpr); int pos = 0; ListCell *l; int def_pos; int nargs = list_length(fnc->args); CaseTestExpr *placeholder = NULL; CaseWhen *neww = NULL; List *newargs = NIL; List *resultexprs = NIL; Node *defresult = NULL; Oid ptype; def_pos = nargs % 2 == 0 ? nargs - 1: -1; foreach(l, fnc->args) { /* first param, generate placeholder */ if (pos == 0) { Node *arg = transformExpr(pstate, (Node *) lfirst(l)); if (exprType(arg) == UNKNOWNOID) arg = coerce_to_common_type(pstate, arg, TEXTOID, "DECODE"); placeholder = makeNode(CaseTestExpr); placeholder->typeId = exprType(arg); placeholder->typeMod = exprTypmod(arg); newc->arg = (Expr *) arg; } /* searched value, generate CaseWhen node */ if (pos % 2 != 0 && pos != def_pos) { Node *warg; Node *expr = (Node *) lfirst(l); neww = makeNode(CaseWhen); neww->location = exprLocation(expr); warg = (Node *) makeA_Expr(AEXPR_NOT, NIL, NULL, (Node *) makeSimpleA_Expr(AEXPR_DISTINCT, "=", (Node *) placeholder, expr, exprLocation(expr)), exprLocation(expr)); neww->expr = (Expr *) transformExpr(pstate, warg); neww->expr = (Expr *) coerce_to_boolean(pstate, (Node *) neww->expr, "DECODE"); } /* result value, fill last generated CaseWhen node */ if (pos % 2 == 0 && pos > 0) { neww->result = (Expr *) transformExpr(pstate, (Node *) lfirst(l));; newargs = lappend(newargs, neww); resultexprs = lappend(resultexprs, neww->result); } if (pos == def_pos) defresult = (Node *) transformExpr(pstate, (Node *) lfirst(l));; pos += 1; } newc->args = newargs; newc->location = fnc->location; if (defresult == NULL) { A_Const *n = makeNode(A_Const); n->val.type = T_Null; n->location = -1; defresult = (Node *) transformExpr(pstate, (Node *) n); } newc->defresult = (Expr *) defresult; resultexprs = lcons(newc->defresult, resultexprs); ptype = select_common_type(pstate, resultexprs, "DECODE", NULL); Assert(OidIsValid(ptype)); newc->casetype = ptype; /* Convert default result clause, if necessary */ newc->defresult = (Expr *) coerce_to_common_type(pstate, (Node *) newc->defresult, ptype, "DECODE"); /* Convert when-clause results, if necessary */ foreach(l, newc->args) { CaseWhen *w = (CaseWhen *) lfirst(l); w->result = (Expr *) coerce_to_common_type(pstate, (Node *) w->result, ptype, "DECODE"); } newc->location = fnc->location; return (Node *) newc; } } not_decode_func: if (prev_transformExpr) return prev_transformExpr(pstate, expr); else return standard_transformExpr(pstate, expr); }