From baeef0e1727bb3299bba05c147df274d6a561458 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sat, 26 Feb 2000 21:13:18 +0000 Subject: [PATCH] Change rule dumper to produce reasonable output for casts that assign a specific length or precision, such as foo::char(8). Remove erroneous removal of user-written casts at the top level of a SELECT target item. --- src/backend/utils/adt/ruleutils.c | 174 ++++++++++++++---------------- 1 file changed, 82 insertions(+), 92 deletions(-) diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 985c0c0309..bdeaf44082 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -3,7 +3,7 @@ * out of its tuple * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.43 2000/02/21 20:18:10 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.44 2000/02/26 21:13:18 tgl Exp $ * * This software is copyrighted by Jan Wieck - Hamburg. * @@ -49,6 +49,7 @@ #include "optimizer/clauses.h" #include "optimizer/tlist.h" #include "parser/keywords.h" +#include "parser/parse_expr.h" #include "parser/parsetree.h" #include "utils/builtins.h" #include "utils/lsyscache.h" @@ -947,7 +948,8 @@ get_select_query_def(Query *query, deparse_context *context) appendStringInfo(buf, sep); sep = ", "; - get_tle_expr(tle, context); + /* Do NOT use get_tle_expr here; see its comments! */ + get_rule_expr(tle->expr, context); /* Check if we must say AS ... */ if (! IsA(tle->expr, Var)) @@ -1486,16 +1488,16 @@ static void get_func_expr(Expr *expr, deparse_context *context) { StringInfo buf = context->buf; + Func *func = (Func *) (expr->oper); HeapTuple proctup; Form_pg_proc procStruct; + char *proname; + int32 coercedTypmod; List *l; char *sep; - Func *func = (Func *) (expr->oper); - char *proname; - /* ---------- + /* * Get the functions pg_proc tuple - * ---------- */ proctup = SearchSysCacheTuple(PROCOID, ObjectIdGetDatum(func->funcid), @@ -1527,9 +1529,59 @@ get_func_expr(Expr *expr, deparse_context *context) } } - /* ---------- - * Build a string of proname(args) - * ---------- + /* + * Check to see if function is a length-coercion function for some + * datatype. If so, display the operation as a type cast. + */ + if (exprIsLengthCoercion((Node *) expr, &coercedTypmod)) + { + Node *arg = lfirst(expr->args); + + /* + * Strip off any RelabelType on the input, so we don't print + * redundancies like x::bpchar::char(8). + * XXX Are there any cases where this is a bad idea? + */ + if (IsA(arg, RelabelType)) + arg = ((RelabelType *) arg)->arg; + appendStringInfoChar(buf, '('); + get_rule_expr(arg, context); + appendStringInfo(buf, ")::"); + /* + * Show typename with appropriate length decoration. + * Note that since exprIsLengthCoercion succeeded, the function + * name is the same as its output type name. + */ + if (strcmp(proname, "bpchar") == 0) + { + if (coercedTypmod > VARHDRSZ) + appendStringInfo(buf, "char(%d)", coercedTypmod - VARHDRSZ); + else + appendStringInfo(buf, "char"); + } + else if (strcmp(proname, "varchar") == 0) + { + if (coercedTypmod > VARHDRSZ) + appendStringInfo(buf, "varchar(%d)", coercedTypmod - VARHDRSZ); + else + appendStringInfo(buf, "varchar"); + } + else if (strcmp(proname, "numeric") == 0) + { + if (coercedTypmod >= VARHDRSZ) + appendStringInfo(buf, "numeric(%d,%d)", + ((coercedTypmod - VARHDRSZ) >> 16) & 0xffff, + (coercedTypmod - VARHDRSZ) & 0xffff); + else + appendStringInfo(buf, "numeric"); + } + else + appendStringInfo(buf, "%s", quote_identifier(proname)); + return; + } + + /* + * Normal function: display as proname(args) */ appendStringInfo(buf, "%s(", quote_identifier(proname)); sep = ""; @@ -1546,99 +1598,37 @@ get_func_expr(Expr *expr, deparse_context *context) /* ---------- * get_tle_expr * - * A target list expression is a bit different from a normal expression. - * If the target column has an atttypmod, the parser usually puts a - * padding-/cut-function call around the expression itself. - * We must get rid of it, otherwise dump/reload/dump... would blow up - * the expressions. + * In an INSERT or UPDATE targetlist item, the parser may have inserted + * a length-coercion function call to coerce the value to the right + * length for the target column. We want to suppress the output of + * that function call, otherwise dump/reload/dump... would blow up the + * expression by adding more and more layers of length-coercion calls. + * + * As of 7.0, this hack is no longer absolutely essential, because the parser + * is now smart enough not to add a redundant length coercion function call. + * But we still suppress the function call just for neatness of displayed + * rules. + * + * Note that this hack must NOT be applied to SELECT targetlist items; + * any length coercion appearing there is something the user actually wrote. * ---------- */ static void get_tle_expr(TargetEntry *tle, deparse_context *context) { Expr *expr = (Expr *) (tle->expr); - Func *func; - HeapTuple tup; - Form_pg_proc procStruct; - Form_pg_type typeStruct; - Const *second_arg; - - /* ---------- - * Check if the result has an atttypmod and if the - * expression in the targetlist entry is a function call - * ---------- - */ - if (tle->resdom->restypmod < 0 || - ! IsA(expr, Expr) || - expr->opType != FUNC_EXPR) - { - get_rule_expr(tle->expr, context); - return; - } - - func = (Func *) (expr->oper); - - /* ---------- - * Get the functions pg_proc tuple - * ---------- - */ - tup = SearchSysCacheTuple(PROCOID, - ObjectIdGetDatum(func->funcid), 0, 0, 0); - if (!HeapTupleIsValid(tup)) - elog(ERROR, "cache lookup for proc %u failed", func->funcid); - procStruct = (Form_pg_proc) GETSTRUCT(tup); - - /* ---------- - * It must be a function with two arguments where the first - * is of the same type as the return value and the second is - * an int4. - * ---------- - */ - if (procStruct->pronargs != 2 || - procStruct->prorettype != procStruct->proargtypes[0] || - procStruct->proargtypes[1] != INT4OID) - { - get_rule_expr(tle->expr, context); - return; - } + int32 coercedTypmod; /* - * Furthermore, the name of the function must be the same - * as the argument/result type name. - */ - tup = SearchSysCacheTuple(TYPEOID, - ObjectIdGetDatum(procStruct->prorettype), - 0, 0, 0); - if (!HeapTupleIsValid(tup)) - elog(ERROR, "cache lookup for type %u failed", - procStruct->prorettype); - typeStruct = (Form_pg_type) GETSTRUCT(tup); - if (strncmp(NameStr(procStruct->proname), - NameStr(typeStruct->typname), - NAMEDATALEN) != 0) - { - get_rule_expr(tle->expr, context); - return; - } - - /* ---------- - * Finally (to be totally safe) the second argument must be a - * const and match the value in the results atttypmod. - * ---------- + * If top level is a length coercion to the correct length, suppress it; + * else dump the expression normally. */ - second_arg = (Const *) lsecond(expr->args); - if (! IsA(second_arg, Const) || - DatumGetInt32(second_arg->constvalue) != tle->resdom->restypmod) - { + if (tle->resdom->restypmod >= 0 && + exprIsLengthCoercion((Node *) expr, &coercedTypmod) && + coercedTypmod == tle->resdom->restypmod) + get_rule_expr((Node *) lfirst(expr->args), context); + else get_rule_expr(tle->expr, context); - return; - } - - /* ---------- - * Whow - got it. Now get rid of the padding function - * ---------- - */ - get_rule_expr((Node *) lfirst(expr->args), context); } -- GitLab