47#define HAVE_TCL_VERSION(maj,min) \
48 ((TCL_MAJOR_VERSION > maj) || \
49 (TCL_MAJOR_VERSION == maj && TCL_MINOR_VERSION >= min))
52#if !HAVE_TCL_VERSION(8,4)
53#error PostgreSQL only supports Tcl 8.4 or later.
61#if !HAVE_TCL_VERSION(8,7)
67#define TEXTDOMAIN PG_TEXTDOMAIN("pltcl")
94 const char *_pltcl_utf_src = NULL; \
95 char *_pltcl_utf_dst = NULL
98 if (_pltcl_utf_src != (const char *) _pltcl_utf_dst) \
99 pfree(_pltcl_utf_dst); \
103 (_pltcl_utf_dst = utf_u2e(_pltcl_utf_src = (x)))
106 (_pltcl_utf_dst = utf_e2u(_pltcl_utf_src = (x)))
265#include "pltclerrcodes.h"
442 elog(
ERROR,
"could not create dummy Tcl interpreter");
444 elog(
ERROR,
"could not initialize dummy Tcl interpreter");
470 gettext_noop(
"PL/Tcl function to call once when pltcl is first used."),
477 gettext_noop(
"PL/TclU function to call once when pltclu is first used."),
506 pltrusted ? 1 : 0)) ==
NULL)
507 elog(
ERROR,
"could not create subsidiary Tcl interpreter");
549 interp_desc->
interp = interp;
613 gucname = pltrusted ?
"pltcl.start_proc" :
"pltclu.start_proc";
644 errmsg(
"function \"%s\" is in the wrong language",
655 errmsg(
"function \"%s\" must not be SECURITY DEFINER",
686 const char *gucname = (
const char *)
arg;
689 errcontext(
"processing %s parameter", gucname);
841 errmsg(
"set-valued function called in context that cannot accept a set")));
846 errmsg(
"materialize mode required, but it is not allowed in this context")));
869 for (
i = 0;
i < prodesc->
nargs;
i++)
876 if (fcinfo->args[
i].isnull)
908 if (fcinfo->args[
i].isnull)
915 fcinfo->args[
i].value);
982 fcinfo->isnull =
true;
984 else if (fcinfo->isnull)
1019 errmsg(
"function returning record called in context "
1020 "that cannot accept type record")));
1024 elog(
ERROR,
"return type must be a row type");
1038 errmsg(
"could not parse function return value: %s",
1139 for (
i = 0;
i < tupdesc->
natts;
i++)
1143 if (
att->attisdropped)
1291 if (
strcmp(result,
"OK") == 0)
1293 if (
strcmp(result,
"SKIP") == 0)
1304 errmsg(
"could not parse trigger return value: %s",
1398 while (*econtext ==
' ')
1435 elog(
ERROR,
"cache lookup failed for function %u", fn_oid);
1459 if (prodesc !=
NULL &&
1484 const char *user_proname;
1485 const char *internal_proname;
1503 interp = interp_desc->
interp;
1513 if (prodesc !=
NULL &&
1541 "__PLTcl_evttrigger_", -1);
1542 else if (is_trigger)
1544 "__PLTcl_trigger_", -1);
1547 "__PLTcl_proc_", -1);
1550 for (
const char *ptr = user_proname; *ptr; ptr++)
1552 if (
strchr(
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1553 "abcdefghijklmnopqrstuvwxyz"
1554 "0123456789_", *ptr) !=
NULL)
1620 elog(
ERROR,
"cache lookup failed for type %u", rettype);
1633 errmsg(
"trigger functions can only be called as triggers")));
1637 errmsg(
"PL/Tcl functions cannot return type %s",
1662 for (
i = 0;
i < prodesc->
nargs;
i++)
1668 elog(
ERROR,
"cache lookup failed for type %u", argtype);
1676 errmsg(
"PL/Tcl functions cannot accept type %s",
1700 else if (is_trigger)
1704 "TG_name TG_relid TG_table_name TG_table_schema TG_relatts TG_when TG_level TG_op __PLTcl_Tup_NEW __PLTcl_Tup_OLD args");
1735 "array set NEW $__PLTcl_Tup_NEW\n", -1);
1737 "array set OLD $__PLTcl_Tup_OLD\n", -1);
1741 "foreach v $args {\n"
1745 "unset i v\n\n", -1);
1753 for (
i = 0;
i < prodesc->
nargs;
i++)
1758 "array set %d $__PLTcl_Tup_%d\n",
1788 errmsg(
"could not create internal procedure \"%s\": %s",
1851 "DEBUG",
"LOG",
"INFO",
"NOTICE",
1852 "WARNING",
"ERROR",
"FATAL", (
const char *)
NULL
1979 if (
edata->schema_name)
1988 if (
edata->table_name)
1997 if (
edata->column_name)
2006 if (
edata->datatype_name)
2015 if (
edata->constraint_name)
2025 if (
edata->internalquery)
2034 if (
edata->internalpos > 0)
2041 if (
edata->filename)
2050 if (
edata->lineno > 0)
2057 if (
edata->funcname)
2084 return "unrecognized_sqlstate";
2115 tmp =
palloc(length * 2 + 1);
2247 volatile int result =
TCL_OK;
2262 Tcl_NewStringObj(
"return_next cannot be used in non-set-returning functions", -1));
2310 bool isNull =
false;
2314 elog(
ERROR,
"wrong result type supplied in return_next");
2428 static const char *
options[] = {
2429 "-array",
"-count", (
const char *)
NULL
2438 "?-count n? ?-array name? query ?loop body?");
2542 if (tuptable ==
NULL)
2559 tuples = tuptable->
vals;
2570 tuples[0], tupdesc);
2580 for (
i = 0;
i < ntuples;
i++)
2583 tuples[
i], tupdesc);
2668 "PL/Tcl spi_prepare query",
2673 qdesc->nargs = nargs;
2693 for (
i = 0;
i < nargs;
i++)
2715 nargs,
qdesc->argtypes);
2769 const char *nulls =
NULL;
2785 static const char *
options[] = {
2786 "-array",
"-count",
"-nulls", (
const char *)
NULL
2852 Tcl_NewStringObj(
"length of nulls string doesn't match number of arguments",
2862 if (
qdesc->nargs > 0)
2867 Tcl_NewStringObj(
"argument list length doesn't match number of arguments for query",
2884 Tcl_NewStringObj(
"argument list length doesn't match number of arguments for query",
2901 "?-count n? ?-array name? ?-nulls string? "
2902 "query ?args? ?loop body?");
2923 if (nulls && nulls[
j] ==
'n')
2927 qdesc->argtypioparams[
j],
2935 qdesc->argtypioparams[
j],
3137 for (
i = 0;
i < tupdesc->
natts;
i++)
3142 if (
att->attisdropped)
3199 for (
i = 0;
i < tupdesc->
natts;
i++)
3204 if (
att->attisdropped)
3207 if (
att->attgenerated)
3238 &typoutput, &typisvarlena);
3288 elog(
ERROR,
"PL/Tcl function does not return a tuple");
3298 errmsg(
"column name/value list must have even number of elements")));
3312 if (
strcmp(fieldName,
".tupno") == 0)
3316 errmsg(
"column name/value list contains nonexistent column name \"%s\"",
3323 errmsg(
"cannot set system attribute \"%s\"",
3329 errmsg(
"cannot set generated column \"%s\"",
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
static Datum values[MAXATTR]
#define TextDatumGetCString(d)
#define unconstify(underlying_type, expr)
#define PG_USED_FOR_ASSERTS_ONLY
#define Assert(condition)
#define OidIsValid(objectId)
const char * GetCommandTagName(CommandTag commandTag)
void domain_check(Datum value, bool isnull, Oid domainType, void **extra, MemoryContext mcxt)
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
HTAB * hash_create(const char *tabname, int64 nelem, const HASHCTL *info, int flags)
void FreeErrorData(ErrorData *edata)
ErrorContextCallback * error_context_stack
ErrorData * CopyErrorData(void)
void FlushErrorState(void)
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
char * unpack_sql_state(int sql_state)
#define ereport(elevel,...)
#define CALLED_AS_EVENT_TRIGGER(fcinfo)
HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
AttInMetadata * TupleDescGetAttInMetadata(TupleDesc tupdesc)
@ SFRM_Materialize_Random
#define palloc0_object(type)
Datum InputFunctionCall(FmgrInfo *flinfo, char *str, Oid typioparam, int32 typmod)
void fmgr_info(Oid functionId, FmgrInfo *finfo)
char * OidOutputFunctionCall(Oid functionId, Datum val)
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
char * OutputFunctionCall(FmgrInfo *flinfo, Datum val)
#define DatumGetHeapTupleHeader(X)
#define PG_MODULE_MAGIC_EXT(...)
#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo)
#define DirectFunctionCall1(func, arg1)
#define LOCAL_FCINFO(name, nargs)
#define PG_FUNCTION_INFO_V1(funcname)
#define FunctionCallInvoke(fcinfo)
TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo, Oid *resultTypeId, TupleDesc *resultTupleDesc)
@ TYPEFUNC_COMPOSITE_DOMAIN
static Datum HeapTupleGetDatum(const HeapTupleData *tuple)
void DefineCustomStringVariable(const char *name, const char *short_desc, const char *long_desc, char **valueAddr, const char *bootValue, GucContext context, int flags, GucStringCheckHook check_hook, GucStringAssignHook assign_hook, GucShowHook show_hook)
void MarkGUCPrefixReserved(const char *className)
HeapTupleData * HeapTuple
#define HeapTupleIsValid(tuple)
static Datum heap_getattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
static int32 HeapTupleHeaderGetTypMod(const HeapTupleHeaderData *tup)
static TransactionId HeapTupleHeaderGetRawXmin(const HeapTupleHeaderData *tup)
static uint32 HeapTupleHeaderGetDatumLength(const HeapTupleHeaderData *tup)
static void * GETSTRUCT(const HeapTupleData *tuple)
static Oid HeapTupleHeaderGetTypeId(const HeapTupleHeaderData *tup)
bool ItemPointerEquals(const ItemPointerData *pointer1, const ItemPointerData *pointer2)
bool type_is_rowtype(Oid typid)
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
void getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
Oid getTypeIOParam(HeapTuple typeTuple)
char * pg_any_to_server(const char *s, int len, int encoding)
char * pg_server_to_any(const char *s, int len, int encoding)
char * pstrdup(const char *in)
void pfree(void *pointer)
void * palloc0(Size size)
MemoryContext TopMemoryContext
MemoryContext CurrentMemoryContext
void MemoryContextDelete(MemoryContext context)
void MemoryContextSetIdentifier(MemoryContext context, const char *id)
#define AllocSetContextCreate
#define ALLOCSET_SMALL_SIZES
void pg_bindtextdomain(const char *domain)
#define IsA(nodeptr, _type_)
#define castNode(_type_, nodeptr)
#define InvokeFunctionExecuteHook(objectId)
Datum oidout(PG_FUNCTION_ARGS)
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool missing_ok)
bool parseTypeString(const char *str, Oid *typeid_p, int32 *typmod_p, Node *escontext)
FormData_pg_attribute * Form_pg_attribute
static PgChecksumMode mode
FormData_pg_proc * Form_pg_proc
static char buf[DEFAULT_XLOG_SEG_SIZE]
FormData_pg_type * Form_pg_type
void pgstat_init_function_usage(FunctionCallInfo fcinfo, PgStat_FunctionCallUsage *fcu)
void pgstat_end_function_usage(PgStat_FunctionCallUsage *fcu, bool finalize)
static HeapTuple pltcl_trigger_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state, bool pltrusted)
static void pltcl_ServiceModeHook(int mode)
static const char * pltcl_get_condition_name(int sqlstate)
static HTAB * pltcl_proc_htab
static void pltcl_AlertNotifier(ClientData clientData)
static char * utf_e2u(const char *src)
static int pltcl_WaitForEvent(CONST86 Tcl_Time *timePtr)
static void pltcl_init_tuple_store(pltcl_call_state *call_state)
static Tcl_Obj * pltcl_build_tuple_argument(HeapTuple tuple, TupleDesc tupdesc, bool include_generated)
static pltcl_proc_desc * compile_pltcl_function(Oid fn_oid, Oid tgreloid, bool is_event_trigger, bool pltrusted)
static void call_pltcl_start_proc(Oid prolang, bool pltrusted)
static int pltcl_returnnext(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
static void pltcl_SetTimer(CONST86 Tcl_Time *timePtr)
static int pltcl_SPI_execute(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
static int pltcl_process_SPI_result(Tcl_Interp *interp, const char *arrayname, Tcl_Obj *loop_body, int spi_rc, SPITupleTable *tuptable, uint64 ntuples)
static int pltcl_elog(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
static void pltcl_subtrans_abort(Tcl_Interp *interp, MemoryContext oldcontext, ResourceOwner oldowner)
static void pltcl_DeleteFileHandler(int fd)
static int pltcl_quote(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
static void pltcl_FinalizeNotifier(ClientData clientData)
static void throw_tcl_error(Tcl_Interp *interp, const char *proname)
static void pltcl_CreateFileHandler(int fd, int mask, Tcl_FileProc *proc, ClientData clientData)
static int pltcl_SPI_prepare(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
static char * pltcl_start_proc
static Datum pltcl_handler(PG_FUNCTION_ARGS, bool pltrusted)
static HTAB * pltcl_interp_htab
static pltcl_interp_desc * pltcl_fetch_interp(Oid prolang, bool pltrusted)
static pltcl_call_state * pltcl_current_call_state
static void pltcl_init_interp(pltcl_interp_desc *interp_desc, Oid prolang, bool pltrusted)
static void pltcl_construct_errorCode(Tcl_Interp *interp, ErrorData *edata)
static char * pltclu_start_proc
static void pltcl_event_trigger_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state, bool pltrusted)
static ClientData pltcl_InitNotifier(void)
static char * utf_u2e(const char *src)
static const TclExceptionNameMap exception_name_map[]
static int pltcl_rollback(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
static void pltcl_set_tuple_values(Tcl_Interp *interp, const char *arrayname, uint64 tupno, HeapTuple tuple, TupleDesc tupdesc)
Datum pltclu_call_handler(PG_FUNCTION_ARGS)
static void start_proc_error_callback(void *arg)
static int pltcl_argisnull(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
static int pltcl_returnnull(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
static void pltcl_subtrans_begin(MemoryContext oldcontext, ResourceOwner oldowner)
static Datum pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state, bool pltrusted)
static Tcl_Interp * pltcl_hold_interp
static int pltcl_SPI_execute_plan(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
static void pltcl_subtrans_commit(MemoryContext oldcontext, ResourceOwner oldowner)
static HeapTuple pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc, pltcl_call_state *call_state)
Datum pltcl_call_handler(PG_FUNCTION_ARGS)
static bool pltcl_pm_init_done
static int pltcl_subtransaction(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
static int pltcl_commit(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
static Datum PointerGetDatum(const void *X)
static Datum ObjectIdGetDatum(Oid X)
static char * DatumGetCString(Datum X)
static int fd(const char *x, int i)
char * format_procedure(Oid procedure_oid)
List * stringToQualifiedNameList(const char *string, Node *escontext)
#define RelationGetRelid(relation)
#define RelationGetDescr(relation)
ResourceOwner CurrentResourceOwner
int SPI_fnumber(TupleDesc tupdesc, const char *fname)
const char * SPI_result_code_string(int code)
SPITupleTable * SPI_tuptable
int SPI_execute_plan(SPIPlanPtr plan, const Datum *Values, const char *Nulls, bool read_only, long tcount)
int SPI_register_trigger_data(TriggerData *tdata)
void SPI_freetuptable(SPITupleTable *tuptable)
SPIPlanPtr SPI_prepare(const char *src, int nargs, Oid *argtypes)
int SPI_keepplan(SPIPlanPtr plan)
int SPI_connect_ext(int options)
char * SPI_getnspname(Relation rel)
int SPI_execute(const char *src, bool read_only, long tcount)
char * SPI_getrelname(Relation rel)
#define SPI_OPT_NONATOMIC
#define SPI_OK_UPDATE_RETURNING
#define SPI_ERROR_NOATTRIBUTE
#define SPI_OK_INSERT_RETURNING
#define SPI_OK_DELETE_RETURNING
#define SPI_OK_MERGE_RETURNING
struct ErrorContextCallback * previous
void(* callback)(void *arg)
MemoryContext ecxt_per_query_memory
SetFunctionReturnMode returnMode
Tuplestorestate * setResult
pltcl_proc_desc * prodesc
MemoryContext tuple_store_cxt
Tuplestorestate * tuple_store
ResourceOwner tuple_store_owner
AttInMetadata * attinmeta
pltcl_interp_desc * interp_desc
unsigned long fn_refcount
pltcl_proc_desc * proc_ptr
void ReleaseSysCache(HeapTuple tuple)
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Datum SysCacheGetAttrNotNull(int cacheId, HeapTuple tup, AttrNumber attributeNumber)
#define TRIGGER_FIRED_FOR_STATEMENT(event)
#define TRIGGER_FIRED_BY_DELETE(event)
#define TRIGGER_FIRED_BEFORE(event)
#define CALLED_AS_TRIGGER(fcinfo)
#define TRIGGER_FIRED_FOR_ROW(event)
#define TRIGGER_FIRED_AFTER(event)
#define TRIGGER_FIRED_BY_TRUNCATE(event)
#define TRIGGER_FIRED_BY_INSERT(event)
#define TRIGGER_FIRED_BY_UPDATE(event)
#define TRIGGER_FIRED_INSTEAD(event)
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
#define ReleaseTupleDesc(tupdesc)
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, const Datum *values, const bool *isnull)
void tuplestore_puttuple(Tuplestorestate *state, HeapTuple tuple)
TupleDesc lookup_rowtype_tupdesc(Oid type_id, int32 typmod)
void BeginInternalSubTransaction(const char *name)
void RollbackAndReleaseCurrentSubTransaction(void)
void ReleaseCurrentSubTransaction(void)