diff -c -r pgsql.00/src/backend/utils/misc/guc.c psql.01/src/backend/utils/misc/guc.c *** pgsql.00/src/backend/utils/misc/guc.c 2005-06-28 07:09:00.000000000 +0200 --- psql.01/src/backend/utils/misc/guc.c 2005-07-03 16:59:29.000000000 +0200 *************** *** 157,163 **** char *HbaFileName; char *IdentFileName; char *external_pid_file; ! /* * These variables are all dummies that don't do anything, except in some --- 157,163 ---- char *HbaFileName; char *IdentFileName; char *external_pid_file; ! bool trace_plpgsql; /* * These variables are all dummies that don't do anything, except in some *************** *** 530,535 **** --- 530,544 ---- false, NULL, NULL }, { + {"trace_plpgsql", PGC_USERSET, DEVELOPER_OPTIONS, + gettext_noop("Set tracing off on plpgsql functions."), + NULL, + GUC_NOT_IN_SAMPLE + }, + &trace_plpgsql, + false, NULL, NULL + }, + { {"log_duration", PGC_SUSET, LOGGING_WHAT, gettext_noop("Logs the duration of each completed SQL statement."), NULL diff -c -r pgsql.00/src/bin/psql/command.c psql.01/src/bin/psql/command.c *** pgsql.00/src/bin/psql/command.c 2005-06-13 08:36:00.000000000 +0200 --- psql.01/src/bin/psql/command.c 2005-07-03 20:13:37.000000000 +0200 *************** *** 1015,1020 **** --- 1015,1021 ---- } PQsetNoticeProcessor(pset.db, NoticeProcessor, NULL); + PQsetTraceProcessor(pset.db, traceProcessor); /* Update variables */ SyncVariables(); diff -c -r pgsql.00/src/bin/psql/common.c psql.01/src/bin/psql/common.c *** pgsql.00/src/bin/psql/common.c 2005-06-22 23:14:00.000000000 +0200 --- psql.01/src/bin/psql/common.c 2005-07-03 20:35:45.000000000 +0200 *************** *** 34,39 **** --- 34,40 ---- #include "print.h" #include "mainloop.h" #include "mb/pg_wchar.h" + #include "input.h" /* Workarounds for Windows */ *************** *** 64,69 **** --- 65,72 ---- static bool command_no_begin(const char *query); + void traceProcessor(char **cmd, char **varname, char **expr); + /* * "Safe" wrapper around strdup() */ *************** *** 216,221 **** --- 219,235 ---- } + void traceProcessor(char **cmd, char **varname, char **expr) + { + *expr = NULL; + *varname = NULL; + + *cmd = gets_interactive("dbg. "); + if (cmd) + if (strcmp(*cmd, "p") == 0) + *varname = gets_interactive("var-. "); + + } /* * Code to support query cancellation diff -c -r pgsql.00/src/bin/psql/common.h psql.01/src/bin/psql/common.h *** pgsql.00/src/bin/psql/common.h 2005-06-13 08:36:00.000000000 +0200 --- psql.01/src/bin/psql/common.h 2005-07-03 20:15:42.000000000 +0200 *************** *** 40,45 **** --- 40,46 ---- __attribute__((format(printf, 1, 2))); extern void NoticeProcessor(void *arg, const char *message); + extern void traceProcessor(char **cmd, char **varname, char **expr); extern volatile bool cancel_pressed; diff -c -r pgsql.00/src/bin/psql/startup.c psql.01/src/bin/psql/startup.c *** pgsql.00/src/bin/psql/startup.c 2005-06-21 06:02:00.000000000 +0200 --- psql.01/src/bin/psql/startup.c 2005-07-03 20:14:13.000000000 +0200 *************** *** 221,226 **** --- 221,227 ---- } PQsetNoticeProcessor(pset.db, NoticeProcessor, NULL); + PQsetTraceProcessor(pset.db, traceProcessor); SyncVariables(); diff -c -r pgsql.00/src/include/utils/guc.h psql.01/src/include/utils/guc.h *** pgsql.00/src/include/utils/guc.h 2005-06-26 05:04:00.000000000 +0200 --- psql.01/src/include/utils/guc.h 2005-07-03 16:50:04.000000000 +0200 *************** *** 133,139 **** extern char *HbaFileName; extern char *IdentFileName; extern char *external_pid_file; ! extern void SetConfigOption(const char *name, const char *value, GucContext context, GucSource source); --- 133,139 ---- extern char *HbaFileName; extern char *IdentFileName; extern char *external_pid_file; ! extern bool trace_plpgsql; extern void SetConfigOption(const char *name, const char *value, GucContext context, GucSource source); diff -c -r pgsql.00/src/interfaces/libpq/fe-connect.c psql.01/src/interfaces/libpq/fe-connect.c *** pgsql.00/src/interfaces/libpq/fe-connect.c 2005-06-27 04:04:00.000000000 +0200 --- psql.01/src/interfaces/libpq/fe-connect.c 2005-07-03 20:30:17.000000000 +0200 *************** *** 202,208 **** } }; - static bool connectOptions1(PGconn *conn, const char *conninfo); static bool connectOptions2(PGconn *conn); static int connectDBStart(PGconn *conn); --- 202,207 ---- *************** *** 216,221 **** --- 215,221 ---- const char *keyword); static void defaultNoticeReceiver(void *arg, const PGresult *res); static void defaultNoticeProcessor(void *arg, const char *message); + static void defaultTraceProcessor(char **cmd, char **varname, char **expr); static int parseServiceInfo(PQconninfoOption *options, PQExpBuffer errorMessage); static char *pwdfMatchesString(char *buf, char *token); *************** *** 1825,1830 **** --- 1825,1831 ---- /* Zero all pointers and booleans */ MemSet(conn, 0, sizeof(PGconn)); + conn->traceProc = defaultTraceProcessor; conn->noticeHooks.noticeRec = defaultNoticeReceiver; conn->noticeHooks.noticeProc = defaultNoticeProcessor; conn->status = CONNECTION_BAD; *************** *** 3024,3029 **** --- 3025,3055 ---- fprintf(stderr, "%s", message); } + + static void + defaultTraceProcessor(char **cmd, char **varname, char **expr) + { + *cmd = strdup("c"); + *varname = NULL; + *expr = NULL; + } + + PQtraceProcessor + PQsetTraceProcessor(PGconn *conn, PQtraceProcessor proc) + { + PQtraceProcessor old; + + if (conn == NULL) + return NULL; + + old = conn->traceProc; + if (proc) + { + conn->traceProc = proc; + } + return old; + } + /* * returns a pointer to the next token or NULL if the current * token doesn't match diff -c -r pgsql.00/src/interfaces/libpq/fe-protocol3.c psql.01/src/interfaces/libpq/fe-protocol3.c *** pgsql.00/src/interfaces/libpq/fe-protocol3.c 2005-06-12 02:00:00.000000000 +0200 --- psql.01/src/interfaces/libpq/fe-protocol3.c 2005-07-03 20:36:44.000000000 +0200 *************** *** 144,149 **** --- 144,150 ---- */ if (id == 'A') { + if (getNotify(conn)) return; } *************** *** 167,172 **** --- 168,174 ---- * why it is about to close the connection, so we don't want * to just discard it...) */ + if (id == 'E') { if (pqGetErrorNotice3(conn, false /* treat as notice */ )) *************** *** 193,198 **** --- 195,221 ---- */ switch (id) { + case 't': + { + char *cmd; + char *varname; + char *expr; + + if (conn->traceProc != NULL) + (*conn->traceProc) (&cmd, &varname, &expr); + + pqPutMsgStart('T', false, conn); + pqPutc((cmd)?cmd[0]:'q', conn); + pqPuts((varname)?varname:"", conn); + pqPuts((expr)?expr:"", conn); + pqPutMsgEnd(conn); + pqFlush(conn); + + if (cmd) free(cmd); + if (varname) free(varname); + if (expr) free(expr); + } + break; case 'C': /* command complete */ if (pqGets(&conn->workBuffer, conn)) return; diff -c -r pgsql.00/src/interfaces/libpq/libpq-fe.h psql.01/src/interfaces/libpq/libpq-fe.h *** pgsql.00/src/interfaces/libpq/libpq-fe.h 2005-06-13 04:26:00.000000000 +0200 --- psql.01/src/interfaces/libpq/libpq-fe.h 2005-07-03 19:40:41.000000000 +0200 *************** *** 140,145 **** --- 140,146 ---- /* Function types for notice-handling callbacks */ typedef void (*PQnoticeReceiver) (void *arg, const PGresult *res); typedef void (*PQnoticeProcessor) (void *arg, const char *message); + typedef void (*PQtraceProcessor) (char **cmd, char **varname, char **expr); /* Print options for PQprint() */ typedef char pqbool; *************** *** 296,301 **** --- 297,304 ---- extern PQnoticeProcessor PQsetNoticeProcessor(PGconn *conn, PQnoticeProcessor proc, void *arg); + extern PQtraceProcessor PQsetTraceProcessor(PGconn *conn, + PQtraceProcessor proc); /* * Used to set callback that prevents concurrent access to diff -c -r pgsql.00/src/interfaces/libpq/libpq-int.h psql.01/src/interfaces/libpq/libpq-int.h *** pgsql.00/src/interfaces/libpq/libpq-int.h 2005-06-27 04:04:00.000000000 +0200 --- psql.01/src/interfaces/libpq/libpq-int.h 2005-07-03 19:37:42.000000000 +0200 *************** *** 333,338 **** --- 333,339 ---- /* Status for asynchronous result construction */ PGresult *result; /* result being constructed */ PGresAttValue *curTuple; /* tuple currently being read */ + PQtraceProcessor traceProc; #ifdef USE_SSL bool allow_ssl_try; /* Allowed to try SSL negotiation */ diff -c -r pgsql.00/src/pl/plpgsql/src/gram.y psql.01/src/pl/plpgsql/src/gram.y *** pgsql.00/src/pl/plpgsql/src/gram.y 2005-06-22 03:35:00.000000000 +0200 --- psql.01/src/pl/plpgsql/src/gram.y 2005-07-03 15:34:05.000000000 +0200 *************** *** 56,61 **** --- 56,62 ---- PLpgSQL_datum *initial_datum); static void check_sql_expr(const char *stmt); static void plpgsql_sql_error_callback(void *arg); + char * plpgsql_scanner_src(void); %} *************** *** 145,150 **** --- 146,152 ---- %type getdiag_kind getdiag_target %type lno + %type src; /* * Keyword tokens *************** *** 222,228 **** pl_function : T_FUNCTION comp_optsect pl_block opt_semi { ! yylval.program = (PLpgSQL_stmt_block *)$3; } | T_TRIGGER comp_optsect pl_block opt_semi { --- 224,231 ---- pl_function : T_FUNCTION comp_optsect pl_block opt_semi { ! yylval.program = (PLpgSQL_stmt_block *)$3; ! } | T_TRIGGER comp_optsect pl_block opt_semi { *************** *** 261,266 **** --- 264,270 ---- new->initvarnos = $1.initvarnos; new->body = $4; new->exceptions = $5; + new->src = NULL; plpgsql_ns_pop(); *************** *** 623,628 **** --- 627,633 ---- new = palloc0(sizeof(PLpgSQL_stmt_perform)); new->cmd_type = PLPGSQL_STMT_PERFORM; new->lineno = $2; + new->breakpoint = false; new->expr = $3; $$ = (PLpgSQL_stmt *)new; *************** *** 636,641 **** --- 641,647 ---- new = palloc0(sizeof(PLpgSQL_stmt_assign)); new->cmd_type = PLPGSQL_STMT_ASSIGN; new->lineno = $2; + new->breakpoint = false; new->varno = $1; new->expr = $4; *************** *** 649,654 **** --- 655,661 ---- new = palloc0(sizeof(PLpgSQL_stmt_getdiag)); new->cmd_type = PLPGSQL_STMT_GETDIAG; + new->breakpoint = false; new->lineno = $3; new->diag_items = $4; *************** *** 736,741 **** --- 743,749 ---- new->cond = $3; new->true_body = $4; new->false_body = $5; + new->breakpoint = false; $$ = (PLpgSQL_stmt *)new; } *************** *** 768,773 **** --- 776,782 ---- new_if->lineno = $2; new_if->cond = $3; new_if->true_body = $4; + new_if->breakpoint = false; new_if->false_body = $5; /* wrap the if-statement in a "container" list */ *************** *** 789,794 **** --- 798,804 ---- new->lineno = $3; new->label = $1; new->body = $4; + new->breakpoint = false; plpgsql_ns_pop(); *************** *** 806,811 **** --- 816,822 ---- new->label = $1; new->cond = $4; new->body = $5; + new->breakpoint = false; plpgsql_ns_pop(); *************** *** 866,871 **** --- 877,883 ---- new = palloc0(sizeof(PLpgSQL_stmt_dynfors)); new->cmd_type = PLPGSQL_STMT_DYNFORS; new->lineno = $1; + new->breakpoint = false; if ($2.rec) new->rec = $2.rec; else if ($2.row) *************** *** 945,950 **** --- 957,963 ---- new->reverse = reverse; new->lower = expr1; new->upper = expr2; + new->breakpoint = false; $$ = (PLpgSQL_stmt *) new; } *************** *** 970,975 **** --- 983,989 ---- new = palloc0(sizeof(PLpgSQL_stmt_fors)); new->cmd_type = PLPGSQL_STMT_FORS; + new->breakpoint = false; new->lineno = $1; if ($2.rec) new->rec = $2.rec; *************** *** 1047,1052 **** --- 1061,1067 ---- new->lineno = $2; new->label = $3; new->cond = $4; + new->breakpoint = false; $$ = (PLpgSQL_stmt *)new; } *************** *** 1071,1076 **** --- 1086,1092 ---- new->lineno = $2; new->expr = NULL; new->retvarno = -1; + new->breakpoint = false; if (plpgsql_curr_compile->fn_retset) { *************** *** 1137,1142 **** --- 1153,1159 ---- new->lineno = $2; new->expr = NULL; new->retvarno = -1; + new->breakpoint = false; if (plpgsql_curr_compile->out_param_varno >= 0) { *************** *** 1182,1187 **** --- 1199,1205 ---- new->elog_level = $3; new->message = $4; new->params = NIL; + new->breakpoint = false; tok = yylex(); *************** *** 1274,1279 **** --- 1292,1298 ---- new = palloc(sizeof(PLpgSQL_stmt_dynexecute)); new->cmd_type = PLPGSQL_STMT_DYNEXECUTE; new->lineno = $2; + new->breakpoint = false; new->query = expr; new->rec = NULL; new->row = NULL; *************** *** 1324,1329 **** --- 1343,1349 ---- new = palloc0(sizeof(PLpgSQL_stmt_open)); new->cmd_type = PLPGSQL_STMT_OPEN; + new->breakpoint = false; new->lineno = $2; new->curvar = $3->varno; *************** *** 1440,1448 **** --- 1460,1470 ---- new = (PLpgSQL_stmt_fetch *)make_fetch_stmt(); new->curvar = $3; + new->breakpoint = false; $$ = (PLpgSQL_stmt *)new; $$->lineno = $2; + } ; *************** *** 1454,1459 **** --- 1476,1482 ---- new->cmd_type = PLPGSQL_STMT_CLOSE; new->lineno = $2; new->curvar = $3; + new->breakpoint = false; $$ = (PLpgSQL_stmt *)new; } *************** *** 1463,1468 **** --- 1486,1492 ---- { /* We do not bother building a node for NULL */ $$ = NULL; + } ; *************** *** 1645,1650 **** --- 1669,1679 ---- } ; + src : + { + $$ = plpgsql_scanner_src(); + } + ; %% diff -c -r pgsql.00/src/pl/plpgsql/src/pl_comp.c psql.01/src/pl/plpgsql/src/pl_comp.c *** pgsql.00/src/pl/plpgsql/src/pl_comp.c 2005-06-10 18:23:00.000000000 +0200 --- psql.01/src/pl/plpgsql/src/pl_comp.c 2005-07-03 15:33:39.000000000 +0200 *************** *** 641,647 **** if (parse_rc != 0) elog(ERROR, "plpgsql parser returned %d", parse_rc); function->action = plpgsql_yylval.program; ! plpgsql_scanner_finish(); pfree(proc_source); --- 641,647 ---- if (parse_rc != 0) elog(ERROR, "plpgsql parser returned %d", parse_rc); function->action = plpgsql_yylval.program; ! function->src = pstrdup(proc_source); plpgsql_scanner_finish(); pfree(proc_source); diff -c -r pgsql.00/src/pl/plpgsql/src/pl_exec.c psql.01/src/pl/plpgsql/src/pl_exec.c *** pgsql.00/src/pl/plpgsql/src/pl_exec.c 2005-06-27 00:05:00.000000000 +0200 --- psql.01/src/pl/plpgsql/src/pl_exec.c 2005-07-03 20:19:39.000000000 +0200 *************** *** 53,63 **** #include "utils/lsyscache.h" #include "utils/memutils.h" #include "utils/typcache.h" ! static const char *const raise_skip_msg = "RAISE"; /* * All plpgsql function executions within a single transaction share * the same executor EState for evaluating "simple" expressions. Each --- 53,67 ---- #include "utils/lsyscache.h" #include "utils/memutils.h" #include "utils/typcache.h" ! #include "libpq/libpq.h" ! #include "libpq/pqformat.h" ! #include "utils/guc.h" static const char *const raise_skip_msg = "RAISE"; + + /* * All plpgsql function executions within a single transaction share * the same executor EState for evaluating "simple" expressions. Each *************** *** 70,75 **** --- 74,80 ---- */ static EState *simple_eval_estate = NULL; static PLpgSQL_expr *active_simple_exprs = NULL; + static bool gdb_continue = false; /************************************************************ * Local function forward declarations *************** *** 181,187 **** static bool compatible_tupdesc(TupleDesc td1, TupleDesc td2); static void exec_set_found(PLpgSQL_execstate *estate, bool state); static void free_var(PLpgSQL_var *var); ! /* ---------- * plpgsql_exec_function Called by the call handler for --- 186,194 ---- static bool compatible_tupdesc(TupleDesc td1, TupleDesc td2); static void exec_set_found(PLpgSQL_execstate *estate, bool state); static void free_var(PLpgSQL_var *var); ! static char* exec_getline(int lno, char *src); ! static void exec_sendinfo(const char *fmt, ...); ! static char *pstrndup(char *src, int size); /* ---------- * plpgsql_exec_function Called by the call handler for *************** *** 200,206 **** --- 207,216 ---- * Setup the execution state */ plpgsql_estate_setup(&estate, func, (ReturnSetInfo *) fcinfo->resultinfo); + estate.src = func->src; + exec_sendinfo("executing function %s", func->fn_name); + gdb_continue = false; /* * Setup error traceback support for ereport() */ *************** *** 284,289 **** --- 294,302 ---- estate.err_text = NULL; estate.err_stmt = (PLpgSQL_stmt *) (func->action); rc = exec_stmt_block(&estate, func->action); + + //estate.src = func->action->src; + if (rc != PLPGSQL_RC_RETURN) { estate.err_stmt = NULL; *************** *** 553,558 **** --- 566,573 ---- * Set the magic variable FOUND to false */ exec_set_found(&estate, false); + + estate.src = func->action->src; /* * Now call the toplevel block of statements *************** *** 992,1008 **** * type specific execution function. * ---------- */ static int exec_stmt(PLpgSQL_execstate *estate, PLpgSQL_stmt *stmt) { PLpgSQL_stmt *save_estmt; int rc = -1; save_estmt = estate->err_stmt; estate->err_stmt = stmt; ! CHECK_FOR_INTERRUPTS(); switch (stmt->cmd_type) { case PLPGSQL_STMT_BLOCK: --- 1007,1231 ---- * type specific execution function. * ---------- */ + + + static void + exec_sendinfo(const char *fmt, ...) + { + StringInfoData msgbuf, dtabuf; + + initStringInfo(&dtabuf); + dtabuf.maxlen = 30000; + + for (;;) + { + va_list args; + bool success; + + va_start(args, fmt); + success = appendStringInfoVA(&dtabuf, fmt, args); + va_end(args); + if (success) + break; + enlargeStringInfo(&dtabuf, dtabuf.maxlen); + } + + pq_beginmessage(&msgbuf, 'N'); + + pq_sendbyte(&msgbuf, PG_DIAG_SEVERITY); + pq_sendstring(&msgbuf, "trace"); + + pq_sendbyte(&msgbuf, PG_DIAG_MESSAGE_PRIMARY); + pq_sendstring(&msgbuf, dtabuf.data); + + pq_sendbyte(&msgbuf, '\0'); + pq_endmessage(&msgbuf); + + pq_flush(); + + pfree(dtabuf.data); + } + + static char * + exec_getline(int ln, char *src) + { + int cl = 1; + char *c; + + if (*src == '\n') + src++; + + while (src) + { + if ((c = strchr(src,'\n')) == NULL) + { + if (cl != ln) + return NULL; + return pstrdup(src); + } + if (cl++ == ln) + return pstrndup(src, c - src); + src = c + 1; + } + return NULL; + } + + static char * + pstrndup(char *str, int size) + { + char *res = palloc(size + 1); + memcpy(res, str, size); + res[size] = '\0'; + return res; + } + static int exec_stmt(PLpgSQL_execstate *estate, PLpgSQL_stmt *stmt) { PLpgSQL_stmt *save_estmt; int rc = -1; + bool first_time = true; save_estmt = estate->err_stmt; estate->err_stmt = stmt; ! CHECK_FOR_INTERRUPTS(); + if (trace_plpgsql) + for (;;) + { + char cmd; + char *varname; + char *expr; + char mtype; + StringInfoData buf; + + + if (first_time) + { + char *line = exec_getline(stmt->lineno, estate->src); + exec_sendinfo("%s on %d: %s", plpgsql_stmt_typename(stmt), stmt->lineno,line); + if (line) pfree(line); + first_time = false; + } + + /* noninterctive debug */ + if (gdb_continue && !stmt->breakpoint) + break; + if (gdb_continue) + exec_sendinfo("stop on breakpoint"); + + gdb_continue = false; + + pq_putemptymessage('t'); + pq_flush(); + + mtype = pq_getbyte(); + if (mtype == EOF) + ereport(ERROR, + (errcode(ERRCODE_CONNECTION_FAILURE), + errmsg("unexpected EOF on client connection"))); + + initStringInfo(&buf); + if (pq_getmessage(&buf, 1000)) + { + pfree(buf.data); + ereport(ERROR, + (errcode(ERRCODE_CONNECTION_FAILURE), + errmsg("unexpected EOF on client connection"))); + } + if (mtype != 'T') + { + pfree(buf.data); + ereport(ERROR, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("unexpected message type 0x%02X during TRACE op ", mtype))); + } + cmd = pq_getmsgbyte(&buf); + varname = (char *) pq_getmsgstring(&buf); + expr = (char *) pq_getmsgstring(&buf); + pq_getmsgend(&buf); + + CHECK_FOR_INTERRUPTS(); + + if (cmd == 's' || cmd == 'c') + { + pfree(buf.data); + gdb_continue = (cmd == 'c'); + break; + } + + switch (cmd) + { + case 'q': + pfree(buf.data); + elog(ERROR, "end of tracing"); + break; + case 'l': + { + StringInfoData list; + int lno = 1; + char *c; + char *src = estate->src; + + initStringInfo(&list); + appendStringInfo(&list, "source of function %s\n", estate->err_func->fn_name); + + if (*src == '\n') + src++; + while (src) + { + if ((c = strchr(src,'\n')) == NULL) + { + appendStringInfo(&list, "%3d: %s\n", lno, src); + break; + } + else + { + char *s; + s = pstrndup(src, c - src); + appendStringInfo(&list, "%3d: %s\n", lno++, s); + pfree(s); + src = c+1; + } + } + exec_sendinfo(list.data); + pfree(list.data); + } + break; + case 'p': + { + char *extval; + int i; + for (i = estate->ndatums-1;i>=0;i--) + { + PLpgSQL_var *var = (PLpgSQL_var *) estate->datums[i]; + if (strcmp(varname,"*") == 0|| strcmp(varname, var->refname) == 0) + { + extval = (var->isnull)?"": + convert_value_to_string(var->value, var->datatype->typoid); + + exec_sendinfo("var %s as %s has %s", var->refname, var->datatype->typname, extval); + } + } + } + break; + case 'b': + if (stmt->breakpoint) + { + stmt->breakpoint = false; + exec_sendinfo("Breakpoint set off"); + } else + { + stmt->breakpoint = true; + exec_sendinfo("Breakpoint set on"); + } + break; + default: + exec_sendinfo("Unknown dbg command"); + } + } + switch (stmt->cmd_type) { case PLPGSQL_STMT_BLOCK: *************** *** 2114,2119 **** --- 2337,2344 ---- estate->err_func = func; estate->err_stmt = NULL; estate->err_text = NULL; + + estate->src = NULL; /* * Create an EState for evaluation of simple expressions, if there's diff -c -r pgsql.00/src/pl/plpgsql/src/plpgsql.h psql.01/src/pl/plpgsql/src/plpgsql.h *** pgsql.00/src/pl/plpgsql/src/plpgsql.h 2005-06-22 03:35:00.000000000 +0200 --- psql.01/src/pl/plpgsql/src/plpgsql.h 2005-07-03 13:51:59.000000000 +0200 *************** *** 313,318 **** --- 313,319 ---- { /* Generic execution node */ int cmd_type; int lineno; + bool breakpoint; } PLpgSQL_stmt; *************** *** 342,347 **** --- 343,350 ---- { /* Block of statements */ int cmd_type; int lineno; + bool breakpoint; + char *src; char *label; List *body; /* List of statements */ int n_initvars; *************** *** 354,359 **** --- 357,363 ---- { /* Assign statement */ int cmd_type; int lineno; + bool breakpoint; int varno; PLpgSQL_expr *expr; } PLpgSQL_stmt_assign; *************** *** 362,367 **** --- 366,372 ---- { /* PERFORM statement */ int cmd_type; int lineno; + bool breakpoint; PLpgSQL_expr *expr; } PLpgSQL_stmt_perform; *************** *** 375,380 **** --- 380,386 ---- { /* Get Diagnostics statement */ int cmd_type; int lineno; + bool breakpoint; List *diag_items; /* List of PLpgSQL_diag_item */ } PLpgSQL_stmt_getdiag; *************** *** 383,388 **** --- 389,395 ---- { /* IF statement */ int cmd_type; int lineno; + bool breakpoint; PLpgSQL_expr *cond; List *true_body; /* List of statements */ List *false_body; /* List of statements */ *************** *** 393,398 **** --- 400,406 ---- { /* Unconditional LOOP statement */ int cmd_type; int lineno; + bool breakpoint; char *label; List *body; /* List of statements */ } PLpgSQL_stmt_loop; *************** *** 402,407 **** --- 410,416 ---- { /* WHILE cond LOOP statement */ int cmd_type; int lineno; + bool breakpoint; char *label; PLpgSQL_expr *cond; List *body; /* List of statements */ *************** *** 412,417 **** --- 421,427 ---- { /* FOR statement with integer loopvar */ int cmd_type; int lineno; + bool breakpoint; char *label; PLpgSQL_var *var; PLpgSQL_expr *lower; *************** *** 425,430 **** --- 435,441 ---- { /* FOR statement running over SELECT */ int cmd_type; int lineno; + bool breakpoint; char *label; PLpgSQL_rec *rec; PLpgSQL_row *row; *************** *** 437,442 **** --- 448,454 ---- { /* FOR statement running over EXECUTE */ int cmd_type; int lineno; + bool breakpoint; char *label; PLpgSQL_rec *rec; PLpgSQL_row *row; *************** *** 449,454 **** --- 461,467 ---- { /* SELECT ... INTO statement */ int cmd_type; int lineno; + bool breakpoint; PLpgSQL_rec *rec; PLpgSQL_row *row; PLpgSQL_expr *query; *************** *** 459,464 **** --- 472,478 ---- { /* OPEN a curvar */ int cmd_type; int lineno; + bool breakpoint; int curvar; PLpgSQL_row *returntype; PLpgSQL_expr *argquery; *************** *** 471,476 **** --- 485,491 ---- { /* FETCH curvar INTO statement */ int cmd_type; int lineno; + bool breakpoint; PLpgSQL_rec *rec; PLpgSQL_row *row; int curvar; *************** *** 481,486 **** --- 496,502 ---- { /* CLOSE curvar */ int cmd_type; int lineno; + bool breakpoint; int curvar; } PLpgSQL_stmt_close; *************** *** 489,494 **** --- 505,511 ---- { /* EXIT or CONTINUE statement */ int cmd_type; int lineno; + bool breakpoint; bool is_exit; /* Is this an exit or a continue? */ char *label; PLpgSQL_expr *cond; *************** *** 499,504 **** --- 516,522 ---- { /* RETURN statement */ int cmd_type; int lineno; + bool breakpoint; PLpgSQL_expr *expr; int retvarno; } PLpgSQL_stmt_return; *************** *** 507,512 **** --- 525,531 ---- { /* RETURN NEXT statement */ int cmd_type; int lineno; + bool breakpoint; PLpgSQL_expr *expr; int retvarno; } PLpgSQL_stmt_return_next; *************** *** 515,520 **** --- 534,540 ---- { /* RAISE statement */ int cmd_type; int lineno; + bool breakpoint; int elog_level; char *message; List *params; /* list of expressions */ *************** *** 525,530 **** --- 545,551 ---- { /* Generic SQL statement to execute */ int cmd_type; int lineno; + bool breakpoint; PLpgSQL_expr *sqlstmt; } PLpgSQL_stmt_execsql; *************** *** 533,538 **** --- 554,560 ---- { /* Dynamic SQL string to execute */ int cmd_type; int lineno; + bool breakpoint; PLpgSQL_rec *rec; /* INTO record or row variable */ PLpgSQL_row *row; PLpgSQL_expr *query; *************** *** 594,599 **** --- 616,622 ---- int tg_nargs_varno; int ndatums; + char *src; PLpgSQL_datum **datums; PLpgSQL_stmt_block *action; } PLpgSQL_function; *************** *** 608,613 **** --- 631,637 ---- Oid fn_rettype; /* info about declared function rettype */ bool retistuple; bool retisset; + char *src; bool readonly_func; Pouze v psql.01/src/pl/plpgsql/src: pl_scan.c diff -c -r pgsql.00/src/pl/plpgsql/src/scan.l psql.01/src/pl/plpgsql/src/scan.l *** pgsql.00/src/pl/plpgsql/src/scan.l 2005-06-26 21:16:00.000000000 +0200 --- psql.01/src/pl/plpgsql/src/scan.l 2005-07-03 10:39:27.000000000 +0200 *************** *** 478,483 **** --- 478,490 ---- return cur_line_num; } + + char * + plpgsql_scanner_src(void) + { + return cur_line_start; + } + /* * Called before any actual parsing is done *