blob: 3b5b7be583a7832bbd97a69f6b2dc4ee2ff7055d [file] [log] [blame]
/*
This code implements one part of functonality of
free available library PL/Vision. Please look www.quest.com
Original author: Steven Feuerstein, 1996 - 2002
PostgreSQL implementation author: Pavel Stehule, 2006
This module is under BSD Licence
History:
1.0. first public version 22. September 2006
*/
#include "postgres.h"
#include "utils/builtins.h"
#include "utils/numeric.h"
#include "string.h"
#include "stdlib.h"
#include "utils/pg_locale.h"
#include "mb/pg_wchar.h"
#include "lib/stringinfo.h"
#include "catalog/pg_type.h"
#include "libpq/pqformat.h"
#include "utils/array.h"
#include "utils/memutils.h"
#include "utils/lsyscache.h"
#include "access/tupmacs.h"
#include "orafunc.h"
#include "builtins.h"
#include "utils/elog.h"
PG_FUNCTION_INFO_V1(dbms_utility_format_call_stack0);
PG_FUNCTION_INFO_V1(dbms_utility_format_call_stack1);
static char*
dbms_utility_format_call_stack(char mode)
{
MemoryContext oldcontext = CurrentMemoryContext;
ErrorData *edata;
ErrorContextCallback *econtext;
StringInfo sinfo;
#ifdef GP_VERSION_NUM
errstart(ERROR, __FILE__, __LINE__, PG_FUNCNAME_MACRO, TEXTDOMAIN);
#else
#if PG_VERSION_NUM >= 80400
errstart(ERROR, __FILE__, __LINE__, PG_FUNCNAME_MACRO, TEXTDOMAIN);
#else
errstart(ERROR, __FILE__, __LINE__, PG_FUNCNAME_MACRO);
#endif
#endif
MemoryContextSwitchTo(oldcontext);
for (econtext = error_context_stack;
econtext != NULL;
econtext = econtext->previous)
(*econtext->callback) (econtext->arg);
edata = CopyErrorData();
FlushErrorState();
/* Now I wont to parse edata->context to more traditional format */
/* I am not sure about order */
sinfo = makeStringInfo();
switch (mode)
{
case 'o':
appendStringInfoString(sinfo, "----- PL/pgSQL Call Stack -----\n");
appendStringInfoString(sinfo, " object line object\n");
appendStringInfoString(sinfo, " handle number name\n");
break;
}
if (edata->context)
{
char *start = edata->context;
while (*start)
{
char *oname = "anonymous object";
char *line = "";
char *eol = strchr(start, '\n');
Oid fnoid = InvalidOid;
/* first, solve multilines */
if (eol)
*eol = '\0';
/* first know format */
if (strncmp(start, "PL/pgSQL function ",18) == 0)
{
char *p1, *p2;
if ((p1 = strstr(start, "function \"")))
{
p1 += strlen("function \"");
if ((p2 = strchr(p1, '"')))
{
*p2++ = '\0';
oname = p1;
start = p2;
}
}
else if ((p1 = strstr(start, "function ")))
{
p1 += strlen("function ");
if ((p2 = strchr(p1, ')')))
{
char c = *++p2;
*p2 = '\0';
oname = pstrdup(p1);
fnoid = DatumGetObjectId(DirectFunctionCall1(regprocedurein,
CStringGetDatum(oname)));
*p2 = c;
start = p2;
}
}
if ((p1 = strstr(start, "line ")))
{
int p2i;
char c;
p1 += strlen("line ");
p2i = strspn(p1, "0123456789");
/* safe separator */
c = p1[p2i];
p1[p2i] = '\0';
line = pstrdup(p1);
p1[p2i] = c;
start = p1 + p2i;
}
}
switch (mode)
{
case 'o':
appendStringInfo(sinfo, "%8x %5s function %s", (int)fnoid, line, oname);
break;
case 'p':
appendStringInfo(sinfo, "%8d %5s function %s", (int)fnoid, line, oname);
break;
case 's':
appendStringInfo(sinfo, "%d,%s,%s", (int)fnoid, line, oname);
break;
}
if (eol)
{
start = eol + 1;
appendStringInfoChar(sinfo, '\n');
}
else
break;
}
}
return sinfo->data;
}
Datum
dbms_utility_format_call_stack0(PG_FUNCTION_ARGS)
{
PG_RETURN_TEXT_P(cstring_to_text(dbms_utility_format_call_stack('o')));
};
Datum
dbms_utility_format_call_stack1(PG_FUNCTION_ARGS)
{
text *arg = PG_GETARG_TEXT_P(0);
char mode;
if ((1 != VARSIZE(arg) - VARHDRSZ))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid parameter"),
errdetail("Allowed only chars [ops].")));
mode = *VARDATA(arg);
switch (mode)
{
case 'o':
case 'p':
case 's':
break;
default:
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid parameter"),
errdetail("Allowed only chars [ops].")));
}
PG_RETURN_TEXT_P(cstring_to_text(dbms_utility_format_call_stack(mode)));
}