pgpool2.git / summary / log / commit / refs

commit    952d3a52ae5946c9aa0d04fb5a962520012dcde5
Author:   Tatsuo Ishii <ishii at sraoss.co.jp>
Date:     Wed Jan 26 01:11:32 2011 +0000

    Fix pgpool-regclass().
    It appeared that using PG_TRY/CATCH is not safe, sometimes backend
    dies with PANIC:  ERRORDATA_STACK_SIZE exceeded.
    The only solution is stealing some functions from PostgreSQL
    and modify it not to throw errors.
    This is not elegant at all but PostgreSQL developers do not allow
    to add such that built-in functions. Sigh.


sql/pgpool-regclass/pgpool-regclass.c | 121 ++++++++++++++++++++++++++++++---- 1 file changed, 110 insertions(+), 11 deletions(-) diff --git a/sql/pgpool-regclass/pgpool-regclass.c b/sql/pgpool-regclass/pgpool-regclass.c index 9e98fff7d..f5b9de52a 100644 --- a/sql/pgpool-regclass/pgpool-regclass.c +++ b/sql/pgpool-regclass/pgpool-regclass.c @@ -2,7 +2,7 @@ /* * $Header$ * - * Copyright (c) 2003-2010 PgPool Global Development Group + * Copyright (c) 2003-2011 PgPool Global Development Group * * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose and without fee is hereby @@ -16,11 +16,8 @@ * is" without express or implied warranty. * * pgpool-regclass.c is similar to PostgreSQL builtin function - * reglcass but do not throw exception. + * reglcass but does not throw exceptions. * If something goes wrong, it returns InvalidOid. - * - * CAUTION: This function uses PG_TRY() and related family macros which - * are only available on 8.0 or later. */ #include <sys/types.h> @@ -29,6 +26,9 @@ #include "postgres.h" #include "utils/builtins.h" #include "utils/elog.h" +#include "catalog/namespace.h" +#include "nodes/makefuncs.h" +#include "commands/dbcommands.h" #include "fmgr.h" #include "funcapi.h" @@ -42,22 +42,121 @@ PG_FUNCTION_INFO_V1(pgpool_regclass); extern Datum pgpool_regclass(PG_FUNCTION_ARGS); +static List * +MystringToQualifiedNameList(const char *string); + +static RangeVar * +MymakeRangeVarFromNameList(List *names); + +extern Oid MyDatabaseId; + Datum pgpool_regclass(PG_FUNCTION_ARGS) { char *pro_name_or_oid = PG_GETARG_CSTRING(0); Oid result; + List *names; + RangeVar *rel; - PG_TRY(); + names = MystringToQualifiedNameList(pro_name_or_oid); + if (names == NIL) + PG_RETURN_OID(InvalidOid); + + rel = MymakeRangeVarFromNameList(names); + if (rel == NULL) + PG_RETURN_OID(InvalidOid); + + /* + * Check to see if cross-database reference is used. + * This is to be done in RangeVarGetRelid(). The reason + * we do this here is, to avoid raising an error + * in RangeVarGetRelid(). + */ + if (rel->catalogname) { - result = DirectFunctionCall1(regclassin, - CStringGetDatum(pro_name_or_oid)); + if (strcmp(rel->catalogname, get_database_name(MyDatabaseId)) != 0) + PG_RETURN_OID(InvalidOid); } - PG_CATCH(); + + /* + * Check to see if schema exists. + * This is to be done in RangeVarGetRelid(). The reason + * we do this here is, to avoid raising an error + * in RangeVarGetRelid(). + */ + if (rel->schemaname) { - result = InvalidOid; + if (LookupNamespaceNoError(rel->schemaname) == InvalidOid) + PG_RETURN_OID(InvalidOid); } - PG_END_TRY(); + + result = RangeVarGetRelid(rel, true); PG_RETURN_OID(result); } + +/* + * Given a C string, parse it into a qualified-name list. + * Stolen from PostgreSQL, removing elog calls. + */ +static List * +MystringToQualifiedNameList(const char *string) +{ + char *rawname; + List *result = NIL; + List *namelist; + ListCell *l; + + /* We need a modifiable copy of the input string. */ + rawname = pstrdup(string); + + if (!SplitIdentifierString(rawname, '.', &namelist)) + return NIL; + + if (namelist == NIL) + return NIL; + + foreach(l, namelist) + { + char *curname = (char *) lfirst(l); + + result = lappend(result, makeString(pstrdup(curname))); + } + + pfree(rawname); + list_free(namelist); + + return result; +} + +/* + * makeRangeVarFromNameList + * Utility routine to convert a qualified-name list into RangeVar form. + * Stolen from PostgreSQL, removing ereport calls. + */ +static RangeVar * +MymakeRangeVarFromNameList(List *names) +{ + RangeVar *rel = makeRangeVar(NULL, NULL, -1); + + switch (list_length(names)) + { + case 1: + rel->relname = strVal(linitial(names)); + break; + case 2: + rel->schemaname = strVal(linitial(names)); + rel->relname = strVal(lsecond(names)); + break; + case 3: + rel->catalogname = strVal(linitial(names)); + rel->schemaname = strVal(lsecond(names)); + rel->relname = strVal(lthird(names)); + break; + default: + rel = NULL; + break; + } + + return rel; +} [parent: 87c98274dd81]