44 #define HAVE_TCL_VERSION(maj,min) \
45 ((TCL_MAJOR_VERSION > maj) || \
46 (TCL_MAJOR_VERSION == maj && TCL_MINOR_VERSION >= min))
49 #if !HAVE_TCL_VERSION(8,4)
50 #error PostgreSQL only supports Tcl 8.4 or later.
58 #if !HAVE_TCL_VERSION(8,7)
64 #define TEXTDOMAIN PG_TEXTDOMAIN("pltcl")
91 const char *_pltcl_utf_src = NULL; \
92 char *_pltcl_utf_dst = NULL
95 if (_pltcl_utf_src != (const char *) _pltcl_utf_dst) \
96 pfree(_pltcl_utf_dst); \
100 (_pltcl_utf_dst = utf_u2e(_pltcl_utf_src = (x)))
103 (_pltcl_utf_dst = utf_e2u(_pltcl_utf_src = (x)))
262 #include "pltclerrcodes.h"
271 Oid prolang,
bool pltrusted);
288 bool is_event_trigger,
291 static int pltcl_elog(ClientData cdata, Tcl_Interp *interp,
292 int objc, Tcl_Obj *
const objv[]);
295 static int pltcl_quote(ClientData cdata, Tcl_Interp *interp,
296 int objc, Tcl_Obj *
const objv[]);
298 int objc, Tcl_Obj *
const objv[]);
300 int objc, Tcl_Obj *
const objv[]);
302 int objc, Tcl_Obj *
const objv[]);
304 int objc, Tcl_Obj *
const objv[]);
306 const char *arrayname,
312 int objc, Tcl_Obj *
const objv[]);
314 int objc, Tcl_Obj *
const objv[]);
316 int objc, Tcl_Obj *
const objv[]);
317 static int pltcl_commit(ClientData cdata, Tcl_Interp *interp,
318 int objc, Tcl_Obj *
const objv[]);
320 int objc, Tcl_Obj *
const objv[]);
334 Tcl_Obj **kvObjv,
int kvObjc,
353 static int fakeThreadKey;
355 return (ClientData) &(fakeThreadKey);
375 Tcl_FileProc *proc, ClientData clientData)
407 Tcl_NotifierProcs notifier;
418 Tcl_FindExecutable(
"");
432 Tcl_SetNotifier(¬ifier);
439 elog(
ERROR,
"could not create dummy Tcl interpreter");
441 elog(
ERROR,
"could not initialize dummy Tcl interpreter");
467 gettext_noop(
"PL/Tcl function to call once when pltcl is first used."),
474 gettext_noop(
"PL/TclU function to call once when pltclu is first used."),
501 snprintf(interpname,
sizeof(interpname),
"subsidiary_%u", interp_desc->
user_id);
503 pltrusted ? 1 : 0)) == NULL)
504 elog(
ERROR,
"could not create subsidiary Tcl interpreter");
509 Tcl_InitHashTable(&interp_desc->
query_hash, TCL_STRING_KEYS);
514 Tcl_CreateObjCommand(interp,
"elog",
516 Tcl_CreateObjCommand(interp,
"quote",
518 Tcl_CreateObjCommand(interp,
"argisnull",
520 Tcl_CreateObjCommand(interp,
"return_null",
522 Tcl_CreateObjCommand(interp,
"return_next",
524 Tcl_CreateObjCommand(interp,
"spi_exec",
526 Tcl_CreateObjCommand(interp,
"spi_prepare",
528 Tcl_CreateObjCommand(interp,
"spi_execp",
530 Tcl_CreateObjCommand(interp,
"subtransaction",
532 Tcl_CreateObjCommand(interp,
"commit",
534 Tcl_CreateObjCommand(interp,
"rollback",
546 interp_desc->
interp = interp;
551 interp_desc->
interp = NULL;
552 Tcl_DeleteInterp(interp);
580 interp_desc->
interp = NULL;
610 gucname = pltrusted ?
"pltcl.start_proc" :
"pltclu.start_proc";
613 if (start_proc == NULL || start_proc[0] ==
'\0')
634 elog(
ERROR,
"cache lookup failed for function %u", procOid);
638 if (procStruct->prolang != prolang)
640 (
errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
641 errmsg(
"function \"%s\" is in the wrong language",
649 if (procStruct->prosecdef)
651 (
errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
652 errmsg(
"function \"%s\" must not be SECURITY DEFINER",
683 const char *gucname = (
const char *)
arg;
686 errcontext(
"processing %s parameter", gucname);
739 memset(¤t_call_state, 0,
sizeof(current_call_state));
769 current_call_state.
fcinfo = fcinfo;
781 if (current_call_state.
prodesc != NULL)
803 Tcl_Interp *
volatile interp;
809 nonatomic = fcinfo->context &&
837 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
838 errmsg(
"set-valued function called in context that cannot accept a set")));
842 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
843 errmsg(
"materialize mode required, but it is not allowed in this context")));
845 call_state->
rsi = rsi;
854 tcl_cmd = Tcl_NewObj();
855 Tcl_ListObjAppendElement(NULL, tcl_cmd,
859 Tcl_IncrRefCount(tcl_cmd);
866 for (
i = 0;
i < prodesc->
nargs;
i++)
873 if (fcinfo->args[
i].isnull)
874 Tcl_ListObjAppendElement(NULL, tcl_cmd, Tcl_NewObj());
894 Tcl_ListObjAppendElement(NULL, tcl_cmd, list_tmp);
905 if (fcinfo->args[
i].isnull)
906 Tcl_ListObjAppendElement(NULL, tcl_cmd, Tcl_NewObj());
912 fcinfo->args[
i].value);
914 Tcl_ListObjAppendElement(NULL, tcl_cmd,
915 Tcl_NewStringObj(
UTF_E2U(tmp), -1));
925 Tcl_DecrRefCount(tcl_cmd);
935 tcl_rc = Tcl_EvalObjEx(interp, tcl_cmd, (TCL_EVAL_DIRECT | TCL_EVAL_GLOBAL));
938 Tcl_DecrRefCount(tcl_cmd);
943 if (tcl_rc != TCL_OK)
979 fcinfo->isnull =
true;
981 else if (fcinfo->isnull)
993 Tcl_Obj **resultObjv;
1015 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1016 errmsg(
"function returning record called in context "
1017 "that cannot accept type record")));
1021 elog(
ERROR,
"return type must be a row type");
1031 resultObj = Tcl_GetObjResult(interp);
1032 if (Tcl_ListObjGetElements(interp, resultObj, &resultObjc, &resultObjv) == TCL_ERROR)
1034 (
errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
1035 errmsg(
"could not parse function return value: %s",
1036 utf_u2e(Tcl_GetStringResult(interp)))));
1044 utf_u2e(Tcl_GetStringResult(interp)),
1060 Tcl_Interp *
volatile interp;
1066 Tcl_Obj *tcl_trigtup;
1071 Tcl_Obj **result_Objv;
1089 call_state->
prodesc = prodesc;
1100 tcl_cmd = Tcl_NewObj();
1101 Tcl_IncrRefCount(tcl_cmd);
1106 Tcl_ListObjAppendElement(NULL, tcl_cmd,
1110 Tcl_ListObjAppendElement(NULL, tcl_cmd,
1117 Tcl_ListObjAppendElement(NULL, tcl_cmd,
1118 Tcl_NewStringObj(stroid, -1));
1123 Tcl_ListObjAppendElement(NULL, tcl_cmd,
1124 Tcl_NewStringObj(
utf_e2u(stroid), -1));
1129 Tcl_ListObjAppendElement(NULL, tcl_cmd,
1130 Tcl_NewStringObj(
utf_e2u(stroid), -1));
1134 tcl_trigtup = Tcl_NewObj();
1135 Tcl_ListObjAppendElement(NULL, tcl_trigtup, Tcl_NewObj());
1136 for (
i = 0;
i < tupdesc->natts;
i++)
1140 if (att->attisdropped)
1141 Tcl_ListObjAppendElement(NULL, tcl_trigtup, Tcl_NewObj());
1143 Tcl_ListObjAppendElement(NULL, tcl_trigtup,
1146 Tcl_ListObjAppendElement(NULL, tcl_cmd, tcl_trigtup);
1150 Tcl_ListObjAppendElement(NULL, tcl_cmd,
1151 Tcl_NewStringObj(
"BEFORE", -1));
1153 Tcl_ListObjAppendElement(NULL, tcl_cmd,
1154 Tcl_NewStringObj(
"AFTER", -1));
1156 Tcl_ListObjAppendElement(NULL, tcl_cmd,
1157 Tcl_NewStringObj(
"INSTEAD OF", -1));
1164 Tcl_ListObjAppendElement(NULL, tcl_cmd,
1165 Tcl_NewStringObj(
"ROW", -1));
1176 Tcl_ListObjAppendElement(NULL, tcl_cmd,
1177 Tcl_NewStringObj(
"INSERT", -1));
1179 Tcl_ListObjAppendElement(NULL, tcl_cmd,
1183 Tcl_ListObjAppendElement(NULL, tcl_cmd, Tcl_NewObj());
1189 Tcl_ListObjAppendElement(NULL, tcl_cmd,
1190 Tcl_NewStringObj(
"DELETE", -1));
1192 Tcl_ListObjAppendElement(NULL, tcl_cmd, Tcl_NewObj());
1193 Tcl_ListObjAppendElement(NULL, tcl_cmd,
1202 Tcl_ListObjAppendElement(NULL, tcl_cmd,
1203 Tcl_NewStringObj(
"UPDATE", -1));
1205 Tcl_ListObjAppendElement(NULL, tcl_cmd,
1209 Tcl_ListObjAppendElement(NULL, tcl_cmd,
1221 Tcl_ListObjAppendElement(NULL, tcl_cmd,
1222 Tcl_NewStringObj(
"STATEMENT", -1));
1225 Tcl_ListObjAppendElement(NULL, tcl_cmd,
1226 Tcl_NewStringObj(
"INSERT", -1));
1228 Tcl_ListObjAppendElement(NULL, tcl_cmd,
1229 Tcl_NewStringObj(
"DELETE", -1));
1231 Tcl_ListObjAppendElement(NULL, tcl_cmd,
1232 Tcl_NewStringObj(
"UPDATE", -1));
1234 Tcl_ListObjAppendElement(NULL, tcl_cmd,
1235 Tcl_NewStringObj(
"TRUNCATE", -1));
1239 Tcl_ListObjAppendElement(NULL, tcl_cmd, Tcl_NewObj());
1240 Tcl_ListObjAppendElement(NULL, tcl_cmd, Tcl_NewObj());
1249 Tcl_ListObjAppendElement(NULL, tcl_cmd,
1254 Tcl_DecrRefCount(tcl_cmd);
1264 tcl_rc = Tcl_EvalObjEx(interp, tcl_cmd, (TCL_EVAL_DIRECT | TCL_EVAL_GLOBAL));
1267 Tcl_DecrRefCount(tcl_cmd);
1272 if (tcl_rc != TCL_OK)
1286 result = Tcl_GetStringResult(interp);
1288 if (strcmp(result,
"OK") == 0)
1290 if (strcmp(result,
"SKIP") == 0)
1297 if (Tcl_ListObjGetElements(interp, Tcl_GetObjResult(interp),
1298 &result_Objc, &result_Objv) != TCL_OK)
1300 (
errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
1301 errmsg(
"could not parse trigger return value: %s",
1302 utf_u2e(Tcl_GetStringResult(interp)))));
1319 Tcl_Interp *
volatile interp;
1331 call_state->
prodesc = prodesc;
1337 tcl_cmd = Tcl_NewObj();
1338 Tcl_IncrRefCount(tcl_cmd);
1339 Tcl_ListObjAppendElement(NULL, tcl_cmd,
1341 Tcl_ListObjAppendElement(NULL, tcl_cmd,
1343 Tcl_ListObjAppendElement(NULL, tcl_cmd,
1347 tcl_rc = Tcl_EvalObjEx(interp, tcl_cmd, (TCL_EVAL_DIRECT | TCL_EVAL_GLOBAL));
1350 Tcl_DecrRefCount(tcl_cmd);
1353 if (tcl_rc != TCL_OK)
1383 econtext =
utf_u2e(Tcl_GetVar(interp,
"errorInfo", TCL_GLOBAL_ONLY));
1389 emsglen = strlen(emsg);
1390 if (strncmp(emsg, econtext, emsglen) == 0 &&
1391 econtext[emsglen] ==
'\n')
1392 econtext += emsglen + 1;
1395 while (*econtext ==
' ')
1400 (
errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
1415 bool is_event_trigger,
bool pltrusted)
1425 Tcl_DString proc_internal_def;
1426 Tcl_DString proc_internal_name;
1427 Tcl_DString proc_internal_body;
1432 elog(
ERROR,
"cache lookup failed for function %u", fn_oid);
1456 if (prodesc != NULL &&
1474 Tcl_DStringInit(&proc_internal_def);
1475 Tcl_DStringInit(&proc_internal_name);
1476 Tcl_DStringInit(&proc_internal_body);
1480 Tcl_CmdInfo cmdinfo;
1481 const char *user_proname;
1482 const char *internal_proname;
1483 bool need_underscore;
1500 interp = interp_desc->
interp;
1510 if (prodesc != NULL &&
1536 if (is_event_trigger)
1537 Tcl_DStringAppend(&proc_internal_name,
1538 "__PLTcl_evttrigger_", -1);
1539 else if (is_trigger)
1540 Tcl_DStringAppend(&proc_internal_name,
1541 "__PLTcl_trigger_", -1);
1543 Tcl_DStringAppend(&proc_internal_name,
1544 "__PLTcl_proc_", -1);
1546 need_underscore =
false;
1547 for (
const char *ptr = user_proname; *ptr; ptr++)
1549 if (strchr(
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1550 "abcdefghijklmnopqrstuvwxyz"
1551 "0123456789_", *ptr) != NULL)
1554 if (need_underscore)
1556 Tcl_DStringAppend(&proc_internal_name,
"_", 1);
1557 need_underscore =
false;
1559 Tcl_DStringAppend(&proc_internal_name, ptr, 1);
1561 else if (strchr(
"(, ", *ptr) != NULL)
1562 need_underscore =
true;
1565 while (Tcl_GetCommandInfo(interp,
1566 Tcl_DStringValue(&proc_internal_name),
1570 Tcl_DStringAppend(&proc_internal_name,
buf, -1);
1572 internal_proname = Tcl_DStringValue(&proc_internal_name);
1590 prodesc->
fn_cxt = proc_cxt;
1594 prodesc->
nargs = procStruct->pronargs;
1601 (procStruct->provolatile != PROVOLATILE_VOLATILE);
1611 if (!is_trigger && !is_event_trigger)
1613 Oid rettype = procStruct->prorettype;
1617 elog(
ERROR,
"cache lookup failed for type %u", rettype);
1621 if (typeStruct->typtype == TYPTYPE_PSEUDO)
1623 if (rettype == VOIDOID ||
1624 rettype == RECORDOID)
1626 else if (rettype == TRIGGEROID ||
1627 rettype == EVENT_TRIGGEROID)
1629 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1630 errmsg(
"trigger functions can only be called as triggers")));
1633 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1634 errmsg(
"PL/Tcl functions cannot return type %s",
1646 prodesc->
fn_retisdomain = (typeStruct->typtype == TYPTYPE_DOMAIN);
1656 if (!is_trigger && !is_event_trigger)
1658 proc_internal_args[0] =
'\0';
1659 for (
i = 0;
i < prodesc->
nargs;
i++)
1661 Oid argtype = procStruct->proargtypes.values[
i];
1665 elog(
ERROR,
"cache lookup failed for type %u", argtype);
1669 if (typeStruct->typtype == TYPTYPE_PSEUDO &&
1670 argtype != RECORDOID)
1672 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1673 errmsg(
"PL/Tcl functions cannot accept type %s",
1691 strcat(proc_internal_args,
" ");
1692 strcat(proc_internal_args,
buf);
1697 else if (is_trigger)
1700 strcpy(proc_internal_args,
1701 "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");
1703 else if (is_event_trigger)
1706 strcpy(proc_internal_args,
"TG_event TG_tag");
1717 Tcl_DStringAppendElement(&proc_internal_def,
"proc");
1718 Tcl_DStringAppendElement(&proc_internal_def, internal_proname);
1719 Tcl_DStringAppendElement(&proc_internal_def, proc_internal_args);
1726 Tcl_DStringAppend(&proc_internal_body,
"upvar #0 ", -1);
1727 Tcl_DStringAppend(&proc_internal_body, internal_proname, -1);
1728 Tcl_DStringAppend(&proc_internal_body,
" GD\n", -1);
1731 Tcl_DStringAppend(&proc_internal_body,
1732 "array set NEW $__PLTcl_Tup_NEW\n", -1);
1733 Tcl_DStringAppend(&proc_internal_body,
1734 "array set OLD $__PLTcl_Tup_OLD\n", -1);
1735 Tcl_DStringAppend(&proc_internal_body,
1738 "foreach v $args {\n"
1742 "unset i v\n\n", -1);
1744 else if (is_event_trigger)
1750 for (
i = 0;
i < prodesc->
nargs;
i++)
1755 "array set %d $__PLTcl_Tup_%d\n",
1757 Tcl_DStringAppend(&proc_internal_body,
buf, -1);
1766 Anum_pg_proc_prosrc);
1769 Tcl_DStringAppend(&proc_internal_body,
UTF_E2U(proc_source), -1);
1772 Tcl_DStringAppendElement(&proc_internal_def,
1773 Tcl_DStringValue(&proc_internal_body));
1778 tcl_rc = Tcl_EvalEx(interp,
1779 Tcl_DStringValue(&proc_internal_def),
1780 Tcl_DStringLength(&proc_internal_def),
1782 if (tcl_rc != TCL_OK)
1784 (
errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
1785 errmsg(
"could not create internal procedure \"%s\": %s",
1787 utf_u2e(Tcl_GetStringResult(interp)))));
1797 Tcl_DStringFree(&proc_internal_def);
1798 Tcl_DStringFree(&proc_internal_name);
1799 Tcl_DStringFree(&proc_internal_body);
1819 if (old_prodesc != NULL)
1826 Tcl_DStringFree(&proc_internal_def);
1827 Tcl_DStringFree(&proc_internal_name);
1828 Tcl_DStringFree(&proc_internal_body);
1841 int objc, Tcl_Obj *
const objv[])
1847 static const char *logpriorities[] = {
1848 "DEBUG",
"LOG",
"INFO",
"NOTICE",
1849 "WARNING",
"ERROR",
"FATAL", (
const char *) NULL
1852 static const int loglevels[] = {
1859 Tcl_WrongNumArgs(interp, 1, objv,
"level msg");
1863 if (Tcl_GetIndexFromObj(interp, objv[1], logpriorities,
"priority",
1864 TCL_EXACT, &priIndex) != TCL_OK)
1867 level = loglevels[priIndex];
1876 Tcl_SetObjResult(interp, objv[2]);
1894 (
errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
1910 Tcl_SetObjResult(interp, Tcl_NewStringObj(
UTF_E2U(edata->
message), -1));
1929 Tcl_Obj *obj = Tcl_NewObj();
1931 Tcl_ListObjAppendElement(interp, obj,
1932 Tcl_NewStringObj(
"POSTGRES", -1));
1933 Tcl_ListObjAppendElement(interp, obj,
1934 Tcl_NewStringObj(PG_VERSION, -1));
1935 Tcl_ListObjAppendElement(interp, obj,
1936 Tcl_NewStringObj(
"SQLSTATE", -1));
1937 Tcl_ListObjAppendElement(interp, obj,
1939 Tcl_ListObjAppendElement(interp, obj,
1940 Tcl_NewStringObj(
"condition", -1));
1941 Tcl_ListObjAppendElement(interp, obj,
1943 Tcl_ListObjAppendElement(interp, obj,
1944 Tcl_NewStringObj(
"message", -1));
1946 Tcl_ListObjAppendElement(interp, obj,
1951 Tcl_ListObjAppendElement(interp, obj,
1952 Tcl_NewStringObj(
"detail", -1));
1954 Tcl_ListObjAppendElement(interp, obj,
1960 Tcl_ListObjAppendElement(interp, obj,
1961 Tcl_NewStringObj(
"hint", -1));
1963 Tcl_ListObjAppendElement(interp, obj,
1969 Tcl_ListObjAppendElement(interp, obj,
1970 Tcl_NewStringObj(
"context", -1));
1972 Tcl_ListObjAppendElement(interp, obj,
1978 Tcl_ListObjAppendElement(interp, obj,
1979 Tcl_NewStringObj(
"schema", -1));
1981 Tcl_ListObjAppendElement(interp, obj,
1987 Tcl_ListObjAppendElement(interp, obj,
1988 Tcl_NewStringObj(
"table", -1));
1990 Tcl_ListObjAppendElement(interp, obj,
1996 Tcl_ListObjAppendElement(interp, obj,
1997 Tcl_NewStringObj(
"column", -1));
1999 Tcl_ListObjAppendElement(interp, obj,
2005 Tcl_ListObjAppendElement(interp, obj,
2006 Tcl_NewStringObj(
"datatype", -1));
2008 Tcl_ListObjAppendElement(interp, obj,
2014 Tcl_ListObjAppendElement(interp, obj,
2015 Tcl_NewStringObj(
"constraint", -1));
2017 Tcl_ListObjAppendElement(interp, obj,
2024 Tcl_ListObjAppendElement(interp, obj,
2025 Tcl_NewStringObj(
"statement", -1));
2027 Tcl_ListObjAppendElement(interp, obj,
2033 Tcl_ListObjAppendElement(interp, obj,
2034 Tcl_NewStringObj(
"cursor_position", -1));
2035 Tcl_ListObjAppendElement(interp, obj,
2040 Tcl_ListObjAppendElement(interp, obj,
2041 Tcl_NewStringObj(
"filename", -1));
2043 Tcl_ListObjAppendElement(interp, obj,
2049 Tcl_ListObjAppendElement(interp, obj,
2050 Tcl_NewStringObj(
"lineno", -1));
2051 Tcl_ListObjAppendElement(interp, obj,
2052 Tcl_NewIntObj(edata->
lineno));
2056 Tcl_ListObjAppendElement(interp, obj,
2057 Tcl_NewStringObj(
"funcname", -1));
2059 Tcl_ListObjAppendElement(interp, obj,
2064 Tcl_SetObjErrorCode(interp, obj);
2081 return "unrecognized_sqlstate";
2091 int objc, Tcl_Obj *
const objv[])
2103 Tcl_WrongNumArgs(interp, 1, objv,
"string");
2111 cp1 = Tcl_GetStringFromObj(objv[1], &length);
2112 tmp =
palloc(length * 2 + 1);
2134 Tcl_SetObjResult(interp, Tcl_NewStringObj(tmp, -1));
2145 int objc, Tcl_Obj *
const objv[])
2155 Tcl_WrongNumArgs(interp, 1, objv,
"argno");
2164 Tcl_SetObjResult(interp,
2165 Tcl_NewStringObj(
"argisnull cannot be used in triggers", -1));
2172 if (Tcl_GetIntFromObj(interp, objv[1], &argno) != TCL_OK)
2179 if (argno < 0 || argno >= fcinfo->
nargs)
2181 Tcl_SetObjResult(interp,
2182 Tcl_NewStringObj(
"argno out of range", -1));
2189 Tcl_SetObjResult(interp, Tcl_NewBooleanObj(
PG_ARGISNULL(argno)));
2199 int objc, Tcl_Obj *
const objv[])
2208 Tcl_WrongNumArgs(interp, 1, objv,
"");
2217 Tcl_SetObjResult(interp,
2218 Tcl_NewStringObj(
"return_null cannot be used in triggers", -1));
2237 int objc, Tcl_Obj *
const objv[])
2244 volatile int result = TCL_OK;
2251 Tcl_SetObjResult(interp,
2252 Tcl_NewStringObj(
"return_next cannot be used in triggers", -1));
2258 Tcl_SetObjResult(interp,
2259 Tcl_NewStringObj(
"return_next cannot be used in non-set-returning functions", -1));
2268 Tcl_WrongNumArgs(interp, 1, objv,
"result");
2293 if (Tcl_ListObjGetElements(interp, objv[1], &rowObjc, &rowObjv) == TCL_ERROR)
2307 bool isNull =
false;
2311 elog(
ERROR,
"wrong result type supplied in return_next");
2314 utf_u2e((
char *) Tcl_GetString(objv[1])),
2395 Tcl_SetObjResult(interp, Tcl_NewStringObj(
UTF_E2U(edata->
message), -1));
2407 int objc, Tcl_Obj *
const objv[])
2415 const char *
volatile arrayname = NULL;
2416 Tcl_Obj *
volatile loop_body = NULL;
2422 OPT_ARRAY, OPT_COUNT
2425 static const char *
options[] = {
2426 "-array",
"-count", (
const char *) NULL
2434 Tcl_WrongNumArgs(interp, 1, objv,
2435 "?-count n? ?-array name? query ?loop body?");
2442 if (Tcl_GetIndexFromObj(NULL, objv[
i],
options, NULL,
2443 TCL_EXACT, &optIndex) != TCL_OK)
2448 Tcl_SetObjResult(interp,
2449 Tcl_NewStringObj(
"missing argument to -count or -array", -1));
2453 switch ((
enum options) optIndex)
2456 arrayname = Tcl_GetString(objv[
i++]);
2460 if (Tcl_GetIntFromObj(interp, objv[
i++], &count) != TCL_OK)
2467 if (query_idx >= objc || query_idx + 2 < objc)
2469 Tcl_WrongNumArgs(interp, query_idx - 1, objv,
"query ?loop body?");
2473 if (query_idx + 1 < objc)
2474 loop_body = objv[query_idx + 1];
2516 const char *arrayname,
2534 Tcl_SetObjResult(interp, Tcl_NewWideIntObj(ntuples));
2539 if (tuptable == NULL)
2541 Tcl_SetObjResult(interp, Tcl_NewIntObj(0));
2556 tuples = tuptable->
vals;
2559 if (loop_body == NULL)
2567 tuples[0], tupdesc);
2577 for (
i = 0;
i < ntuples;
i++)
2580 tuples[
i], tupdesc);
2582 loop_rc = Tcl_EvalObjEx(interp, loop_body, 0);
2584 if (loop_rc == TCL_OK)
2586 if (loop_rc == TCL_CONTINUE)
2588 if (loop_rc == TCL_RETURN)
2593 if (loop_rc == TCL_BREAK)
2600 if (my_rc == TCL_OK)
2602 Tcl_SetObjResult(interp, Tcl_NewWideIntObj(ntuples));
2607 Tcl_AppendResult(interp,
"pltcl: SPI_execute failed: ",
2629 int objc, Tcl_Obj *
const objv[])
2636 Tcl_HashEntry *hashent;
2638 Tcl_HashTable *query_hash;
2647 Tcl_WrongNumArgs(interp, 1, objv,
"query argtypes");
2654 if (Tcl_ListObjGetElements(interp, objv[2], &nargs, &argsObj) != TCL_OK)
2665 "PL/Tcl spi_prepare query",
2670 qdesc->
nargs = nargs;
2690 for (
i = 0;
i < nargs;
i++)
2698 &typId, &typmod, NULL);
2715 if (qdesc->
plan == NULL)
2743 hashent = Tcl_CreateHashEntry(query_hash, qdesc->
qname, &hashnew);
2744 Tcl_SetHashValue(hashent, (ClientData) qdesc);
2747 Tcl_SetObjResult(interp, Tcl_NewStringObj(qdesc->
qname, -1));
2757 int objc, Tcl_Obj *
const objv[])
2764 Tcl_HashEntry *hashent;
2766 const char *nulls = NULL;
2767 const char *arrayname = NULL;
2768 Tcl_Obj *loop_body = NULL;
2771 Tcl_Obj **callObjv = NULL;
2775 Tcl_HashTable *query_hash;
2779 OPT_ARRAY, OPT_COUNT, OPT_NULLS
2782 static const char *
options[] = {
2783 "-array",
"-count",
"-nulls", (
const char *) NULL
2792 if (Tcl_GetIndexFromObj(NULL, objv[
i],
options, NULL,
2793 TCL_EXACT, &optIndex) != TCL_OK)
2798 Tcl_SetObjResult(interp,
2799 Tcl_NewStringObj(
"missing argument to -array, -count or -nulls", -1));
2803 switch ((
enum options) optIndex)
2806 arrayname = Tcl_GetString(objv[
i++]);
2810 if (Tcl_GetIntFromObj(interp, objv[
i++], &count) != TCL_OK)
2815 nulls = Tcl_GetString(objv[
i++]);
2825 Tcl_SetObjResult(interp,
2826 Tcl_NewStringObj(
"missing argument to -count or -array", -1));
2832 hashent = Tcl_FindHashEntry(query_hash, Tcl_GetString(objv[
i]));
2833 if (hashent == NULL)
2835 Tcl_AppendResult(interp,
"invalid queryid '", Tcl_GetString(objv[
i]),
"'", NULL);
2846 if (strlen(nulls) != qdesc->
nargs)
2848 Tcl_SetObjResult(interp,
2849 Tcl_NewStringObj(
"length of nulls string doesn't match number of arguments",
2859 if (qdesc->
nargs > 0)
2863 Tcl_SetObjResult(interp,
2864 Tcl_NewStringObj(
"argument list length doesn't match number of arguments for query",
2872 if (Tcl_ListObjGetElements(interp, objv[
i++], &callObjc, &callObjv) != TCL_OK)
2878 if (callObjc != qdesc->
nargs)
2880 Tcl_SetObjResult(interp,
2881 Tcl_NewStringObj(
"argument list length doesn't match number of arguments for query",
2893 loop_body = objv[
i++];
2897 Tcl_WrongNumArgs(interp, 1, objv,
2898 "?-count n? ?-array name? ?-nulls string? "
2899 "query ?args? ?loop body?");
2918 for (
j = 0;
j < callObjc;
j++)
2920 if (nulls && nulls[
j] ==
'n')
2931 UTF_U2E(Tcl_GetString(callObjv[
j])),
2973 int objc, Tcl_Obj *
const objv[])
2981 Tcl_WrongNumArgs(interp, 1, objv,
"command");
2993 retcode = Tcl_EvalObjEx(interp, objv[1], 0);
2995 if (retcode == TCL_ERROR)
3021 int objc, Tcl_Obj *
const objv[])
3041 Tcl_SetObjResult(interp, Tcl_NewStringObj(
UTF_E2U(edata->
message), -1));
3060 int objc, Tcl_Obj *
const objv[])
3080 Tcl_SetObjResult(interp, Tcl_NewStringObj(
UTF_E2U(edata->
message), -1));
3109 const char **arrptr;
3110 const char **nameptr;
3111 const char *nullname = NULL;
3116 if (arrayname == NULL)
3119 nameptr = &nullname;
3123 arrptr = &arrayname;
3131 Tcl_SetVar2Ex(interp, arrayname,
".tupno", Tcl_NewWideIntObj(tupno), 0);
3134 for (
i = 0;
i < tupdesc->
natts;
i++)
3139 if (att->attisdropped)
3167 Tcl_SetVar2Ex(interp, *arrptr, *nameptr,
3168 Tcl_NewStringObj(
UTF_E2U(outputstr), -1), 0);
3173 Tcl_UnsetVar2(interp, *arrptr, *nameptr, 0);
3187 Tcl_Obj *retobj = Tcl_NewObj();
3196 for (
i = 0;
i < tupdesc->
natts;
i++)
3201 if (att->attisdropped)
3204 if (att->attgenerated)
3207 if (!include_generated)
3232 &typoutput, &typisvarlena);
3235 Tcl_ListObjAppendElement(NULL, retobj,
3239 Tcl_ListObjAppendElement(NULL, retobj,
3240 Tcl_NewStringObj(
UTF_E2U(outputstr), -1));
3282 elog(
ERROR,
"PL/Tcl function does not return a tuple");
3289 if (kvObjc % 2 != 0)
3291 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3292 errmsg(
"column name/value list must have even number of elements")));
3294 for (
i = 0;
i < kvObjc;
i += 2)
3296 char *fieldName =
utf_u2e(Tcl_GetString(kvObjv[
i]));
3306 if (strcmp(fieldName,
".tupno") == 0)
3309 (
errcode(ERRCODE_UNDEFINED_COLUMN),
3310 errmsg(
"column name/value list contains nonexistent column name \"%s\"",
3316 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3317 errmsg(
"cannot set system attribute \"%s\"",
3322 (
errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
3323 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, long nelem, const HASHCTL *info, int flags)
void FreeErrorData(ErrorData *edata)
ErrorContextCallback * error_context_stack
void FlushErrorState(void)
char * unpack_sql_state(int sql_state)
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
ErrorData * CopyErrorData(void)
#define ereport(elevel,...)
#define CALLED_AS_EVENT_TRIGGER(fcinfo)
HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
AttInMetadata * TupleDescGetAttInMetadata(TupleDesc tupdesc)
@ SFRM_Materialize_Random
Datum InputFunctionCall(FmgrInfo *flinfo, char *str, Oid typioparam, int32 typmod)
void fmgr_info(Oid functionId, FmgrInfo *finfo)
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
char * OidOutputFunctionCall(Oid functionId, Datum val)
char * OutputFunctionCall(FmgrInfo *flinfo, Datum val)
#define DatumGetHeapTupleHeader(X)
#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo)
#define DirectFunctionCall1(func, arg1)
#define LOCAL_FCINFO(name, nargs)
#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)
#define HeapTupleHeaderGetTypMod(tup)
#define HeapTupleHeaderGetTypeId(tup)
#define HeapTupleHeaderGetDatumLength(tup)
#define HeapTupleHeaderGetRawXmin(tup)
if(TABLE==NULL||TABLE_index==NULL)
bool ItemPointerEquals(ItemPointer pointer1, ItemPointer 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)
MemoryContext TopMemoryContext
void * palloc0(Size size)
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)
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
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)
PG_FUNCTION_INFO_V1(pltcl_call_handler)
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 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 char * utf_e2u(const char *src)
static int pltcl_quote(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
struct pltcl_proc_desc pltcl_proc_desc
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
struct pltcl_proc_key pltcl_proc_key
static pltcl_interp_desc * pltcl_fetch_interp(Oid prolang, bool pltrusted)
struct pltcl_interp_desc pltcl_interp_desc
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)
struct pltcl_query_desc pltcl_query_desc
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[])
struct pltcl_call_state pltcl_call_state
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)
static char * utf_u2e(const char *src)
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[])
struct pltcl_proc_ptr pltcl_proc_ptr
static int pltcl_commit(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
static Datum PointerGetDatum(const void *X)
static char * DatumGetCString(Datum X)
static Datum ObjectIdGetDatum(Oid X)
static int fd(const char *x, int i)
MemoryContextSwitchTo(old_ctx)
char * format_procedure(Oid procedure_oid)
List * stringToQualifiedNameList(const char *string, Node *escontext)
#define RelationGetRelid(relation)
#define RelationGetDescr(relation)
ResourceOwner CurrentResourceOwner
char * SPI_getrelname(Relation rel)
int SPI_fnumber(TupleDesc tupdesc, const char *fname)
SPITupleTable * SPI_tuptable
const char * SPI_result_code_string(int code)
int SPI_execute_plan(SPIPlanPtr plan, 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)
char * SPI_getnspname(Relation rel)
int SPI_connect_ext(int options)
int SPI_execute(const char *src, bool read_only, long tcount)
#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)
#define TupleDescAttr(tupdesc, 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)