2771 lines
106 KiB
Diff
2771 lines
106 KiB
Diff
diff --git a/gpl_dependency/pldebugger/gplsrc/pldebugger_3_0/Makefile b/gpl_dependency/pldebugger/gplsrc/pldebugger_3_0/Makefile
|
|
index 321b61c..9b678ff 100644
|
|
--- a/gpl_dependency/pldebugger/gplsrc/pldebugger_3_0/Makefile
|
|
+++ b/gpl_dependency/pldebugger/gplsrc/pldebugger_3_0/Makefile
|
|
@@ -13,7 +13,14 @@
|
|
EXTENSION = pldbgapi
|
|
MODULE_big = plugin_debugger
|
|
|
|
+top_builddir = ../../../..
|
|
+
|
|
+override CPPFLAGS := -I$(top_builddir)/src/common/pl/plpgsql/src -fPIC $(CPPFLAGS)
|
|
+#LDFLAGS += -pie
|
|
+CFLAGS += -Wl,-z,relro,-z,now
|
|
+
|
|
OBJS = plpgsql_debugger.o plugin_debugger.o dbgcomm.o pldbgapi.o
|
|
+
|
|
ifdef INCLUDE_PACKAGE_SUPPORT
|
|
OBJS += spl_debugger.o
|
|
endif
|
|
@@ -28,7 +35,6 @@ PGXS := $(shell $(PG_CONFIG) --pgxs)
|
|
include $(PGXS)
|
|
else
|
|
subdir = contrib/pldebugger
|
|
-top_builddir = ../..
|
|
include $(top_builddir)/src/Makefile.global
|
|
include $(top_srcdir)/contrib/contrib-global.mk
|
|
endif
|
|
@@ -37,7 +43,6 @@ endif
|
|
# it is installed into include/server, but when building without pgxs,
|
|
# with the pldebugger directory being directly in the server source tree's
|
|
# contrib directory, we need to tell the compiler where to find it.
|
|
-plpgsql_debugger.o: CFLAGS += -I$(top_builddir)/src/pl/plpgsql/src
|
|
|
|
################################################################################
|
|
## If we're building against EnterpriseDB's Advanced Server, also build a
|
|
@@ -52,7 +57,7 @@ plpgsql_debugger.o: CFLAGS += -I$(top_builddir)/src/pl/plpgsql/src
|
|
## To enable this, you need to run make as "make INCLUDE_PACKAGE_SUPPORT=1"
|
|
##
|
|
ifdef INCLUDE_PACKAGE_SUPPORT
|
|
-spl_debugger.c: plpgsql_debugger.c
|
|
+spl_debugger.cpp: plpgsql_debugger.cpp
|
|
sed -e 's/plpgsql_/spl_/g' $(module_srcdir)plpgsql_debugger.c > spl_debugger.c
|
|
|
|
spl_debugger.o: CFLAGS += -DINCLUDE_PACKAGE_SUPPORT=1 -I$(top_builddir)/src/pl/edb-spl/src
|
|
diff --git a/gpl_dependency/pldebugger/gplsrc/pldebugger_3_0/dbgcomm.cpp b/gpl_dependency/pldebugger/gplsrc/pldebugger_3_0/dbgcomm.cpp
|
|
index 3ad3129..35f0e96 100644
|
|
--- a/gpl_dependency/pldebugger/gplsrc/pldebugger_3_0/dbgcomm.cpp
|
|
+++ b/gpl_dependency/pldebugger/gplsrc/pldebugger_3_0/dbgcomm.cpp
|
|
@@ -25,7 +25,7 @@
|
|
|
|
#include "miscadmin.h"
|
|
#include "storage/backendid.h"
|
|
-#include "storage/lwlock.h"
|
|
+#include "storage/lock/lwlock.h"
|
|
#include "storage/pmsignal.h"
|
|
#include "storage/shmem.h"
|
|
#include "storage/sinvaladt.h"
|
|
@@ -68,12 +68,12 @@
|
|
#define DBGCOMM_PROXY_CONNECTING 2 /* proxy is connecting to our port */
|
|
#define DBGCOMM_CONNECTING_TO_PROXY 3 /* target is connecting to a proxy */
|
|
|
|
-typedef struct
|
|
-{
|
|
- BackendId backendid;
|
|
+typedef struct {
|
|
+ int proxyId;
|
|
int status;
|
|
- int pid;
|
|
+ uint64 sessionId;
|
|
int port;
|
|
+ Oid userid;
|
|
} dbgcomm_target_slot_t;
|
|
|
|
static dbgcomm_target_slot_t *dbgcomm_slots = NULL;
|
|
@@ -90,7 +90,7 @@ static dbgcomm_target_slot_t *dbgcomm_slots = NULL;
|
|
static void dbgcomm_init(void);
|
|
static uint32 resolveHostName(const char *hostName);
|
|
static int findFreeTargetSlot(void);
|
|
-static int findTargetSlot(BackendId backendid);
|
|
+static int findTargetSlot(int proxyId);
|
|
|
|
/**********************************************************************
|
|
* Initialization routines
|
|
@@ -118,7 +118,8 @@ dbgcomm_init(void)
|
|
return;
|
|
|
|
LWLockAcquire(getPLDebuggerLock(), LW_EXCLUSIVE);
|
|
- dbgcomm_slots = ShmemInitStruct("Debugger Connection slots", sizeof(dbgcomm_target_slot_t) * NumTargetSlots, &found);
|
|
+ dbgcomm_slots = (dbgcomm_target_slot_t*)ShmemInitStruct("Debugger Connection slots",
|
|
+ sizeof(dbgcomm_target_slot_t) * NumTargetSlots, &found);
|
|
if (dbgcomm_slots == NULL)
|
|
elog(ERROR, "out of shared memory");
|
|
|
|
@@ -127,8 +128,9 @@ dbgcomm_init(void)
|
|
int i;
|
|
for (i = 0; i < NumTargetSlots; i++)
|
|
{
|
|
- dbgcomm_slots[i].backendid = InvalidBackendId;
|
|
+ dbgcomm_slots[i].proxyId = -1;
|
|
dbgcomm_slots[i].status = DBGCOMM_IDLE;
|
|
+ dbgcomm_slots[i].userid = GetUserId();
|
|
}
|
|
}
|
|
LWLockRelease(getPLDebuggerLock());
|
|
@@ -153,8 +155,7 @@ dbgcomm_init(void)
|
|
* We assume that the proxyPort came from a breakpoint or some other reliable
|
|
* source, so that we don't allow connecting to any random port in the system.
|
|
*/
|
|
-int
|
|
-dbgcomm_connect_to_proxy(int proxyPort)
|
|
+int dbgcomm_connect_to_proxy(int proxyId)
|
|
{
|
|
int sockfd;
|
|
struct sockaddr_in remoteaddr = {0};
|
|
@@ -217,12 +218,12 @@ dbgcomm_connect_to_proxy(int proxyPort)
|
|
}
|
|
dbgcomm_slots[slot].port = ntohs(localaddr.sin_port);
|
|
dbgcomm_slots[slot].status = DBGCOMM_CONNECTING_TO_PROXY;
|
|
- dbgcomm_slots[slot].backendid = MyBackendId;
|
|
- dbgcomm_slots[slot].pid = MyProcPid;
|
|
+ dbgcomm_slots[slot].proxyId = slot;
|
|
+ dbgcomm_slots[slot].sessionId = MY_SESS_ID;
|
|
LWLockRelease(getPLDebuggerLock());
|
|
|
|
remoteaddr.sin_family = AF_INET;
|
|
- remoteaddr.sin_port = htons(proxyPort);
|
|
+ remoteaddr.sin_port = htons(proxyId);
|
|
remoteaddr.sin_addr.s_addr = resolveHostName( "127.0.0.1" );
|
|
|
|
/* Now connect to the other end. */
|
|
@@ -231,14 +232,14 @@ dbgcomm_connect_to_proxy(int proxyPort)
|
|
{
|
|
ereport(COMMERROR,
|
|
(errcode_for_socket_access(),
|
|
- errmsg("could not connect to debugging proxy at port %d: %m", proxyPort)));
|
|
+ errmsg("could not connect to debugging proxy Id: %d", proxyId)));
|
|
/*
|
|
* Reset our entry in the array. On success, this will be done by
|
|
* the proxy.
|
|
*/
|
|
LWLockAcquire(getPLDebuggerLock(), LW_EXCLUSIVE);
|
|
dbgcomm_slots[slot].status = DBGCOMM_IDLE;
|
|
- dbgcomm_slots[slot].backendid = InvalidBackendId;
|
|
+ dbgcomm_slots[slot].proxyId = -1;
|
|
dbgcomm_slots[slot].port = 0;
|
|
LWLockRelease(getPLDebuggerLock());
|
|
return -1;
|
|
@@ -321,12 +322,12 @@ dbgcomm_listen_for_proxy(void)
|
|
}
|
|
dbgcomm_slots[slot].port = localport;
|
|
dbgcomm_slots[slot].status = DBGCOMM_LISTENING_FOR_PROXY;
|
|
- dbgcomm_slots[slot].backendid = MyBackendId;
|
|
- dbgcomm_slots[slot].pid = MyProcPid;
|
|
+ dbgcomm_slots[slot].proxyId = slot;
|
|
+ dbgcomm_slots[slot].sessionId = MY_SESS_ID;
|
|
LWLockRelease(getPLDebuggerLock());
|
|
|
|
/* Notify the client application that this backend is waiting for a proxy. */
|
|
- elog(NOTICE, "PLDBGBREAK:%d", MyBackendId);
|
|
+ elog(NOTICE, "YOUR PROXY PORT ID IS:%d", slot);
|
|
|
|
/* wait for the other end to connect to us */
|
|
done = false;
|
|
@@ -345,7 +346,7 @@ dbgcomm_listen_for_proxy(void)
|
|
if (dbgcomm_slots[slot].status == DBGCOMM_PROXY_CONNECTING &&
|
|
dbgcomm_slots[slot].port == ntohs(remoteaddr.sin_port))
|
|
{
|
|
- dbgcomm_slots[slot].backendid = InvalidBackendId;
|
|
+ dbgcomm_slots[slot].proxyId = -1;
|
|
dbgcomm_slots[slot].status = DBGCOMM_IDLE;
|
|
done = true;
|
|
}
|
|
@@ -369,8 +370,7 @@ dbgcomm_listen_for_proxy(void)
|
|
* Connect to given target backend that's waiting for us. Returns a socket
|
|
* that is open for communication. Uses ereport(ERROR) on error.
|
|
*/
|
|
-int
|
|
-dbgcomm_connect_to_target(BackendId targetBackend)
|
|
+int dbgcomm_connect_to_target(int targetProxyId)
|
|
{
|
|
int sockfd;
|
|
struct sockaddr_in remoteaddr = {0};
|
|
@@ -422,9 +422,12 @@ dbgcomm_connect_to_target(BackendId targetBackend)
|
|
* let it know we're connecting to it from this port.
|
|
*/
|
|
LWLockAcquire(getPLDebuggerLock(), LW_EXCLUSIVE);
|
|
- slot = findTargetSlot(targetBackend);
|
|
- if (slot < 0 || dbgcomm_slots[slot].status != DBGCOMM_LISTENING_FOR_PROXY)
|
|
- {
|
|
+ slot = findTargetSlot(targetProxyId);
|
|
+ if (slot < 0 || dbgcomm_slots[slot].status != DBGCOMM_LISTENING_FOR_PROXY) {
|
|
+ closesocket(sockfd);
|
|
+ ereport(ERROR, (errmsg("target backend is not listening for a connection")));
|
|
+ }
|
|
+ if (dbgcomm_slots[slot].userid != GetUserId() && !superuser()) {
|
|
closesocket(sockfd);
|
|
ereport(ERROR,
|
|
(errmsg("target backend is not listening for a connection")));
|
|
@@ -455,8 +458,7 @@ dbgcomm_connect_to_target(BackendId targetBackend)
|
|
* Waits for one connection from a target backend to the given socket. Returns
|
|
* a socket that is open for communication. Uses ereport(ERROR) on error.
|
|
*/
|
|
-int
|
|
-dbgcomm_accept_target(int sockfd, int *targetPid)
|
|
+int dbgcomm_accept_target(int sockfd, uint64* targetSessId)
|
|
{
|
|
int serverSocket;
|
|
int i;
|
|
@@ -523,7 +525,7 @@ dbgcomm_accept_target(int sockfd, int *targetPid)
|
|
if (dbgcomm_slots[i].status == DBGCOMM_CONNECTING_TO_PROXY &&
|
|
dbgcomm_slots[i].port == ntohs(remoteaddr.sin_port))
|
|
{
|
|
- *targetPid = dbgcomm_slots[i].pid;
|
|
+ *targetSessId = dbgcomm_slots[i].sessionId;
|
|
dbgcomm_slots[i].status = DBGCOMM_IDLE;
|
|
break;
|
|
}
|
|
@@ -615,16 +617,14 @@ findFreeTargetSlot(void)
|
|
|
|
for (i = 0; i < NumTargetSlots; i++)
|
|
{
|
|
- if (dbgcomm_slots[i].backendid == InvalidBackendId)
|
|
+ if (dbgcomm_slots[i].proxyId == -1)
|
|
return i;
|
|
- if (dbgcomm_slots[i].backendid == MyBackendId)
|
|
- {
|
|
+ if (dbgcomm_slots[i].sessionId == MY_SESS_ID) {
|
|
/*
|
|
* If we've failed to deallocate our slot earlier, reuse this slot.
|
|
* This shouldn't happen.
|
|
*/
|
|
- elog(LOG, "found leftover debugging target slot for backend %d",
|
|
- MyBackendId);
|
|
+ elog(LOG, "found leftover debugging target slot for session %ld", MY_SESS_ID);
|
|
return i;
|
|
}
|
|
}
|
|
@@ -637,14 +637,13 @@ findFreeTargetSlot(void)
|
|
*
|
|
* Note: Caller must be holding the lock.
|
|
*/
|
|
-static int
|
|
-findTargetSlot(BackendId backendid)
|
|
+static int findTargetSlot(int proxyId)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < NumTargetSlots; i++)
|
|
{
|
|
- if (dbgcomm_slots[i].backendid == backendid)
|
|
+ if (dbgcomm_slots[i].proxyId == proxyId)
|
|
return i;
|
|
}
|
|
return -1;
|
|
@@ -674,7 +673,7 @@ static uint32 resolveHostName( const char * hostName )
|
|
else
|
|
hostAddress = inet_addr( hostName );
|
|
|
|
- if(( hostAddress == -1 ) || ( hostAddress == INADDR_NONE ))
|
|
+ if(( hostAddress == (uint32)(-1) ) || ( hostAddress == INADDR_NONE ))
|
|
return( 0 );
|
|
else
|
|
return( hostAddress );
|
|
diff --git a/gpl_dependency/pldebugger/gplsrc/pldebugger_3_0/dbgcomm.h b/gpl_dependency/pldebugger/gplsrc/pldebugger_3_0/dbgcomm.h
|
|
index 3503c4a..333f4b2 100644
|
|
--- a/gpl_dependency/pldebugger/gplsrc/pldebugger_3_0/dbgcomm.h
|
|
+++ b/gpl_dependency/pldebugger/gplsrc/pldebugger_3_0/dbgcomm.h
|
|
@@ -9,17 +9,22 @@
|
|
* Licensed under the Artistic License, see
|
|
* http://www.opensource.org/licenses/artistic-license.php
|
|
* for full details
|
|
+ *
|
|
+ * --------------------------------------------------------------------
|
|
+ * OpenGauss Modification:
|
|
+ * We have changed the name and type of several function parameters of 'dbgcomm_target_slot_t' struct.
|
|
+ *
|
|
*/
|
|
#ifndef DBGCOMM_H
|
|
#define DBGCOMM_H
|
|
|
|
extern void dbgcomm_reserve(void);
|
|
|
|
-extern int dbgcomm_connect_to_proxy(int proxyPort);
|
|
+extern int dbgcomm_connect_to_proxy(int proxyId);
|
|
extern int dbgcomm_listen_for_proxy(void);
|
|
|
|
extern int dbgcomm_listen_for_target(int *port);
|
|
-extern int dbgcomm_accept_target(int sockfd, int *targetPid);
|
|
-extern int dbgcomm_connect_to_target(BackendId targetBackend);
|
|
+extern int dbgcomm_accept_target(int sockfd, uint64* targetSessId);
|
|
+extern int dbgcomm_connect_to_target(int targetProxyId);
|
|
|
|
#endif
|
|
diff --git a/gpl_dependency/pldebugger/gplsrc/pldebugger_3_0/globalbp.h b/gpl_dependency/pldebugger/gplsrc/pldebugger_3_0/globalbp.h
|
|
index eecd011..613cae2 100644
|
|
--- a/gpl_dependency/pldebugger/gplsrc/pldebugger_3_0/globalbp.h
|
|
+++ b/gpl_dependency/pldebugger/gplsrc/pldebugger_3_0/globalbp.h
|
|
@@ -9,6 +9,12 @@
|
|
* Licensed under the Artistic License, see
|
|
* http://www.opensource.org/licenses/artistic-license.php
|
|
* for full details
|
|
+ *
|
|
+ * -----------------------------------------------------------------------------
|
|
+ * OpenGauss Modifications:
|
|
+ * We changed the name and type of var 'targetPid' of struct BreakpointKey,
|
|
+ * to adapt to openGauss thread pool mode.
|
|
+ *
|
|
*/
|
|
#ifndef GLOBALBP_H
|
|
#define GLOBALBP_H
|
|
@@ -18,7 +24,7 @@
|
|
typedef enum
|
|
{
|
|
BP_LOCAL = 0,
|
|
- BP_GLOBAL
|
|
+ BP_GLOBAL /* be removed. */
|
|
} eBreakpointScope;
|
|
|
|
/*
|
|
@@ -41,7 +47,7 @@ typedef struct BreakpointKey
|
|
Oid databaseId;
|
|
Oid functionId;
|
|
int lineNumber;
|
|
- int targetPid; /* -1 means any process */
|
|
+ uint64 targetSessId; /* uint64(-1) means any process */
|
|
} BreakpointKey;
|
|
|
|
typedef struct Breakpoint
|
|
diff --git a/gpl_dependency/pldebugger/gplsrc/pldebugger_3_0/pldbgapi--1.0.sql b/gpl_dependency/pldebugger/gplsrc/pldebugger_3_0/pldbgapi--1.0.sql
|
|
index 5095845..46b844b 100644
|
|
--- a/gpl_dependency/pldebugger/gplsrc/pldebugger_3_0/pldbgapi--1.0.sql
|
|
+++ b/gpl_dependency/pldebugger/gplsrc/pldebugger_3_0/pldbgapi--1.0.sql
|
|
@@ -6,6 +6,13 @@
|
|
-- Licensed under the Artistic License, see
|
|
-- http://www.opensource.org/licenses/artistic-license.php
|
|
-- for full details
|
|
+--
|
|
+-- OpenGauss Modification:
|
|
+-- We have made the following modifications on the source code to adapt to openGauss:
|
|
+-- add pldbg_on, pldbg_off
|
|
+-- rewrite pldbg_get_source
|
|
+-- remove pldbg_create_listener, pldbg_deposit_value, pldbg_get_target_info, pldbg_select_frame,
|
|
+-- pldbg_set_global_breakpoint, pldbg_wait_for_breakpoint, pldbg_wait_for_target
|
|
|
|
\echo Installing pldebugger as unpackaged objects. If you are using PostgreSQL
|
|
\echo version 9.1 or above, use "CREATE EXTENSION pldbgapi" instead.
|
|
@@ -14,8 +21,10 @@ CREATE TYPE breakpoint AS ( func OID, linenumber INTEGER, targetName TEXT );
|
|
CREATE TYPE frame AS ( level INT, targetname TEXT, func OID, linenumber INTEGER, args TEXT );
|
|
|
|
CREATE TYPE var AS ( name TEXT, varClass char, lineNumber INTEGER, isUnique bool, isConst bool, isNotNull bool, dtype OID, value TEXT );
|
|
-CREATE TYPE proxyInfo AS ( serverVersionStr TEXT, serverVersionNum INT, proxyAPIVer INT, serverProcessID INT );
|
|
+CREATE TYPE proxyInfo AS ( serverVersionStr TEXT, serverVersionNum INT, proxyAPIVer INT, serverProcessID BIGINT );
|
|
|
|
+CREATE FUNCTION pldbg_on() RETURNS boolean AS '$libdir/plugin_debugger' LANGUAGE C STRICT;
|
|
+CREATE FUNCTION pldbg_off() RETURNS boolean AS '$libdir/plugin_debugger' LANGUAGE C STRICT;
|
|
CREATE FUNCTION pldbg_oid_debug( functionOID OID ) RETURNS INTEGER AS '$libdir/plugin_debugger' LANGUAGE C STRICT;
|
|
|
|
-- for backwards-compatibility
|
|
@@ -24,21 +33,15 @@ CREATE FUNCTION plpgsql_oid_debug( functionOID OID ) RETURNS INTEGER AS $$ SELEC
|
|
CREATE FUNCTION pldbg_abort_target( session INTEGER ) RETURNS SETOF boolean AS '$libdir/plugin_debugger' LANGUAGE C STRICT;
|
|
CREATE FUNCTION pldbg_attach_to_port( portNumber INTEGER ) RETURNS INTEGER AS '$libdir/plugin_debugger' LANGUAGE C STRICT;
|
|
CREATE FUNCTION pldbg_continue( session INTEGER ) RETURNS breakpoint AS '$libdir/plugin_debugger' LANGUAGE C STRICT;
|
|
-CREATE FUNCTION pldbg_create_listener() RETURNS INTEGER AS '$libdir/plugin_debugger' LANGUAGE C STRICT;
|
|
-CREATE FUNCTION pldbg_deposit_value( session INTEGER, varName TEXT, lineNumber INTEGER, value TEXT ) RETURNS boolean AS '$libdir/plugin_debugger' LANGUAGE C STRICT;
|
|
CREATE FUNCTION pldbg_drop_breakpoint( session INTEGER, func OID, linenumber INTEGER ) RETURNS boolean AS '$libdir/plugin_debugger' LANGUAGE C STRICT;
|
|
CREATE FUNCTION pldbg_get_breakpoints( session INTEGER ) RETURNS SETOF breakpoint AS '$libdir/plugin_debugger' LANGUAGE C STRICT;
|
|
-CREATE FUNCTION pldbg_get_source( session INTEGER, func OID ) RETURNS TEXT AS '$libdir/plugin_debugger' LANGUAGE C STRICT;
|
|
+CREATE FUNCTION pldbg_get_source( func OID ) RETURNS TEXT AS 'SELECT prosrc from pg_proc where oid=($1)' LANGUAGE SQL;
|
|
CREATE FUNCTION pldbg_get_stack( session INTEGER ) RETURNS SETOF frame AS '$libdir/plugin_debugger' LANGUAGE C STRICT;
|
|
CREATE FUNCTION pldbg_get_proxy_info( ) RETURNS proxyInfo AS '$libdir/plugin_debugger' LANGUAGE C STRICT;
|
|
CREATE FUNCTION pldbg_get_variables( session INTEGER ) RETURNS SETOF var AS '$libdir/plugin_debugger' LANGUAGE C STRICT;
|
|
-CREATE FUNCTION pldbg_select_frame( session INTEGER, frame INTEGER ) RETURNS breakpoint AS '$libdir/plugin_debugger' LANGUAGE C STRICT;
|
|
CREATE FUNCTION pldbg_set_breakpoint( session INTEGER, func OID, linenumber INTEGER ) RETURNS boolean AS '$libdir/plugin_debugger' LANGUAGE C STRICT;
|
|
-CREATE FUNCTION pldbg_set_global_breakpoint( session INTEGER, func OID, linenumber INTEGER, targetPID INTEGER ) RETURNS boolean AS '$libdir/plugin_debugger' LANGUAGE C;
|
|
CREATE FUNCTION pldbg_step_into( session INTEGER ) RETURNS breakpoint AS '$libdir/plugin_debugger' LANGUAGE C STRICT;
|
|
CREATE FUNCTION pldbg_step_over( session INTEGER ) RETURNS breakpoint AS '$libdir/plugin_debugger' LANGUAGE C STRICT;
|
|
-CREATE FUNCTION pldbg_wait_for_breakpoint( session INTEGER ) RETURNS breakpoint AS '$libdir/plugin_debugger' LANGUAGE C STRICT;
|
|
-CREATE FUNCTION pldbg_wait_for_target( session INTEGER ) RETURNS INTEGER AS '$libdir/plugin_debugger' LANGUAGE C STRICT;
|
|
|
|
/*
|
|
* pldbg_get_target_info() function can be used to return information about
|
|
@@ -68,88 +71,3 @@ CREATE TYPE targetinfo AS ( target OID, schema OID, nargs INT, argTypes oidvecto
|
|
argDefVals TEXT[]
|
|
);
|
|
|
|
--- Create the pldbg_get_target_info() function. We use an inline code block
|
|
--- so that we can check and create it slightly differently if running on
|
|
--- an EnterpriseDB server.
|
|
-
|
|
-DO $do$
|
|
-
|
|
-declare
|
|
- isedb bool;
|
|
- createstmt text;
|
|
-begin
|
|
-
|
|
- isedb = (SELECT version() LIKE 'EnterpriseDB%');
|
|
-
|
|
- createstmt := $create_stmt$
|
|
-
|
|
-CREATE FUNCTION pldbg_get_target_info(signature text, targetType "char") returns targetinfo AS $$
|
|
- SELECT p.oid AS target,
|
|
- pronamespace AS schema,
|
|
- pronargs::int4 AS nargs,
|
|
- -- The returned argtypes column is of type oidvector, but unlike
|
|
- -- proargtypes, it's supposed to include OUT params. So we
|
|
- -- essentially have to return proallargtypes, converted to an
|
|
- -- oidvector. There is no oid[] -> oidvector cast, so we have to
|
|
- -- do it via text.
|
|
- CASE WHEN proallargtypes IS NOT NULL THEN
|
|
- translate(proallargtypes::text, ',{}', ' ')::oidvector
|
|
- ELSE
|
|
- proargtypes
|
|
- END AS argtypes,
|
|
- proname AS targetname,
|
|
- proargmodes AS argmodes,
|
|
- proargnames AS proargnames,
|
|
- prolang AS targetlang,
|
|
- quote_ident(nspname) || '.' || quote_ident(proname) AS fqname,
|
|
- proretset AS returnsset,
|
|
- prorettype AS returntype,
|
|
-$create_stmt$;
|
|
-
|
|
--- Add the three EDB-columns to the query (as dummies if we're installing
|
|
--- to PostgreSQL)
|
|
-IF isedb THEN
|
|
- createstmt := createstmt ||
|
|
-$create_stmt$
|
|
- p.protype='0' AS isfunc,
|
|
- CASE WHEN n.nspparent <> 0 THEN n.oid ELSE 0 END AS pkg,
|
|
- edb_get_func_defvals(p.oid) AS argdefvals
|
|
-$create_stmt$;
|
|
-ELSE
|
|
- createstmt := createstmt ||
|
|
-$create_stmt$
|
|
- 't'::bool AS isfunc,
|
|
- 0::oid AS pkg,
|
|
- NULL::text[] AS argdefvals
|
|
-$create_stmt$;
|
|
-END IF;
|
|
- -- End of conditional part
|
|
-
|
|
- createstmt := createstmt ||
|
|
-$create_stmt$
|
|
- FROM pg_proc p, pg_namespace n
|
|
- WHERE p.pronamespace = n.oid
|
|
- AND p.oid = $1::oid
|
|
- -- We used to support querying by function name or trigger name/oid as well,
|
|
- -- but that was never used in the client, so the support for that has been
|
|
- -- removed. The targeType argument remains as a legacy of that. You're
|
|
- -- expected to pass 'o' as target type, but it doesn't do anything.
|
|
- AND $2 = 'o'
|
|
-$$ LANGUAGE SQL;
|
|
-$create_stmt$;
|
|
-
|
|
- execute createstmt;
|
|
-
|
|
--- Add a couple of EDB specific functions
|
|
-IF isedb THEN
|
|
- CREATE FUNCTION edb_oid_debug(functionOID oid) RETURNS integer AS $$
|
|
- select pldbg_oid_debug($1);
|
|
- $$ LANGUAGE SQL;
|
|
-
|
|
- CREATE FUNCTION pldbg_get_pkg_cons(packageOID oid) RETURNS oid AS $$
|
|
- select oid from pg_proc where pronamespace=$1 and proname='cons';
|
|
- $$ LANGUAGE SQL;
|
|
-END IF;
|
|
-
|
|
-end;
|
|
-$do$;
|
|
diff --git a/gpl_dependency/pldebugger/gplsrc/pldebugger_3_0/pldbgapi--unpackaged--1.0.sql b/gpl_dependency/pldebugger/gplsrc/pldebugger_3_0/pldbgapi--unpackaged--1.0.sql
|
|
index 21d32df..a195443 100644
|
|
--- a/gpl_dependency/pldebugger/gplsrc/pldebugger_3_0/pldbgapi--unpackaged--1.0.sql
|
|
+++ b/gpl_dependency/pldebugger/gplsrc/pldebugger_3_0/pldbgapi--unpackaged--1.0.sql
|
|
@@ -6,40 +6,20 @@ ALTER EXTENSION pldbgapi ADD TYPE targetinfo;
|
|
ALTER EXTENSION pldbgapi ADD TYPE var;
|
|
ALTER EXTENSION pldbgapi ADD TYPE proxyInfo;
|
|
|
|
+ALTER EXTENSION pldbgapi ADD FUNCTION plpgsql_on();
|
|
+ALTER EXTENSION pldbgapi ADD FUNCTION plpgsql_off();
|
|
ALTER EXTENSION pldbgapi ADD FUNCTION plpgsql_oid_debug( functionOID OID );
|
|
|
|
ALTER EXTENSION pldbgapi ADD FUNCTION pldbg_abort_target( session INTEGER );
|
|
ALTER EXTENSION pldbgapi ADD FUNCTION pldbg_attach_to_port( portNumber INTEGER );
|
|
ALTER EXTENSION pldbgapi ADD FUNCTION pldbg_continue( session INTEGER );
|
|
-ALTER EXTENSION pldbgapi ADD FUNCTION pldbg_create_listener();
|
|
-ALTER EXTENSION pldbgapi ADD FUNCTION pldbg_deposit_value( session INTEGER, varName TEXT, lineNumber INTEGER, value TEXT );
|
|
ALTER EXTENSION pldbgapi ADD FUNCTION pldbg_drop_breakpoint( session INTEGER, func OID, linenumber INTEGER );
|
|
ALTER EXTENSION pldbgapi ADD FUNCTION pldbg_get_breakpoints( session INTEGER );
|
|
-ALTER EXTENSION pldbgapi ADD FUNCTION pldbg_get_source( session INTEGER, func OID );
|
|
+ALTER EXTENSION pldbgapi ADD FUNCTION pldbg_get_source( func OID );
|
|
ALTER EXTENSION pldbgapi ADD FUNCTION pldbg_get_stack( session INTEGER );
|
|
ALTER EXTENSION pldbgapi ADD FUNCTION pldbg_get_proxy_info( );
|
|
ALTER EXTENSION pldbgapi ADD FUNCTION pldbg_get_variables( session INTEGER );
|
|
-ALTER EXTENSION pldbgapi ADD FUNCTION pldbg_select_frame( session INTEGER, frame INTEGER );
|
|
ALTER EXTENSION pldbgapi ADD FUNCTION pldbg_set_breakpoint( session INTEGER, func OID, linenumber INTEGER );
|
|
-ALTER EXTENSION pldbgapi ADD FUNCTION pldbg_set_global_breakpoint( session INTEGER, func OID, linenumber INTEGER, targetPID INTEGER );
|
|
ALTER EXTENSION pldbgapi ADD FUNCTION pldbg_step_into( session INTEGER );
|
|
ALTER EXTENSION pldbgapi ADD FUNCTION pldbg_step_over( session INTEGER );
|
|
-ALTER EXTENSION pldbgapi ADD FUNCTION pldbg_wait_for_breakpoint( session INTEGER );
|
|
-ALTER EXTENSION pldbgapi ADD FUNCTION pldbg_wait_for_target( session INTEGER );
|
|
-ALTER EXTENSION pldbgapi ADD FUNCTION pldbg_get_target_info( signature TEXT, targetType "char" );
|
|
|
|
-DO $do$
|
|
-
|
|
-declare
|
|
- isedb bool;
|
|
-begin
|
|
-
|
|
- isedb = (SELECT version() LIKE 'EnterpriseDB%');
|
|
-
|
|
- -- Add a couple of EDB specific functions
|
|
- IF isedb THEN
|
|
- ALTER EXTENSION pldbgapi ADD edb_oid_debug( functionOID oid );
|
|
- ALTER EXTENSION pldbgapi ADD pldbg_get_pkg_cons( packageOID oid );
|
|
- END IF;
|
|
-
|
|
-$do$;
|
|
diff --git a/gpl_dependency/pldebugger/gplsrc/pldebugger_3_0/pldbgapi.cpp b/gpl_dependency/pldebugger/gplsrc/pldebugger_3_0/pldbgapi.cpp
|
|
index 0958779..a4627d9 100644
|
|
--- a/gpl_dependency/pldebugger/gplsrc/pldebugger_3_0/pldbgapi.cpp
|
|
+++ b/gpl_dependency/pldebugger/gplsrc/pldebugger_3_0/pldbgapi.cpp
|
|
@@ -86,6 +86,12 @@
|
|
* Licensed under the Artistic License, see
|
|
* http://www.opensource.org/licenses/artistic-license.php
|
|
* for full details
|
|
+ *
|
|
+ * ----------------------------------------------------------------------------
|
|
+ * OpenGauss Modifications:
|
|
+ * For a better system performance, we add two APIs, pldbg_on() and pldbg_off(), to start up or shut down PLDEBUGGER.
|
|
+ * Some of the original APIs are reserved but not used in debugging process. For details, please see
|
|
+ * file pldbgapi--1.0.sql.
|
|
*/
|
|
|
|
#include "postgres.h"
|
|
@@ -106,10 +112,10 @@
|
|
#include <unistd.h> /* For close() */
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
-#include <arpa/inet.h>
|
|
|
|
#include "globalbp.h"
|
|
#include "dbgcomm.h"
|
|
+#include "pldebugger.h"
|
|
|
|
/* Include header for GETSTRUCT */
|
|
#if (PG_VERSION_NUM >= 90300)
|
|
@@ -128,9 +134,10 @@ PG_MODULE_MAGIC;
|
|
/*******************************************************************************
|
|
* Proxy functions
|
|
*******************************************************************************/
|
|
+PG_FUNCTION_INFO_V1( pldbg_on ); /* start pldebugger, init debug context */
|
|
+PG_FUNCTION_INFO_V1( pldbg_off ); /* close pldebugger, clear debug context */
|
|
|
|
PG_FUNCTION_INFO_V1( pldbg_attach_to_port ); /* Attach to debugger server at the given port */
|
|
-PG_FUNCTION_INFO_V1( pldbg_wait_for_breakpoint ); /* Wait for the target to reach a breakpoint */
|
|
PG_FUNCTION_INFO_V1( pldbg_step_into ); /* Steop into a function/procedure call */
|
|
PG_FUNCTION_INFO_V1( pldbg_step_over ); /* Step over a function/procedure call */
|
|
PG_FUNCTION_INFO_V1( pldbg_continue ); /* Continue execution until next breakpoint */
|
|
@@ -140,75 +147,32 @@ PG_FUNCTION_INFO_V1( pldbg_get_variables ); /* Get a list of variable names/ty
|
|
PG_FUNCTION_INFO_V1( pldbg_get_stack ); /* Get the call stack from the target */
|
|
PG_FUNCTION_INFO_V1( pldbg_set_breakpoint ); /* CREATE BREAKPOINT equivalent (deprecated) */
|
|
PG_FUNCTION_INFO_V1( pldbg_drop_breakpoint ); /* DROP BREAKPOINT equivalent (deprecated) */
|
|
-PG_FUNCTION_INFO_V1( pldbg_select_frame ); /* Change the focus to a different stack frame */
|
|
-PG_FUNCTION_INFO_V1( pldbg_deposit_value ); /* Change the value of an in-scope variable */
|
|
PG_FUNCTION_INFO_V1( pldbg_abort_target ); /* Abort execution of the target - throws error */
|
|
PG_FUNCTION_INFO_V1( pldbg_get_proxy_info ); /* Get server version, proxy API version, ... */
|
|
|
|
PG_FUNCTION_INFO_V1( pldbg_create_listener ); /* Create a listener for global breakpoints */
|
|
PG_FUNCTION_INFO_V1( pldbg_wait_for_target ); /* Wait for a global breakpoint to fire */
|
|
PG_FUNCTION_INFO_V1( pldbg_set_global_breakpoint ); /* Create a global breakpoint */
|
|
-
|
|
-/*******************************************************************************
|
|
- * Structure debugSession
|
|
- *
|
|
- * A debugger client may attach to many target sessions at the same time. We
|
|
- * keep track of each connection in a debugSession structure. When the client
|
|
- * makes a connection, we allocate a new debugSession structure and return
|
|
- * a handle to that structure to the caller. He gives us back the handle
|
|
- * whenever he calls another proxy function. A handle is just a smallish
|
|
- * integer value that we use to track each session - we use a hash to map
|
|
- * handles into debugSession pointers.
|
|
- */
|
|
-
|
|
-typedef struct
|
|
-{
|
|
- int serverSocket; /* Socket connected to the debugger server */
|
|
- int serverPort; /* Port number where debugger server is listening */
|
|
- int listener; /* Socket where we wait for global breakpoints */
|
|
- char *breakpointString;
|
|
-} debugSession;
|
|
-
|
|
-/*******************************************************************************
|
|
- * Stucture sessionHashEntry
|
|
- *
|
|
- * As mentioned above (see debugSession), a debugger proxy can manage many
|
|
- * debug sessions at once. To keep track of each session, we create a
|
|
- * debugSession object and return a handle to that object to the caller. The
|
|
- * handle is an opaque value - it's just an integer value. To convert a
|
|
- * handle into an actual debugSession pointer, we create a hash that maps
|
|
- * handles into debugSession pointers.
|
|
- *
|
|
- * Each member of the hash is shaped like a sessionHashEntry object.
|
|
- */
|
|
-typedef int32 sessionHandle;
|
|
-
|
|
-typedef struct
|
|
-{
|
|
- sessionHandle m_handle;
|
|
- debugSession *m_session;
|
|
-} sessionHashEntry;
|
|
-
|
|
-static debugSession * mostRecentSession;
|
|
-static HTAB * sessionHash;
|
|
+PG_FUNCTION_INFO_V1( pldbg_wait_for_breakpoint ); /* Wait for the target to reach a breakpoint */
|
|
+PG_FUNCTION_INFO_V1( pldbg_deposit_value ); /* Change the value of an in-scope variable */
|
|
+PG_FUNCTION_INFO_V1( pldbg_select_frame ); /* Change the focus to a different stack frame */
|
|
|
|
/*******************************************************************************
|
|
* The following symbols represent the magic strings that we send to the
|
|
* debugger server running in the target process
|
|
*/
|
|
-
|
|
-#define PLDBG_GET_VARIABLES "i\n"
|
|
-#define PLDBG_GET_BREAKPOINTS "l\n"
|
|
-#define PLDBG_GET_STACK "$\n"
|
|
-#define PLDBG_STEP_INTO "s\n"
|
|
-#define PLDBG_STEP_OVER "o\n"
|
|
-#define PLDBG_CONTINUE "c\n"
|
|
-#define PLDBG_ABORT "x"
|
|
-#define PLDBG_SELECT_FRAME "^" /* Followed by frame number */
|
|
-#define PLDBG_SET_BREAKPOINT "b" /* Followed by pkgoid:funcoid:linenumber */
|
|
-#define PLDBG_CLEAR_BREAKPOINT "f" /* Followed by pkgoid:funcoid:linenumber */
|
|
-#define PLDBG_GET_SOURCE "#" /* Followed by pkgoid:funcoid */
|
|
-#define PLDBG_DEPOSIT "d" /* Followed by var.line=value */
|
|
+#define PLDBGAPI_GET_VARIABLES "i\n"
|
|
+#define PLDBGAPI_GET_BREAKPOINTS "l\n"
|
|
+#define PLDBGAPI_GET_STACK "$\n"
|
|
+#define PLDBGAPI_STEP_INTO "s\n"
|
|
+#define PLDBGAPI_STEP_OVER "o\n"
|
|
+#define PLDBGAPI_CONTINUE "c\n"
|
|
+#define PLDBGAPI_ABORT "x"
|
|
+#define PLDBGAPI_SELECT_FRAME "^" /* Followed by frame number */
|
|
+#define PLDBGAPI_SET_BREAKPOINT "b" /* Followed by pkgoid:funcoid:linenumber */
|
|
+#define PLDBGAPI_CLEAR_BREAKPOINT "f" /* Followed by pkgoid:funcoid:linenumber */
|
|
+#define PLDBGAPI_GET_SOURCE "#" /* Followed by pkgoid:funcoid */
|
|
+#define PLDBGAPI_DEPOSIT "d" /* Followed by var.line=value */
|
|
|
|
#define PROXY_API_VERSION 3 /* API version number */
|
|
|
|
@@ -224,27 +188,30 @@ static HTAB * sessionHash;
|
|
#define GET_STR( textp ) DatumGetCString( DirectFunctionCall1( textout, PointerGetDatum( textp )))
|
|
#define PG_GETARG_SESSION( n ) (sessionHandle)PG_GETARG_UINT32( n )
|
|
|
|
-Datum pldbg_select_frame( PG_FUNCTION_ARGS );
|
|
-Datum pldbg_attach_to_port( PG_FUNCTION_ARGS );
|
|
-Datum pldbg_get_source( PG_FUNCTION_ARGS );
|
|
-Datum pldbg_get_breakpoints( PG_FUNCTION_ARGS );
|
|
-Datum pldbg_get_variables( PG_FUNCTION_ARGS );
|
|
-Datum pldbg_get_stack( PG_FUNCTION_ARGS );
|
|
-Datum pldbg_wait_for_breakpoint( PG_FUNCTION_ARGS );
|
|
-Datum pldbg_set_breakpoint( PG_FUNCTION_ARGS );
|
|
-Datum pldbg_drop_breakpoint( PG_FUNCTION_ARGS );
|
|
-Datum pldbg_step_into( PG_FUNCTION_ARGS );
|
|
-Datum pldbg_step_over( PG_FUNCTION_ARGS );
|
|
-Datum pldbg_continue( PG_FUNCTION_ARGS );
|
|
-Datum pldbg_deposit_value( PG_FUNCTION_ARGS );
|
|
-Datum pldbg_get_proxy_info( PG_FUNCTION_ARGS );
|
|
-Datum pldbg_get_pkg_cons( PG_FUNCTION_ARGS );
|
|
-Datum pldbg_abort_target( PG_FUNCTION_ARGS );
|
|
-
|
|
-Datum pldbg_create_listener( PG_FUNCTION_ARGS );
|
|
-Datum pldbg_wait_for_target( PG_FUNCTION_ARGS );
|
|
-Datum pldbg_set_global_breakpoint( PG_FUNCTION_ARGS );
|
|
|
|
+extern "C" Datum pldbg_on( PG_FUNCTION_ARGS );
|
|
+extern "C" Datum pldbg_off( PG_FUNCTION_ARGS );
|
|
+extern "C" Datum pldbg_attach_to_port( PG_FUNCTION_ARGS );
|
|
+extern "C" Datum pldbg_get_source( PG_FUNCTION_ARGS );
|
|
+extern "C" Datum pldbg_get_breakpoints( PG_FUNCTION_ARGS );
|
|
+extern "C" Datum pldbg_get_variables( PG_FUNCTION_ARGS );
|
|
+extern "C" Datum pldbg_get_stack( PG_FUNCTION_ARGS );
|
|
+extern "C" Datum pldbg_set_breakpoint( PG_FUNCTION_ARGS );
|
|
+extern "C" Datum pldbg_drop_breakpoint( PG_FUNCTION_ARGS );
|
|
+extern "C" Datum pldbg_step_into( PG_FUNCTION_ARGS );
|
|
+extern "C" Datum pldbg_step_over( PG_FUNCTION_ARGS );
|
|
+extern "C" Datum pldbg_continue( PG_FUNCTION_ARGS );
|
|
+extern "C" Datum pldbg_get_proxy_info( PG_FUNCTION_ARGS );
|
|
+extern "C" Datum pldbg_abort_target( PG_FUNCTION_ARGS );
|
|
+
|
|
+extern "C" Datum pldbg_create_listener( PG_FUNCTION_ARGS );
|
|
+extern "C" Datum pldbg_wait_for_target( PG_FUNCTION_ARGS );
|
|
+extern "C" Datum pldbg_set_global_breakpoint( PG_FUNCTION_ARGS );
|
|
+extern "C" Datum pldbg_select_frame( PG_FUNCTION_ARGS );
|
|
+extern "C" Datum pldbg_wait_for_breakpoint( PG_FUNCTION_ARGS );
|
|
+extern "C" Datum pldbg_deposit_value( PG_FUNCTION_ARGS );
|
|
+
|
|
+Datum pldbg_get_pkg_cons(PG_FUNCTION_ARGS);
|
|
/************************************************************
|
|
* Local function forward declarations
|
|
************************************************************/
|
|
@@ -253,22 +220,60 @@ static void * readn( int serverHandle, void * dst, size_t len );
|
|
static void * writen( int serverHandle, void * dst, size_t len );
|
|
static void sendBytes( debugSession * session, void * src, size_t len );
|
|
static void sendUInt32( debugSession * session, uint32 val );
|
|
-static void sendString( debugSession * session, char * src );
|
|
+void sendString( debugSession * session, char * src );
|
|
static bool getBool( debugSession * session );
|
|
static uint32 getUInt32( debugSession * session );
|
|
static char * getNString( debugSession * session );
|
|
-static void initializeModule( void );
|
|
+void registCallbackInSessExit( void );
|
|
static void cleanupAtExit( int code, Datum arg );
|
|
-static void initSessionHash();
|
|
static debugSession * defaultSession( sessionHandle handle );
|
|
static sessionHandle addSession( debugSession * session );
|
|
static debugSession * findSession( sessionHandle handle );
|
|
static TupleDesc getResultTupleDesc( FunctionCallInfo fcinfo );
|
|
-
|
|
+void clearSocketContent(debugSession* session);
|
|
|
|
/*******************************************************************************
|
|
* Exported functions
|
|
*******************************************************************************/
|
|
+/*******************************************************************************
|
|
+ * pldbg_on, pldbg_off
|
|
+ * start up or close the pldebugger on the target session, so we can attach the breakpoint and start debugging process.
|
|
+ *
|
|
+ * pldbg_on() is the API to start the pldebugger, it can be manually called and will also auto loaded through other APIs
|
|
+ *
|
|
+ * function added by openGauss
|
|
+ */
|
|
+Datum pldbg_on(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ if (IS_PLDEBUGGER_ON) {
|
|
+ ereport(NOTICE, (errmsg("pldebugger is alreadly on.")));
|
|
+ PG_RETURN_BOOL(true);
|
|
+ }
|
|
+ init_pldebugger_role(PLDBG_SERVER);
|
|
+ PG_RETURN_BOOL(true);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * pldbg_off() is the API to shut down the pldebuggre, it will be triggered when the session exits, or the pldebugger
|
|
+ * will keep running during the active session, which is not good for the proformance. So it is better to manually call
|
|
+ * pldbg_off() when debugger is not used.
|
|
+ *
|
|
+ * function added by openGauss
|
|
+ */
|
|
+Datum pldbg_off(PG_FUNCTION_ARGS)
|
|
+{
|
|
+ if (!IS_PLDEBUGGER_ON) {
|
|
+ ereport(NOTICE, (errmsg("pldebugger server or client is not on.")));
|
|
+ PG_RETURN_BOOL(true);
|
|
+ }
|
|
+ if (IS_PLDEBUGGER_SERVER) {
|
|
+ pldbg_server_shutdown();
|
|
+ } else if (IS_PLDEBUGGER_CLIENT) {
|
|
+ pldbg_client_shutdown();
|
|
+ }
|
|
+ destroy_pldebugger_context();
|
|
+ PG_RETURN_BOOL(true);
|
|
+}
|
|
|
|
/*******************************************************************************
|
|
* pldbg_attach_to_port( portNumber INTEGER ) RETURNS INTEGER
|
|
@@ -288,13 +293,16 @@ static TupleDesc getResultTupleDesc( FunctionCallInfo fcinfo );
|
|
|
|
Datum pldbg_attach_to_port( PG_FUNCTION_ARGS )
|
|
{
|
|
+ if (!IS_PLDEBUGGER_CLIENT) {
|
|
+ init_pldebugger_role(PLDBG_CLIENT);
|
|
+ }
|
|
+
|
|
int32 targetBackend = PG_GETARG_INT32( 0 );
|
|
debugSession *session;
|
|
|
|
- initializeModule();
|
|
-
|
|
- session = MemoryContextAllocZero( TopMemoryContext, sizeof( *session ));
|
|
+ session = (debugSession*)MemoryContextAllocZero( PldbgMemoryContext, sizeof( *session ));
|
|
session->listener = -1;
|
|
+ session->state = DBG_SESS_ACTIVE;
|
|
|
|
session->serverSocket = dbgcomm_connect_to_target(targetBackend);
|
|
|
|
@@ -308,7 +316,7 @@ Datum pldbg_attach_to_port( PG_FUNCTION_ARGS )
|
|
* the local breakpoint that it hit. Read it. We will hand it to the client
|
|
* if it calls wait_for_breakpoint().
|
|
*/
|
|
- session->breakpointString = MemoryContextStrdup(TopMemoryContext,
|
|
+ session->breakpointString = MemoryContextStrdup(PldbgMemoryContext,
|
|
getNString(session));
|
|
|
|
/*
|
|
@@ -323,12 +331,14 @@ Datum pldbg_attach_to_port( PG_FUNCTION_ARGS )
|
|
|
|
Datum pldbg_create_listener( PG_FUNCTION_ARGS )
|
|
{
|
|
- debugSession * session = MemoryContextAllocZero( TopMemoryContext, sizeof( *session ));
|
|
-
|
|
- initializeModule();
|
|
+ if (!IS_PLDEBUGGER_CLIENT) {
|
|
+ init_pldebugger_role(PLDBG_CLIENT);
|
|
+ }
|
|
+ debugSession * session = (debugSession*)MemoryContextAllocZero( PldbgMemoryContext, sizeof( *session ));
|
|
|
|
session->listener = dbgcomm_listen_for_target(&session->serverPort);
|
|
session->serverSocket = -1;
|
|
+ session->state = DBG_SESS_ACTIVE;
|
|
|
|
mostRecentSession = session;
|
|
|
|
@@ -354,15 +364,15 @@ Datum pldbg_wait_for_target( PG_FUNCTION_ARGS )
|
|
{
|
|
debugSession *session = defaultSession(PG_GETARG_SESSION( 0 ));
|
|
int serverSocket;
|
|
- int serverPID;
|
|
+ uint64 serverSessId;
|
|
|
|
/*
|
|
* Now mark all of our global breakpoints as 'available' (that is, not
|
|
* busy)
|
|
*/
|
|
- BreakpointFreeSession( MyProc->pid );
|
|
+ BreakpointFreeSession(MY_SESS_ID);
|
|
|
|
- serverSocket = dbgcomm_accept_target(session->listener, &serverPID);
|
|
+ serverSocket = dbgcomm_accept_target(session->listener, &serverSessId);
|
|
if (serverSocket < 0)
|
|
ereport(ERROR,
|
|
(errmsg("could not accept a connection from debugging target")));
|
|
@@ -374,10 +384,10 @@ Datum pldbg_wait_for_target( PG_FUNCTION_ARGS )
|
|
* the local breakpoint that it hit. Read it. We will hand it to the client
|
|
* if it calls wait_for_breakpoint().
|
|
*/
|
|
- session->breakpointString = MemoryContextStrdup(TopMemoryContext,
|
|
+ session->breakpointString = MemoryContextStrdup(PldbgMemoryContext,
|
|
getNString(session));
|
|
|
|
- PG_RETURN_UINT32( serverPID );
|
|
+ PG_RETURN_INT64(serverSessId);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
@@ -402,7 +412,7 @@ Datum pldbg_set_global_breakpoint( PG_FUNCTION_ARGS )
|
|
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
|
errmsg("given session is not a listener")));
|
|
|
|
- breakpoint.key.databaseId = MyProc->databaseId;
|
|
+ breakpoint.key.databaseId = t_thrd.proc->databaseId;
|
|
breakpoint.key.functionId = PG_GETARG_OID( 1 );
|
|
|
|
if( PG_ARGISNULL( 2 ))
|
|
@@ -411,13 +421,13 @@ Datum pldbg_set_global_breakpoint( PG_FUNCTION_ARGS )
|
|
breakpoint.key.lineNumber = PG_GETARG_INT32( 2 );
|
|
|
|
if( PG_ARGISNULL( 3 ))
|
|
- breakpoint.key.targetPid = -1;
|
|
+ breakpoint.key.targetSessId = -1;
|
|
else
|
|
- breakpoint.key.targetPid = PG_GETARG_INT32( 3 );
|
|
+ breakpoint.key.targetSessId = PG_GETARG_INT32(3);
|
|
|
|
breakpoint.data.isTmp = TRUE;
|
|
breakpoint.data.proxyPort = session->serverPort;
|
|
- breakpoint.data.proxyPid = MyProc->pid;
|
|
+ breakpoint.data.proxyPid = MY_SESS_ID;
|
|
|
|
if( !BreakpointInsert( BP_GLOBAL, &breakpoint.key, &breakpoint.data ))
|
|
ereport(ERROR,
|
|
@@ -427,19 +437,6 @@ Datum pldbg_set_global_breakpoint( PG_FUNCTION_ARGS )
|
|
PG_RETURN_BOOL( true );
|
|
}
|
|
|
|
-/*******************************************************************************
|
|
- * pldbg_wait_for_breakpoint( sessionID INTEGER ) RETURNS breakpoint
|
|
- *
|
|
- * This function waits for the debug target to reach a breakpoint. You should
|
|
- * call this function immediately after pldbg_attach_to_port() returns a
|
|
- * session ID. pldbg_wait_for_breakpoint() is nearly identical to
|
|
- * pldbg_step_into(), pldbg_step_over(), and pldbg_continue(), (they all wait
|
|
- * for the target) but this function does not send a command to the target
|
|
- * first.
|
|
- *
|
|
- * This function returns a tuple of type 'breakpoint' - such a tuple contains
|
|
- * the function OID and line number where the target is currently stopped.
|
|
- */
|
|
|
|
static Datum buildBreakpointDatum( char * breakpointString )
|
|
{
|
|
@@ -457,6 +454,19 @@ static Datum buildBreakpointDatum( char * breakpointString )
|
|
return( HeapTupleGetDatum( result ));
|
|
}
|
|
|
|
+/*******************************************************************************
|
|
+ * pldbg_wait_for_breakpoint( sessionID INTEGER ) RETURNS breakpoint
|
|
+ *
|
|
+ * This function waits for the debug target to reach a breakpoint. You should
|
|
+ * call this function immediately after pldbg_attach_to_port() returns a
|
|
+ * session ID. pldbg_wait_for_breakpoint() is nearly identical to
|
|
+ * pldbg_step_into(), pldbg_step_over(), and pldbg_continue(), (they all wait
|
|
+ * for the target) but this function does not send a command to the target
|
|
+ * first.
|
|
+ *
|
|
+ * This function returns a tuple of type 'breakpoint' - such a tuple contains
|
|
+ * the function OID and line number where the target is currently stopped.
|
|
+ */
|
|
Datum pldbg_wait_for_breakpoint( PG_FUNCTION_ARGS )
|
|
{
|
|
debugSession * session = defaultSession( PG_GETARG_SESSION( 0 ));
|
|
@@ -486,7 +496,7 @@ Datum pldbg_step_into( PG_FUNCTION_ARGS )
|
|
{
|
|
debugSession * session = defaultSession( PG_GETARG_SESSION( 0 ));
|
|
|
|
- sendString( session, PLDBG_STEP_INTO );
|
|
+ sendString( session, PLDBGAPI_STEP_INTO );
|
|
|
|
PG_RETURN_DATUM( buildBreakpointDatum( getNString( session )));
|
|
}
|
|
@@ -508,7 +518,7 @@ Datum pldbg_step_over( PG_FUNCTION_ARGS )
|
|
{
|
|
debugSession * session = defaultSession( PG_GETARG_SESSION( 0 ));
|
|
|
|
- sendString( session, PLDBG_STEP_OVER );
|
|
+ sendString( session, PLDBGAPI_STEP_OVER );
|
|
|
|
PG_RETURN_DATUM( buildBreakpointDatum( getNString( session )));
|
|
}
|
|
@@ -526,8 +536,9 @@ Datum pldbg_step_over( PG_FUNCTION_ARGS )
|
|
Datum pldbg_continue( PG_FUNCTION_ARGS )
|
|
{
|
|
debugSession * session = defaultSession( PG_GETARG_SESSION( 0 ));
|
|
-
|
|
- sendString( session, PLDBG_CONTINUE );
|
|
+
|
|
+ clearSocketContent(session);
|
|
+ sendString( session, PLDBGAPI_CONTINUE );
|
|
|
|
PG_RETURN_DATUM( buildBreakpointDatum( getNString( session )));
|
|
}
|
|
@@ -542,10 +553,12 @@ Datum pldbg_continue( PG_FUNCTION_ARGS )
|
|
Datum pldbg_abort_target( PG_FUNCTION_ARGS )
|
|
{
|
|
debugSession * session = defaultSession( PG_GETARG_SESSION( 0 ));
|
|
-
|
|
- sendString( session, PLDBG_ABORT );
|
|
+ bool res;
|
|
|
|
- PG_RETURN_BOOL( getBool( session ));
|
|
+ sendString( session, PLDBGAPI_ABORT );
|
|
+ res = getBool(session) ? true : getBool(session); /* the first is breakpoint str, except the first command. */
|
|
+
|
|
+ PG_RETURN_BOOL(res);
|
|
|
|
}
|
|
|
|
@@ -581,8 +594,10 @@ Datum pldbg_select_frame( PG_FUNCTION_ARGS )
|
|
char frameString[12]; /* sign, 10 digits, '\0' */
|
|
char * resultString;
|
|
Datum result;
|
|
+ errno_t rc;
|
|
|
|
- sprintf( frameString, "%s %d", PLDBG_SELECT_FRAME, frameNumber );
|
|
+ rc = sprintf_s(frameString, 12, "%s %d", PLDBGAPI_SELECT_FRAME, frameNumber); // sizeof frameString.
|
|
+ securec_check_ss(rc, "\0", "\0");
|
|
|
|
sendString( session, frameString );
|
|
|
|
@@ -608,6 +623,11 @@ Datum pldbg_select_frame( PG_FUNCTION_ARGS )
|
|
* ensures that the source code that you get is the source code that the
|
|
* target is executing.
|
|
*
|
|
+ * OpenGauss Modifications:
|
|
+ * This function is no longer used in openGauss, because it will cause some unexpected results, like
|
|
+ * if we pass in an OID that does not exist, server will throw an ERROR and then abort, so we
|
|
+ * just do a 'get-source' action in client by a sql function 'select pg_proc' rewrited in pldbgapi--1.0.sql.
|
|
+ *
|
|
*/
|
|
|
|
Datum pldbg_get_source( PG_FUNCTION_ARGS )
|
|
@@ -617,7 +637,8 @@ Datum pldbg_get_source( PG_FUNCTION_ARGS )
|
|
char sourceString[13]; /* 10 digits(oid) + space + 1 command + null terminator */
|
|
char * source;
|
|
|
|
- sprintf( sourceString, "%s %d", PLDBG_GET_SOURCE, funcOID );
|
|
+ errno_t rc = sprintf_s(sourceString, 13, "%s %d", PLDBGAPI_GET_SOURCE, funcOID); // sizeof sourceString
|
|
+ securec_check_ss(rc, "\0", "\0");
|
|
|
|
sendString( session, sourceString );
|
|
|
|
@@ -654,7 +675,7 @@ Datum pldbg_get_breakpoints( PG_FUNCTION_ARGS )
|
|
srf->attinmeta = TupleDescGetAttInMetadata( RelationNameGetTupleDesc( TYPE_NAME_BREAKPOINT ));
|
|
MemoryContextSwitchTo( oldContext );
|
|
|
|
- sendString( session, PLDBG_GET_BREAKPOINTS );
|
|
+ sendString( session, PLDBGAPI_GET_BREAKPOINTS );
|
|
}
|
|
else
|
|
{
|
|
@@ -706,7 +727,7 @@ Datum pldbg_get_variables( PG_FUNCTION_ARGS )
|
|
srf->attinmeta = TupleDescGetAttInMetadata( RelationNameGetTupleDesc( TYPE_NAME_VAR ));
|
|
MemoryContextSwitchTo( oldContext );
|
|
|
|
- sendString( session, PLDBG_GET_VARIABLES );
|
|
+ sendString( session, PLDBGAPI_GET_VARIABLES );
|
|
}
|
|
else
|
|
{
|
|
@@ -769,7 +790,7 @@ Datum pldbg_get_stack( PG_FUNCTION_ARGS )
|
|
srf->attinmeta = TupleDescGetAttInMetadata( RelationNameGetTupleDesc( TYPE_NAME_FRAME ));
|
|
MemoryContextSwitchTo( oldContext );
|
|
|
|
- sendString( session, PLDBG_GET_STACK );
|
|
+ sendString( session, PLDBGAPI_GET_STACK );
|
|
}
|
|
else
|
|
{
|
|
@@ -787,7 +808,8 @@ Datum pldbg_get_stack( PG_FUNCTION_ARGS )
|
|
* frameString points to a string like:
|
|
* targetName:funcOID:lineNumber:arguments
|
|
*/
|
|
- sprintf( callCount, "%d", srf->call_cntr );
|
|
+ errno_t rc = sprintf_s(callCount, 11, "%d", srf->call_cntr); /* size of callcount */
|
|
+ securec_check_ss(rc, "\0", "\0");
|
|
|
|
values[0] = callCount;
|
|
values[1] = tokenize( frameString, ":", &ctx ); /* targetName */
|
|
@@ -827,7 +849,7 @@ Datum pldbg_get_proxy_info( PG_FUNCTION_ARGS )
|
|
values[0] = DirectFunctionCall1( textin, PointerGetDatum( PG_VERSION_STR ));
|
|
values[1] = Int32GetDatum( PG_VERSION_NUM );
|
|
values[2] = Int32GetDatum( PROXY_API_VERSION );
|
|
- values[3] = Int32GetDatum( MyProcPid );
|
|
+ values[3] = UInt64GetDatum(MY_SESS_ID);
|
|
|
|
result = heap_form_tuple( tupleDesc, values, nulls );
|
|
|
|
@@ -847,9 +869,11 @@ Datum pldbg_set_breakpoint( PG_FUNCTION_ARGS )
|
|
Oid funcOID = PG_GETARG_OID( 1 );
|
|
int lineNumber = PG_GETARG_INT32( 2 );
|
|
char breakpointString[24]; /* 20 digits + 2 delimiters + 1 command + null terminator */
|
|
+ errno_t rc;
|
|
|
|
- sprintf( breakpointString, "%s %d:%d", PLDBG_SET_BREAKPOINT, funcOID, lineNumber );
|
|
-
|
|
+ rc = sprintf_s(breakpointString, 24, "%s %d:%d", // sizeof breakpointString
|
|
+ PLDBGAPI_SET_BREAKPOINT, funcOID, lineNumber);
|
|
+ securec_check_ss(rc, "\0", "\0");
|
|
sendString( session, breakpointString );
|
|
|
|
PG_RETURN_BOOL( getBool( session ));
|
|
@@ -866,9 +890,11 @@ Datum pldbg_drop_breakpoint( PG_FUNCTION_ARGS )
|
|
Oid funcOID = PG_GETARG_OID( 1 );
|
|
int lineNumber = PG_GETARG_INT32( 2 );
|
|
char breakpointString[13]; /* 10 digits + 1 delimiters + 1 command + null terminator */
|
|
+ errno_t rc;
|
|
|
|
- sprintf( breakpointString, "%s %d:%d", PLDBG_CLEAR_BREAKPOINT, funcOID, lineNumber );
|
|
-
|
|
+ rc = sprintf_s(breakpointString, 13, "%s %d:%d", // sizeof breakpointString
|
|
+ PLDBGAPI_CLEAR_BREAKPOINT, funcOID, lineNumber);
|
|
+ securec_check_ss(rc, "\0", "\0");
|
|
sendString( session, breakpointString );
|
|
|
|
PG_RETURN_BOOL( getBool( session ));
|
|
@@ -894,7 +920,7 @@ Datum pldbg_deposit_value( PG_FUNCTION_ARGS )
|
|
|
|
initStringInfo( &buf );
|
|
|
|
- appendStringInfo( &buf, "%s %s.%d=%s", PLDBG_DEPOSIT, varName, lineNumber, value );
|
|
+ appendStringInfo( &buf, "%s %s.%d=%s", PLDBGAPI_DEPOSIT, varName, lineNumber, value );
|
|
|
|
sendString( session, buf.data );
|
|
|
|
@@ -909,9 +935,9 @@ Datum pldbg_deposit_value( PG_FUNCTION_ARGS )
|
|
*******************************************************************************/
|
|
|
|
/*******************************************************************************
|
|
- * initializeModule()
|
|
+ * registCallbackInSessExit()
|
|
*
|
|
- * Initializes the debugger proxy module. For now, we just register a callback
|
|
+ * For now, we just register a callback
|
|
* (cleanupAtExit()) that this backend will invoke on exit - we use that
|
|
* callback to gracefully close any outstanding connections.
|
|
*
|
|
@@ -919,16 +945,13 @@ Datum pldbg_deposit_value( PG_FUNCTION_ARGS )
|
|
* each of the complex datatypes that we use (breakpoint, var, frame).
|
|
*/
|
|
|
|
-static void initializeModule( void )
|
|
+void registCallbackInSessExit( void )
|
|
{
|
|
- static bool initialized = FALSE;
|
|
-
|
|
- if( !initialized )
|
|
- {
|
|
- initialized = TRUE;
|
|
-
|
|
- on_shmem_exit( cleanupAtExit, 0 );
|
|
- }
|
|
+ if (!g_instance.attr.attr_common.enable_thread_pool) {
|
|
+ on_proc_exit(cleanupAtExit, 0);
|
|
+ } else {
|
|
+ u_sess->ext_fdw_ctx[PLDEBUG_TYPE].fdwExitFunc = cleanupAtExit;
|
|
+ }
|
|
}
|
|
|
|
/*******************************************************************************
|
|
@@ -944,18 +967,21 @@ static void initializeModule( void )
|
|
*
|
|
* NOTE: If you give this function an invalid sessionHandle it will throw an
|
|
* error. A sessionHandle is valid if returned by addSession().
|
|
+ *
|
|
+ * openGauss Modification:
|
|
+ * session state will be check here, before server close, it will send close
|
|
+ * message to client, then client mark this session DBG_SESS_NOTCONNECT.
|
|
*/
|
|
|
|
static debugSession * defaultSession( sessionHandle handle )
|
|
{
|
|
- debugSession * session;
|
|
+ MAKESURE_CLIENT_IS_ON;
|
|
+ debugSession * session = mostRecentSession;
|
|
|
|
if( handle == 0 )
|
|
{
|
|
if( mostRecentSession == NULL )
|
|
ereport( ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg( "invalid session handle" )));
|
|
- else
|
|
- return( mostRecentSession );
|
|
}
|
|
else
|
|
{
|
|
@@ -966,11 +992,13 @@ static debugSession * defaultSession( sessionHandle handle )
|
|
else
|
|
{
|
|
mostRecentSession = session;
|
|
- return( session );
|
|
}
|
|
}
|
|
+ if (session->state == DBG_SESS_NOTCONNECT) {
|
|
+ ereport(ERROR, (errcode(ERRCODE_CONNECTION_FAILURE), errmsg("Session connect failed, server is not on")));
|
|
+ }
|
|
|
|
- return( NULL ); /* keep the compiler happy */
|
|
+ return(session); /* keep the compiler happy */
|
|
}
|
|
|
|
/*******************************************************************************
|
|
@@ -979,12 +1007,15 @@ static debugSession * defaultSession( sessionHandle handle )
|
|
* Initialize a hash table that we use to map session handles (simple integer
|
|
* values) into debugSession pointers.
|
|
*
|
|
- * You should call this function before you use the hash - you can call it
|
|
- * as many times as you like, it will only initialize the hash table on the
|
|
- * first invocation.
|
|
+ * You should call this function before you use the hash - you can call it
|
|
+ * as many times as you like, it will only initialize the hash table on the
|
|
+ * first invocation.
|
|
+ *
|
|
+ * OpenGauss Modifications:
|
|
+ * session hash will be inited when client is starting up;
|
|
*/
|
|
|
|
-static void initSessionHash()
|
|
+void initSessionHash()
|
|
{
|
|
if( sessionHash )
|
|
return;
|
|
@@ -995,8 +1026,9 @@ static void initSessionHash()
|
|
ctl.keysize = sizeof( sessionHandle );
|
|
ctl.entrysize = sizeof( sessionHashEntry );
|
|
ctl.hash = tag_hash;
|
|
+ ctl.hcxt = PldbgMemoryContext;
|
|
|
|
- sessionHash = hash_create( "Debugger sessions", 5, &ctl, HASH_ELEM | HASH_FUNCTION );
|
|
+ sessionHash = hash_create( "Debugger sessions", 5, &ctl, HASH_CONTEXT | HASH_ELEM | HASH_FUNCTION );
|
|
}
|
|
}
|
|
|
|
@@ -1014,14 +1046,13 @@ static void initSessionHash()
|
|
|
|
static sessionHandle addSession( debugSession * session )
|
|
{
|
|
- static sessionHandle nextHandle;
|
|
sessionHashEntry * entry;
|
|
bool found;
|
|
sessionHandle handle;
|
|
|
|
initSessionHash();
|
|
|
|
- handle = ++nextHandle;
|
|
+ handle = nextHandle ++;
|
|
|
|
entry = (sessionHashEntry *)hash_search( sessionHash, &handle, HASH_ENTER, &found );
|
|
|
|
@@ -1045,7 +1076,7 @@ static debugSession * findSession( sessionHandle handle )
|
|
|
|
initSessionHash();
|
|
|
|
- if(( entry = hash_search( sessionHash, &handle, HASH_FIND, NULL )) != NULL )
|
|
+ if(( entry = (sessionHashEntry*)hash_search( sessionHash, &handle, HASH_FIND, NULL )) != NULL )
|
|
{
|
|
return( entry->m_session );
|
|
}
|
|
@@ -1131,7 +1162,7 @@ static void * readn( int serverHandle, void * dst, size_t len )
|
|
char * buffer = (char *)dst;
|
|
|
|
if( serverHandle == -1 )
|
|
- ereport( ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg( "given session is not connected" )));
|
|
+ ereport(ERROR, (errcode(ERRCODE_CONNECTION_DOES_NOT_EXIST), errmsg("given session is not connected")));
|
|
|
|
while( bytesRemaining > 0 )
|
|
{
|
|
@@ -1152,9 +1183,9 @@ static void * readn( int serverHandle, void * dst, size_t len )
|
|
|
|
FD_ZERO( &rmask );
|
|
FD_SET( serverHandle, &rmask );
|
|
- FD_SET( MyProcPort->sock, &rmask );
|
|
+ FD_SET( u_sess->proc_cxt.MyProcPort->sock, &rmask );
|
|
|
|
- switch( select(( serverHandle > MyProcPort->sock ? serverHandle : MyProcPort->sock ) + 1, &rmask, NULL, NULL, NULL ))
|
|
+ switch( select(( serverHandle > u_sess->proc_cxt.MyProcPort->sock ? serverHandle : u_sess->proc_cxt.MyProcPort->sock ) + 1, &rmask, NULL, NULL, NULL ))
|
|
{
|
|
case -1:
|
|
{
|
|
@@ -1179,7 +1210,7 @@ static void * readn( int serverHandle, void * dst, size_t len )
|
|
* is when the client process has killed itself...
|
|
*/
|
|
|
|
- if( FD_ISSET( MyProcPort->sock, &rmask ))
|
|
+ if( FD_ISSET( u_sess->proc_cxt.MyProcPort->sock, &rmask ))
|
|
ereport( ERROR, ( ERRCODE_CONNECTION_FAILURE, errmsg( "debugger connection(client side) terminated" )));
|
|
break;
|
|
}
|
|
@@ -1266,7 +1297,7 @@ static void sendUInt32( debugSession * session, uint32 val )
|
|
* don't send the null-terminator.
|
|
*/
|
|
|
|
-static void sendString( debugSession * session, char * src )
|
|
+void sendString( debugSession * session, char * src )
|
|
{
|
|
size_t len = strlen( src );
|
|
|
|
@@ -1328,6 +1359,10 @@ static uint32 getUInt32( debugSession * session )
|
|
* enough space to hold the entire string (including the null-terminator) and
|
|
* return a pointer to that space (after, of course, reading the string from
|
|
* the server and tacking on the null-terminator).
|
|
+ *
|
|
+ * OpenGauss Modifications:
|
|
+ * " : : " means that server is closed, it will be sent to client before server's shutdown,
|
|
+ * so that client can mark this session state as DBG_SESS_NOTCONNECT;
|
|
*/
|
|
|
|
static char * getNString( debugSession * session )
|
|
@@ -1336,16 +1371,18 @@ static char * getNString( debugSession * session )
|
|
|
|
if( len == 0 )
|
|
return( NULL );
|
|
- else
|
|
- {
|
|
- char * result = palloc( len + 1 );
|
|
-
|
|
- readn( session->serverSocket, result, len );
|
|
|
|
- result[len] = '\0';
|
|
+ char * result = (char*)palloc( len + 1 );
|
|
+ readn( session->serverSocket, result, len );
|
|
+ result[len] = '\0';
|
|
|
|
- return( result );
|
|
+ if (strcmp(result, " : : ") == 0) {
|
|
+ session->state = DBG_SESS_NOTCONNECT;
|
|
+ pfree(result);
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_CONNECTION_DOES_NOT_EXIST), errmsg("The pldebugger server has been shutdown.")));
|
|
}
|
|
+ return( result );
|
|
}
|
|
|
|
/*******************************************************************************
|
|
@@ -1355,18 +1392,12 @@ static char * getNString( debugSession * session )
|
|
* server.
|
|
*/
|
|
|
|
-static void closeSession( debugSession * session )
|
|
+void closeSession( debugSession * session )
|
|
{
|
|
- if( session->serverSocket )
|
|
- closesocket( session->serverSocket );
|
|
+ if( session->serverSocket )
|
|
+ closesocket( session->serverSocket );
|
|
|
|
- if( session->listener )
|
|
- BreakpointCleanupProc( MyProcPid );
|
|
-
|
|
- if( session->breakpointString )
|
|
- pfree( session->breakpointString );
|
|
-
|
|
- pfree( session );
|
|
+ session->state = DBG_SESS_NOTCONNECT;
|
|
}
|
|
|
|
/******************************************************************************
|
|
@@ -1375,19 +1406,14 @@ static void closeSession( debugSession * session )
|
|
* This is a callback function that the backend invokes when exiting. At exit,
|
|
* we close any connections that we may still have (connections to debugger
|
|
* servers, that is).
|
|
+ *
|
|
+ * OpenGauss Modifications:
|
|
+ * We call the new function pldbg_off() instead to clean up everything.
|
|
*/
|
|
|
|
static void cleanupAtExit( int code, Datum arg )
|
|
{
|
|
- /*
|
|
- * FIXME: we should clean up all of the sessions stored in the
|
|
- * sessionHash.
|
|
- */
|
|
-
|
|
- if( mostRecentSession )
|
|
- closeSession( mostRecentSession );
|
|
-
|
|
- mostRecentSession = NULL;
|
|
+ pldbg_off(NULL);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
@@ -1417,3 +1443,26 @@ static TupleDesc getResultTupleDesc( FunctionCallInfo fcinfo )
|
|
}
|
|
return( rsinfo->expectedDesc );
|
|
}
|
|
+
|
|
+/******************************************************************************
|
|
+ * clearSocketContent
|
|
+ * clear socket content
|
|
+ */
|
|
+void clearSocketContent(debugSession* session)
|
|
+{
|
|
+ fd_set fds;
|
|
+ struct timeval timeout={0,1};
|
|
+ FD_ZERO(&fds);
|
|
+ FD_SET(session->serverSocket, &fds);
|
|
+ for (;;) {
|
|
+ switch (select(session->serverSocket + 1, &fds, NULL, NULL, &timeout)) {
|
|
+ case -1:
|
|
+ ereport(ERROR, (errmsg("select() failed while waiting for target")));
|
|
+ case 0:
|
|
+ return;
|
|
+ default:
|
|
+ pfree(getNString(session));
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+}
|
|
\ No newline at end of file
|
|
diff --git a/gpl_dependency/pldebugger/gplsrc/pldebugger_3_0/pldebugger.h b/gpl_dependency/pldebugger/gplsrc/pldebugger_3_0/pldebugger.h
|
|
index 223ac81..8d15040 100644
|
|
--- a/gpl_dependency/pldebugger/gplsrc/pldebugger_3_0/pldebugger.h
|
|
+++ b/gpl_dependency/pldebugger/gplsrc/pldebugger_3_0/pldebugger.h
|
|
@@ -1,8 +1,22 @@
|
|
+/*
|
|
+ * OpenGauss Modification:
|
|
+ * We have made the following modifications on the source code to adapt to openGauss:
|
|
+ * 1. 'LWLockId' is redefined to 'LWLock' by typedef method.
|
|
+ * 2. Some structs in other .cpp files have been moved to here.
|
|
+ * 3. 'debugSessionState' var is added to mark session status in client.
|
|
+ * 4. Add a message command 'PLDBG_DISCONNECT', which means the client is closed, and the server will
|
|
+ * re-send a message to proxy and keep waiting for a new client to connect.
|
|
+ *
|
|
+ * 5. Most importantly, we split the contents of pldebugger into server and client, and each role will keep their
|
|
+ * own vars within the struct scope. All of these vars are inited in 'init_pldebugger_role()'.
|
|
+ */
|
|
#ifndef PLDEBUGGER_H
|
|
#define PLDEBUGGER_H
|
|
|
|
#include "globalbp.h"
|
|
-#include "storage/lwlock.h"
|
|
+#include "storage/lock/lwlock.h"
|
|
+
|
|
+typedef LWLock *LWLockId;
|
|
|
|
/*
|
|
* We keep one per_session_ctx structure per backend. This structure holds all
|
|
@@ -15,8 +29,65 @@ typedef struct
|
|
int client_w; /* Write stream connected to client */
|
|
} per_session_ctx_t;
|
|
|
|
-extern per_session_ctx_t per_session_ctx;
|
|
+/*******************************************************************************
|
|
+ * Structure debugSession
|
|
+ *
|
|
+ * A debugger client may attach to many target sessions at the same time. We
|
|
+ * keep track of each connection in a debugSession structure. When the client
|
|
+ * makes a connection, we allocate a new debugSession structure and return
|
|
+ * a handle to that structure to the caller. He gives us back the handle
|
|
+ * whenever he calls another proxy function. A handle is just a smallish
|
|
+ * integer value that we use to track each session - we use a hash to map
|
|
+ * handles into debugSession pointers.
|
|
+ */
|
|
+typedef enum debugSessionState {
|
|
+ DBG_SESS_UNINIT, // session not init
|
|
+ DBG_SESS_ACTIVE, // session server active.
|
|
+ DBG_SESS_NOTCONNECT // session server has been shutdown.
|
|
+} debugSessionState;
|
|
+
|
|
+typedef struct
|
|
+{
|
|
+ int serverSocket; /* Socket connected to the debugger server */
|
|
+ int serverPort; /* Port number where debugger server is listening */
|
|
+ int listener; /* Socket where we wait for global breakpoints */
|
|
+ char *breakpointString;
|
|
+ debugSessionState state;
|
|
+} debugSession;
|
|
+
|
|
+/*******************************************************************************
|
|
+ * Stucture sessionHashEntry
|
|
+ *
|
|
+ * As mentioned above (see debugSession), a debugger proxy can manage many
|
|
+ * debug sessions at once. To keep track of each session, we create a
|
|
+ * debugSession object and return a handle to that object to the caller. The
|
|
+ * handle is an opaque value - it's just an integer value. To convert a
|
|
+ * handle into an actual debugSession pointer, we create a hash that maps
|
|
+ * handles into debugSession pointers.
|
|
+ *
|
|
+ * Each member of the hash is shaped like a sessionHashEntry object.
|
|
+ */
|
|
+typedef int32 sessionHandle;
|
|
+
|
|
+typedef struct
|
|
+{
|
|
+ sessionHandle m_handle;
|
|
+ debugSession *m_session;
|
|
+} sessionHashEntry;
|
|
|
|
+typedef struct
|
|
+{
|
|
+ void (* initialize)(void);
|
|
+ bool (* frame_belongs_to_me)(ErrorContextCallback *frame);
|
|
+ void (* send_stack_frame)(ErrorContextCallback *frame);
|
|
+ void (* send_vars)(ErrorContextCallback *frame);
|
|
+ void (* select_frame)(ErrorContextCallback *frame);
|
|
+ void (* print_var)(ErrorContextCallback *frame, const char *var_name, int lineno);
|
|
+ bool (* do_deposit)(ErrorContextCallback *frame, const char *var_name,
|
|
+ int line_number, const char *value);
|
|
+ Oid (* get_func_oid)(ErrorContextCallback *frame);
|
|
+ void (* send_cur_line)(ErrorContextCallback *frame);
|
|
+} debugger_language_t;
|
|
|
|
/*
|
|
* errorHandlerCtx
|
|
@@ -26,7 +97,6 @@ extern per_session_ctx_t per_session_ctx;
|
|
* wrap sigjmp_buf's - we have to do that because sigjmp_buf is defined as an
|
|
* array on some platforms (like Win32).
|
|
*/
|
|
-
|
|
typedef struct
|
|
{
|
|
sigjmp_buf m_savepoint;
|
|
@@ -49,22 +119,66 @@ extern errorHandlerCtx client_lost;
|
|
#define PLDBG_DEPOSIT 'd'
|
|
#define PLDBG_RESTART 'r'
|
|
#define PLDBG_STOP 'x'
|
|
+#define PLDBG_DISCONNECT 'C'
|
|
|
|
-typedef struct
|
|
-{
|
|
- void (* initialize)(void);
|
|
- bool (* frame_belongs_to_me)(ErrorContextCallback *frame);
|
|
- void (* send_stack_frame)(ErrorContextCallback *frame);
|
|
- void (* send_vars)(ErrorContextCallback *frame);
|
|
- void (* select_frame)(ErrorContextCallback *frame);
|
|
- void (* print_var)(ErrorContextCallback *frame, const char *var_name, int lineno);
|
|
- bool (* do_deposit)(ErrorContextCallback *frame, const char *var_name,
|
|
- int line_number, const char *value);
|
|
- Oid (* get_func_oid)(ErrorContextCallback *frame);
|
|
- void (* send_cur_line)(ErrorContextCallback *frame);
|
|
-} debugger_language_t;
|
|
+/*****************************************************************************
|
|
+ * for thread pool of openGauss, we use knl_u_pldbg_context to store global var of
|
|
+ * of session-level.
|
|
+ */
|
|
+typedef enum Pldbg_Role {
|
|
+ PLDBG_NONE, // not a pldebugger session.
|
|
+ PLDBG_SERVER, // pldebugger server, be debugged.
|
|
+ PLDBG_CLIENT // pldebugger client, be used to debug server.
|
|
+} Pldbg_Role;
|
|
+
|
|
+typedef struct knl_u_pldbg_client_context {
|
|
+ debugSession* theMostRecentSession; // the most recent session we used
|
|
+ HTAB* my_attached_sessions; // sessions we attached
|
|
+ sessionHandle nextHandleNum; // session id of next handle
|
|
+} knl_u_pldbg_client_context;
|
|
+
|
|
+typedef struct knl_u_pldbg_server_context {
|
|
+ HTAB* breakpoints; // local breakpoints
|
|
+ HTAB* breakCounts; // key and count of local breakpoints
|
|
+ per_session_ctx_t session_debug_info; // session-level debug info
|
|
+} knl_u_pldbg_server_context;
|
|
+
|
|
+typedef struct knl_u_pldbg_context {
|
|
+ Pldbg_Role role;
|
|
+ knl_u_pldbg_client_context* client;
|
|
+ knl_u_pldbg_server_context* server;
|
|
+ void (*shutdown)();
|
|
+ MemoryContext pldbg_sess_cxt;
|
|
+} knl_u_pldbg_context;
|
|
+
|
|
+
|
|
+#define localBreakpoints ((knl_u_pldbg_context*)(u_sess->ext_fdw_ctx[PLDEBUG_TYPE].pldbg_ctx))->server->breakpoints
|
|
+#define localBreakCounts ((knl_u_pldbg_context*)(u_sess->ext_fdw_ctx[PLDEBUG_TYPE].pldbg_ctx))->server->breakCounts
|
|
+#define per_session_ctx ((knl_u_pldbg_context*)(u_sess->ext_fdw_ctx[PLDEBUG_TYPE].pldbg_ctx))->server->session_debug_info
|
|
+#define mostRecentSession ((knl_u_pldbg_context*)(u_sess->ext_fdw_ctx[PLDEBUG_TYPE].pldbg_ctx))->client->theMostRecentSession
|
|
+#define sessionHash ((knl_u_pldbg_context*)(u_sess->ext_fdw_ctx[PLDEBUG_TYPE].pldbg_ctx))->client->my_attached_sessions
|
|
+#define nextHandle ((knl_u_pldbg_context*)(u_sess->ext_fdw_ctx[PLDEBUG_TYPE].pldbg_ctx))->client->nextHandleNum
|
|
+#define PldbgMemoryContext ((knl_u_pldbg_context*)(u_sess->ext_fdw_ctx[PLDEBUG_TYPE].pldbg_ctx))->pldbg_sess_cxt
|
|
+#define IS_PLDEBUGGER_ON (u_sess->ext_fdw_ctx[PLDEBUG_TYPE].pldbg_ctx != NULL)
|
|
+#define IS_PLDEBUGGER_CLIENT (IS_PLDEBUGGER_ON && ((knl_u_pldbg_context*)(u_sess->ext_fdw_ctx[PLDEBUG_TYPE].pldbg_ctx))->client != NULL)
|
|
+#define IS_PLDEBUGGER_SERVER (IS_PLDEBUGGER_ON && ((knl_u_pldbg_context*)(u_sess->ext_fdw_ctx[PLDEBUG_TYPE].pldbg_ctx))->server != NULL)
|
|
+#define MAKESURE_CLIENT_IS_ON \
|
|
+ do { \
|
|
+ if (!IS_PLDEBUGGER_CLIENT) { \
|
|
+ ereport(ERROR, (errcode(ERRCODE_INITIALIZE_FAILED), errmsg("Pldebugger is not active or you are not client now."))); \
|
|
+ } \
|
|
+ } while (0);
|
|
+#define InvalidSessId uint64(-1)
|
|
+#define MY_SESS_ID (IS_THREAD_POOL_WORKER ? u_sess->session_id : t_thrd.proc_cxt.MyProcPid)
|
|
+
|
|
+int LWLockNewTrancheId();
|
|
+void init_pldebugger_role(Pldbg_Role role);
|
|
+void destroy_pldebugger_context();
|
|
+void pldbg_client_shutdown();
|
|
+void pldbg_server_shutdown();
|
|
|
|
/* in plugin_debugger.c */
|
|
+extern void initLocalBreakpoints(void);
|
|
extern void initGlobalBreakpoints(void);
|
|
extern bool plugin_debugger_main_loop(void);
|
|
|
|
@@ -73,6 +187,7 @@ extern bool attach_to_proxy( Breakpoint * breakpoint );
|
|
extern void setBreakpoint( char * command );
|
|
extern void clearBreakpoint( char * command );
|
|
extern bool breakpointsForFunction( Oid funcOid );
|
|
+extern void initSessionHash(void);
|
|
|
|
extern void dbg_send( const char *fmt, ... )
|
|
#ifdef PG_PRINTF_ATTRIBUTE
|
|
@@ -82,8 +197,10 @@ __attribute__((format(PG_PRINTF_ATTRIBUTE, 1, 2)))
|
|
#endif
|
|
;
|
|
extern char * dbg_read_str(void);
|
|
-
|
|
-extern LWLockId getPLDebuggerLock(void);
|
|
+void sendString( debugSession * session, char * src );
|
|
+void closeSession( debugSession * session );
|
|
+void registCallbackInSessExit(void);
|
|
+extern LWLock* getPLDebuggerLock(void);
|
|
|
|
/* in plpgsql_debugger.c */
|
|
extern void plpgsql_debugger_fini(void);
|
|
diff --git a/gpl_dependency/pldebugger/gplsrc/pldebugger_3_0/plpgsql_debugger.cpp b/gpl_dependency/pldebugger/gplsrc/pldebugger_3_0/plpgsql_debugger.cpp
|
|
index df52f01..f753d40 100644
|
|
--- a/gpl_dependency/pldebugger/gplsrc/pldebugger_3_0/plpgsql_debugger.cpp
|
|
+++ b/gpl_dependency/pldebugger/gplsrc/pldebugger_3_0/plpgsql_debugger.cpp
|
|
@@ -24,6 +24,7 @@
|
|
#include "globalbp.h"
|
|
#include "utils/array.h"
|
|
#include "utils/builtins.h"
|
|
+#include "utils/memutils.h"
|
|
#include "utils/syscache.h"
|
|
#include "miscadmin.h"
|
|
|
|
@@ -46,8 +47,7 @@
|
|
* each variable.
|
|
*/
|
|
|
|
-typedef struct
|
|
-{
|
|
+typedef struct var_value {
|
|
bool isnull; /* TRUE -> this variable IS NULL */
|
|
bool visible; /* hidden or visible? see is_visible_datum() */
|
|
bool duplicate_name; /* Is this one of many vars with same name? */
|
|
@@ -63,8 +63,7 @@ typedef struct
|
|
* code and display variable values
|
|
*/
|
|
|
|
-typedef struct
|
|
-{
|
|
+typedef struct dbg_ctx {
|
|
PLpgSQL_function * func; /* Function definition */
|
|
bool stepping; /* If TRUE, stop at next statement */
|
|
var_value * symbols; /* Extra debugger-private info about variables */
|
|
@@ -128,22 +127,153 @@ debugger_language_t plpgsql_debugger_lang =
|
|
plpgsql_send_cur_line
|
|
};
|
|
|
|
-/* Install this module as an PL/pgSQL instrumentation plugin */
|
|
-static void
|
|
-plpgsql_debugger_init(void)
|
|
+/*
|
|
+
|
|
+ * Install this module as an PL/pgSQL instrumentation plugin when database start up;
|
|
+ * Called by: _PG_init
|
|
+ */
|
|
+static void plpgsql_debugger_init(void)
|
|
{
|
|
- PLpgSQL_plugin ** var_ptr = (PLpgSQL_plugin **) find_rendezvous_variable( plugin_name );
|
|
+ PLpgSQL_plugin ** var_ptr = (PLpgSQL_plugin **) find_rendezvous_variable(plugin_name);
|
|
|
|
*var_ptr = &plugin_funcs;
|
|
}
|
|
|
|
|
|
+/*
|
|
+ * Initialize the contents of 'u_sess->ext_fdw_ctx[PLDEBUG_TYPE].pldbg_ctx'
|
|
+ * during the debugger starting process.
|
|
+ */
|
|
+void init_pldebugger_role(Pldbg_Role role)
|
|
+{
|
|
+ if (u_sess->ext_fdw_ctx[PLDEBUG_TYPE].pldbg_ctx != NULL) {
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_INVALID_ROLE_SPECIFICATION), errmsg("You already have an identity. ")));
|
|
+ }
|
|
+
|
|
+ if (t_thrd.role == THREADPOOL_WORKER &&
|
|
+ (u_sess->plsql_cxt.plugin_ptr == NULL || *u_sess->plsql_cxt.plugin_ptr == NULL)) {
|
|
+ process_shared_preload_libraries();
|
|
+ }
|
|
+
|
|
+ MemoryContext pldbg_sess_cxt = AllocSetContextCreate(u_sess->top_mem_cxt, "PldbgSessCxt",
|
|
+ ALLOCSET_SMALL_MINSIZE, ALLOCSET_SMALL_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE);
|
|
+
|
|
+ MemoryContext oldcontext = MemoryContextSwitchTo(pldbg_sess_cxt);
|
|
+ knl_u_pldbg_context* pldbg_cxt = (knl_u_pldbg_context*)palloc(sizeof(knl_u_pldbg_context));
|
|
+
|
|
+ switch (role) {
|
|
+ case PLDBG_CLIENT: {
|
|
+ knl_u_pldbg_client_context* client =
|
|
+ (knl_u_pldbg_client_context*)palloc(sizeof(knl_u_pldbg_client_context));
|
|
+ client->theMostRecentSession = NULL;
|
|
+ client->my_attached_sessions = NULL;
|
|
+ client->nextHandleNum = 1;
|
|
+
|
|
+ pldbg_cxt->server = NULL;
|
|
+ pldbg_cxt->client = client;
|
|
+ pldbg_cxt->role = PLDBG_CLIENT;
|
|
+ pldbg_cxt->pldbg_sess_cxt = pldbg_sess_cxt;
|
|
+ u_sess->ext_fdw_ctx[PLDEBUG_TYPE].pldbg_ctx = (void*)pldbg_cxt;
|
|
+ initSessionHash();
|
|
+ ereport(NOTICE, (errmsg("Pldebugger is started successfully, you are CLIENT now.")));
|
|
+ } break;
|
|
+ case PLDBG_SERVER: {
|
|
+ knl_u_pldbg_server_context* server =
|
|
+ (knl_u_pldbg_server_context*)palloc(sizeof(knl_u_pldbg_server_context));
|
|
+ server->breakpoints = NULL;
|
|
+ server->breakCounts = NULL;
|
|
+ server->session_debug_info.step_into_next_func = false;
|
|
+ server->session_debug_info.client_w = 0;
|
|
+ server->session_debug_info.client_r = 0;
|
|
+
|
|
+ pldbg_cxt->server = server;
|
|
+ pldbg_cxt->client = NULL;
|
|
+ pldbg_cxt->role = PLDBG_SERVER;
|
|
+ pldbg_cxt->pldbg_sess_cxt = pldbg_sess_cxt;
|
|
+ u_sess->ext_fdw_ctx[PLDEBUG_TYPE].pldbg_ctx = (void*)pldbg_cxt;
|
|
+
|
|
+ /* now we can init some pointers */
|
|
+ initLocalBreakpoints();
|
|
+ ereport(NOTICE, (errmsg("Pldebugger is started successfully, you are SERVER now.")));
|
|
+ } break;
|
|
+ default: {
|
|
+ MemoryContextSwitchTo(oldcontext);
|
|
+ ereport(ERROR,
|
|
+ (errcode(ERRCODE_INVALID_ROLE_SPECIFICATION), errmsg("invalid pldebugger role.")));
|
|
+ }
|
|
+ }
|
|
+ MemoryContextSwitchTo(oldcontext);
|
|
+
|
|
+ // when session exits, call 'pldbg_off()'.
|
|
+ registCallbackInSessExit();
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Destroy pldebugger context when the current session exits
|
|
+ */
|
|
+void destroy_pldebugger_context()
|
|
+{
|
|
+ MemoryContextDelete(PldbgMemoryContext);
|
|
+ PldbgMemoryContext = NULL;
|
|
+ u_sess->ext_fdw_ctx[PLDEBUG_TYPE].pldbg_ctx = NULL;
|
|
+ u_sess->ext_fdw_ctx[PLDEBUG_TYPE].fdwExitFunc = NULL;
|
|
+}
|
|
+void pldbg_client_shutdown()
|
|
+{
|
|
+#define PLDBGAPI_DISCONNECT "C\n"
|
|
+ // free all sessions
|
|
+ HASH_SEQ_STATUS scan;
|
|
+ sessionHashEntry* session = NULL;
|
|
+ if (sessionHash != NULL) {
|
|
+ hash_seq_init(&scan, sessionHash);
|
|
+ while((session = (sessionHashEntry*)hash_seq_search(&scan)) != NULL){
|
|
+ sendString(session->m_session, PLDBGAPI_DISCONNECT);
|
|
+ closeSession(session->m_session);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+/*
|
|
+ * shut down the server when do pldbg_off()
|
|
+ */
|
|
+void pldbg_server_shutdown()
|
|
+{
|
|
+ /* server just on before and do not have a client. */
|
|
+ if (per_session_ctx.client_r == 0)
|
|
+ return;
|
|
+
|
|
+ /* client mabey down before, we must test it first. */
|
|
+ bool client_is_off = false;
|
|
+ fd_set fds;
|
|
+ struct timeval timeout={1,0};
|
|
+
|
|
+ FD_ZERO(&fds);
|
|
+ FD_SET(per_session_ctx.client_r, &fds);
|
|
+ switch (select(per_session_ctx.client_r + 1, &fds, NULL, NULL, &timeout)) {
|
|
+ case -1:
|
|
+ ereport(ERROR, (errmsg("select() failed while waiting for target")));
|
|
+ case 0:
|
|
+ client_is_off = false;
|
|
+ break;
|
|
+ default: /* there is something in socket, mabey shutdown message of client or other command. */
|
|
+ if (FD_ISSET(per_session_ctx.client_r, &fds)) {
|
|
+ char* cmd = dbg_read_str();
|
|
+ if (cmd[0] == PLDBG_DISCONNECT)
|
|
+ client_is_off = true;
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+ if (!client_is_off)
|
|
+ dbg_send(" :%s: ", " ");
|
|
+ per_session_ctx.client_r = 0;
|
|
+ per_session_ctx.client_w = 0;
|
|
+}
|
|
+
|
|
/**********************************************************************
|
|
* Functions implemeting the pldebugger_language_t interface
|
|
**********************************************************************/
|
|
|
|
-static bool
|
|
-plpgsql_frame_belongs_to_me(ErrorContextCallback *frame)
|
|
+static bool plpgsql_frame_belongs_to_me(ErrorContextCallback* frame)
|
|
{
|
|
return (frame->callback == plugin_funcs.error_callback);
|
|
}
|
|
@@ -156,8 +286,7 @@ plpgsql_frame_belongs_to_me(ErrorContextCallback *frame)
|
|
* finds a PL/pgSQL call in the stack (remember, the call stack may contain
|
|
* stack frames for functions written in other languages like PL/Tcl).
|
|
*/
|
|
-static void
|
|
-plpgsql_send_stack_frame(ErrorContextCallback *frame)
|
|
+static void plpgsql_send_stack_frame(ErrorContextCallback* frame)
|
|
{
|
|
PLpgSQL_execstate *estate = (PLpgSQL_execstate *) frame->arg;
|
|
#if (PG_VERSION_NUM >= 80500)
|
|
@@ -189,8 +318,7 @@ plpgsql_send_stack_frame(ErrorContextCallback *frame)
|
|
* Now assemble a string that shows the argument names and value for this frame
|
|
*/
|
|
|
|
- for( arg = 0; arg < func->fn_nargs; ++arg )
|
|
- {
|
|
+ for (arg = 0; arg < func->fn_nargs; ++arg) {
|
|
int index = func->fn_argvarnos[arg];
|
|
PLpgSQL_datum *argDatum = (PLpgSQL_datum *)estate->datums[index];
|
|
char *value;
|
|
@@ -273,35 +401,9 @@ plpgsql_send_vars(ErrorContextCallback *frame)
|
|
var->notnull ? 't':'f',
|
|
var->datatype ? var->datatype->typoid : InvalidOid,
|
|
val );
|
|
-
|
|
- break;
|
|
- }
|
|
-#if 0
|
|
- FIXME: implement other types
|
|
-
|
|
- case PLPGSQL_DTYPE_REC:
|
|
- {
|
|
- PLpgSQL_rec * rec = (PLpgSQL_rec *) estate->datums[i];
|
|
- int att;
|
|
- char * typeName;
|
|
|
|
- if (rec->tupdesc != NULL)
|
|
- {
|
|
- for( att = 0; att < rec->tupdesc->natts; ++att )
|
|
- {
|
|
- typeName = SPI_gettype( rec->tupdesc, att + 1 );
|
|
-
|
|
- dbg_send( "o:%s.%s:%d:%d:%d:%d:%s\n",
|
|
- rec->refname, NameStr( rec->tupdesc->attrs[att]->attname ),
|
|
- 0, rec->lineno, 0, rec->tupdesc->attrs[att]->attnotnull, typeName ? typeName : "" );
|
|
-
|
|
- if( typeName )
|
|
- pfree( typeName );
|
|
- }
|
|
- }
|
|
break;
|
|
}
|
|
-#endif
|
|
}
|
|
}
|
|
}
|
|
@@ -549,7 +651,9 @@ static void print_var( const PLpgSQL_execstate * frame, const char * var_name, i
|
|
|
|
fmgr_info( typeStruct->typoutput, &finfo_output );
|
|
|
|
- extval = DatumGetCString( FunctionCall3( &finfo_output, tgt->value, ObjectIdGetDatum(typeStruct->typelem), Int32GetDatum(-1)));
|
|
+ extval = DatumGetCString(FunctionCall3(&finfo_output, tgt->value,
|
|
+ ObjectIdGetDatum(typeStruct->typelem),
|
|
+ Int32GetDatum(-1)));
|
|
|
|
/* Send the name:value to the debugger client */
|
|
|
|
@@ -586,10 +690,10 @@ static void print_rec( const PLpgSQL_execstate * frame, const char * var_name, i
|
|
}
|
|
}
|
|
|
|
-static void print_recfield( const PLpgSQL_execstate * frame, const char * var_name, int lineno, const PLpgSQL_recfield * tgt )
|
|
+static void print_recfield(const PLpgSQL_execstate* frame, const char* var_name,
|
|
+ int lineno, const PLpgSQL_recfield* tgt)
|
|
{
|
|
-
|
|
-
|
|
+ return;
|
|
}
|
|
|
|
static void
|
|
@@ -837,7 +941,7 @@ plpgsql_get_func_oid(ErrorContextCallback *frame)
|
|
|
|
static void dbg_startup( PLpgSQL_execstate * estate, PLpgSQL_function * func )
|
|
{
|
|
- if( func == NULL )
|
|
+ if( func == NULL || !IS_PLDEBUGGER_SERVER)
|
|
{
|
|
/*
|
|
* In general, this should never happen, but it seems to in the
|
|
@@ -943,13 +1047,14 @@ static void initialize_plugin_info( PLpgSQL_execstate * estate,
|
|
static bool plpgsql_do_deposit(ErrorContextCallback *frame, const char *var_name, int lineno, const char *value)
|
|
{
|
|
PLpgSQL_execstate *estate = (PLpgSQL_execstate *) frame->arg;
|
|
- dbg_ctx *dbg_info = estate->plugin_info;
|
|
+ dbg_ctx *dbg_info = (dbg_ctx*)estate->plugin_info;
|
|
PLpgSQL_datum *target;
|
|
char *select;
|
|
PLpgSQL_expr *expr;
|
|
MemoryContext curContext = CurrentMemoryContext;
|
|
- ResourceOwner curOwner = CurrentResourceOwner;
|
|
+ ResourceOwner curOwner = t_thrd.utils_cxt.CurrentResourceOwner;
|
|
bool retval = false;
|
|
+ errno_t rc = 0;
|
|
|
|
target = find_datum_by_name(estate, var_name, lineno, NULL);
|
|
if (!target)
|
|
@@ -962,9 +1067,10 @@ static bool plpgsql_do_deposit(ErrorContextCallback *frame, const char *var_name
|
|
* need to later (see the retry logic below)
|
|
*/
|
|
|
|
- select = palloc( strlen( "SELECT " ) + strlen( value ) + 2 + 1 );
|
|
+ select = (char*)palloc( strlen( "SELECT " ) + strlen( value ) + 2 + 1 );
|
|
|
|
- sprintf( select, "SELECT %s", value );
|
|
+ rc = sprintf_s(select, strlen("SELECT ") + strlen(value) + 2 + 1, "SELECT %s", value);
|
|
+ securec_check_ss_c(rc, "\0", "\0");
|
|
|
|
/*
|
|
* Note: we must create a dynamically allocated PLpgSQL_expr here - we
|
|
@@ -998,7 +1104,7 @@ static bool plpgsql_do_deposit(ErrorContextCallback *frame, const char *var_name
|
|
/* Commit the inner transaction, return to outer xact context */
|
|
ReleaseCurrentSubTransaction();
|
|
MemoryContextSwitchTo( curContext );
|
|
- CurrentResourceOwner = curOwner;
|
|
+ t_thrd.utils_cxt.CurrentResourceOwner = curOwner;
|
|
|
|
SPI_restore_connection();
|
|
|
|
@@ -1014,7 +1120,7 @@ static bool plpgsql_do_deposit(ErrorContextCallback *frame, const char *var_name
|
|
/* Abort the inner transaction */
|
|
RollbackAndReleaseCurrentSubTransaction();
|
|
MemoryContextSwitchTo( curContext );
|
|
- CurrentResourceOwner = curOwner;
|
|
+ t_thrd.utils_cxt.CurrentResourceOwner = curOwner;
|
|
|
|
SPI_restore_connection();
|
|
|
|
@@ -1030,7 +1136,8 @@ static bool plpgsql_do_deposit(ErrorContextCallback *frame, const char *var_name
|
|
|
|
if (!retval)
|
|
{
|
|
- sprintf( select, "SELECT '%s'", value );
|
|
+ rc = sprintf_s(select, strlen("SELECT ") + strlen(value) + 2 + 1, "SELECT '%s'", value);
|
|
+ securec_check_ss_c(rc, "\0", "\0");
|
|
|
|
expr->dtype = PLPGSQL_DTYPE_EXPR;
|
|
expr->dno = -1;
|
|
@@ -1054,7 +1161,7 @@ static bool plpgsql_do_deposit(ErrorContextCallback *frame, const char *var_name
|
|
/* Commit the inner transaction, return to outer xact context */
|
|
ReleaseCurrentSubTransaction();
|
|
MemoryContextSwitchTo( curContext );
|
|
- CurrentResourceOwner = curOwner;
|
|
+ t_thrd.utils_cxt.CurrentResourceOwner = curOwner;
|
|
|
|
SPI_restore_connection();
|
|
|
|
@@ -1069,7 +1176,7 @@ static bool plpgsql_do_deposit(ErrorContextCallback *frame, const char *var_name
|
|
/* Abort the inner transaction */
|
|
RollbackAndReleaseCurrentSubTransaction();
|
|
MemoryContextSwitchTo( curContext );
|
|
- CurrentResourceOwner = curOwner;
|
|
+ t_thrd.utils_cxt.CurrentResourceOwner = curOwner;
|
|
|
|
SPI_restore_connection();
|
|
|
|
@@ -1119,7 +1226,7 @@ static bool is_datum_visible( PLpgSQL_datum * datum )
|
|
PLpgSQL_var * var = (PLpgSQL_var *)datum;
|
|
int i;
|
|
|
|
- for( i = 0; i < sizeof( hidden_variables ) / sizeof( hidden_variables[0] ); ++i )
|
|
+ for( i = 0; i < (int)(sizeof( hidden_variables ) / sizeof( hidden_variables[0] )); ++i )
|
|
{
|
|
if( strcmp( var->refname, hidden_variables[i] ) == 0 )
|
|
{
|
|
@@ -1200,7 +1307,7 @@ plpgsql_send_cur_line(ErrorContextCallback *frame)
|
|
|
|
dbg_send( "%d:%d:%s",
|
|
func->fn_oid,
|
|
- stmt->lineno+1,
|
|
+ stmt->lineno,
|
|
#if (PG_VERSION_NUM >= 90200)
|
|
func->fn_signature
|
|
#else
|
|
@@ -1244,132 +1351,126 @@ static bool isFirstStmt( PLpgSQL_stmt * stmt, PLpgSQL_function * func )
|
|
|
|
static void dbg_newstmt( PLpgSQL_execstate * estate, PLpgSQL_stmt * stmt )
|
|
{
|
|
- PLpgSQL_execstate * frame = estate;
|
|
-
|
|
/*
|
|
- * If there's no debugger attached, go home as quickly as possible.
|
|
+ * If there's no debugger attached or pldebugger is off, go home as quickly as possible.
|
|
*/
|
|
- if( frame->plugin_info == NULL )
|
|
+ if( !IS_PLDEBUGGER_SERVER || estate->plugin_info == NULL)
|
|
return;
|
|
- else
|
|
- {
|
|
- dbg_ctx * dbg_info = (dbg_ctx *)frame->plugin_info;
|
|
- Breakpoint * breakpoint = NULL;
|
|
- eBreakpointScope breakpointScope = 0;
|
|
+
|
|
+ PLpgSQL_execstate * frame = estate;
|
|
+ dbg_ctx * dbg_info = (dbg_ctx *)frame->plugin_info;
|
|
+ Breakpoint * breakpoint = NULL;
|
|
+ eBreakpointScope breakpointScope = (BP_LOCAL);
|
|
|
|
- /*
|
|
- * The PL compiler marks certain statements as 'invisible' to the
|
|
- * debugger. In particular, the compiler may generate statements
|
|
- * that do not appear in the source code. Such a statement is
|
|
- * marked with a line number of -1: if we're looking at an invisible
|
|
- * statement, just return to the caller.
|
|
- */
|
|
+ /*
|
|
+ * The PL compiler marks certain statements as 'invisible' to the
|
|
+ * debugger. In particular, the compiler may generate statements
|
|
+ * that do not appear in the source code. Such a statement is
|
|
+ * marked with a line number of -1: if we're looking at an invisible
|
|
+ * statement, just return to the caller.
|
|
+ */
|
|
|
|
- if( stmt->lineno == -1 )
|
|
- return;
|
|
+ if( stmt->lineno == -1 )
|
|
+ return;
|
|
|
|
+ /*
|
|
+ * Now set up an error handler context so we can intercept any
|
|
+ * networking errors (errors communicating with the proxy).
|
|
+ */
|
|
+ if( sigsetjmp( client_lost.m_savepoint, 1 ) != 0 )
|
|
+ {
|
|
/*
|
|
- * Now set up an error handler context so we can intercept any
|
|
- * networking errors (errors communicating with the proxy).
|
|
+ * The connection to the debugger client has slammed shut -
|
|
+ * just pretend like there's no debugger attached and return
|
|
+ *
|
|
+ * NOTE: we no longer have a connection to the debugger proxy -
|
|
+ * that means that we cannot interact with the proxy, we
|
|
+ * can't wait for another command, nothing. We let the
|
|
+ * executor continue execution - anything else will hang
|
|
+ * this backend, waiting for a debugger command that will
|
|
+ * never arrive.
|
|
+ *
|
|
+ * If, however, we hit a breakpoint again, we'll stop and
|
|
+ * wait for another debugger proxy to connect to us. If
|
|
+ * that's not the behavior you're looking for, you can
|
|
+ * drop the breakpoint, or call free_function_breakpoints()
|
|
+ * here to get rid of all breakpoints in this backend.
|
|
*/
|
|
+ per_session_ctx.client_w = 0; /* No client connection */
|
|
+ dbg_info->stepping = FALSE; /* No longer stepping */
|
|
+ }
|
|
|
|
- if( sigsetjmp( client_lost.m_savepoint, 1 ) != 0 )
|
|
- {
|
|
- /*
|
|
- * The connection to the debugger client has slammed shut -
|
|
- * just pretend like there's no debugger attached and return
|
|
- *
|
|
- * NOTE: we no longer have a connection to the debugger proxy -
|
|
- * that means that we cannot interact with the proxy, we
|
|
- * can't wait for another command, nothing. We let the
|
|
- * executor continue execution - anything else will hang
|
|
- * this backend, waiting for a debugger command that will
|
|
- * never arrive.
|
|
- *
|
|
- * If, however, we hit a breakpoint again, we'll stop and
|
|
- * wait for another debugger proxy to connect to us. If
|
|
- * that's not the behavior you're looking for, you can
|
|
- * drop the breakpoint, or call free_function_breakpoints()
|
|
- * here to get rid of all breakpoints in this backend.
|
|
- */
|
|
- per_session_ctx.client_w = 0; /* No client connection */
|
|
- dbg_info->stepping = FALSE; /* No longer stepping */
|
|
- }
|
|
-
|
|
- if(( dbg_info->stepping ) || breakAtThisLine( &breakpoint, &breakpointScope, dbg_info->func->fn_oid, isFirstStmt( stmt, dbg_info->func ) ? -1 : stmt->lineno ))
|
|
- dbg_info->stepping = TRUE;
|
|
- else
|
|
- return;
|
|
-
|
|
- per_session_ctx.step_into_next_func = FALSE;
|
|
+ if ((dbg_info->stepping) ||
|
|
+ breakAtThisLine(&breakpoint, &breakpointScope, dbg_info->func->fn_oid,
|
|
+ isFirstStmt(stmt, dbg_info->func) ? -1 : stmt->lineno))
|
|
+ dbg_info->stepping = TRUE;
|
|
+ else
|
|
+ return;
|
|
|
|
- /* We found a breakpoint for this function (or we're stepping into) */
|
|
- /* Make contact with the debugger client */
|
|
+ per_session_ctx.step_into_next_func = FALSE;
|
|
+ /* We found a breakpoint for this function (or we're stepping into) */
|
|
+ /* Make contact with the debugger client */
|
|
+ if( !attach_to_proxy( breakpoint ))
|
|
+ {
|
|
+ /*
|
|
+ * Can't attach to the proxy, maybe we found a stale breakpoint?
|
|
+ * That can happen if you set a global breakpoint on a function,
|
|
+ * invoke that function from a client application, debug the target
|
|
+ * kill the debugger client, and then re-invoke the function from
|
|
+ * the same client application - we will find the stale global
|
|
+ * breakpoint on the second invocation.
|
|
+ *
|
|
+ * We want to remove that breakpoint so that we don't keep trying
|
|
+ * to attach to a phantom proxy process.
|
|
+ */
|
|
+ if( breakpoint )
|
|
+ BreakpointDelete( breakpointScope, &(breakpoint->key));
|
|
|
|
- if( !attach_to_proxy( breakpoint ))
|
|
- {
|
|
- /*
|
|
- * Can't attach to the proxy, maybe we found a stale breakpoint?
|
|
- * That can happen if you set a global breakpoint on a function,
|
|
- * invoke that function from a client application, debug the target
|
|
- * kill the debugger client, and then re-invoke the function from
|
|
- * the same client application - we will find the stale global
|
|
- * breakpoint on the second invocation.
|
|
- *
|
|
- * We want to remove that breakpoint so that we don't keep trying
|
|
- * to attach to a phantom proxy process.
|
|
- */
|
|
- if( breakpoint )
|
|
- BreakpointDelete( breakpointScope, &(breakpoint->key));
|
|
+ /*
|
|
+ * In any case, if we don't have a proxy to work with, we can't
|
|
+ * do any debugging so give up.
|
|
+ */
|
|
+ pfree( frame->plugin_info );
|
|
+ frame->plugin_info = NULL; /* No debugger context */
|
|
+ per_session_ctx.client_w = 0; /* No client connection */
|
|
|
|
- /*
|
|
- * In any case, if we don't have a proxy to work with, we can't
|
|
- * do any debugging so give up.
|
|
- */
|
|
- pfree( frame->plugin_info );
|
|
- frame->plugin_info = NULL; /* No debugger context */
|
|
- per_session_ctx.client_w = 0; /* No client connection */
|
|
+ return;
|
|
+ }
|
|
|
|
- return;
|
|
- }
|
|
+ if( stmt->cmd_type == PLPGSQL_STMT_BLOCK )
|
|
+ return;
|
|
|
|
- if( stmt->cmd_type == PLPGSQL_STMT_BLOCK )
|
|
- return;
|
|
+ /*
|
|
+ * The PL/pgSQL compiler inserts an automatic RETURN statement at the
|
|
+ * end of each function (unless the last statement in the function is
|
|
+ * already a RETURN). If we run into that statement, we don't really
|
|
+ * want to wait for the user to STEP across it. Remember, the user won't
|
|
+ * see the RETURN statement in the source-code listing for his function.
|
|
+ *
|
|
+ * Fortunately, the automatic RETURN statement has a line-number of 0
|
|
+ * so it's easy to spot.
|
|
+ */
|
|
+ if( stmt->lineno == 0 )
|
|
+ return;
|
|
|
|
+ /*
|
|
+ * If we're in step mode, tell the debugger client, read a command from the client and
|
|
+ * execute the command
|
|
+ */
|
|
+ if( dbg_info->stepping )
|
|
+ {
|
|
/*
|
|
- * The PL/pgSQL compiler inserts an automatic RETURN statement at the
|
|
- * end of each function (unless the last statement in the function is
|
|
- * already a RETURN). If we run into that statement, we don't really
|
|
- * want to wait for the user to STEP across it. Remember, the user won't
|
|
- * see the RETURN statement in the source-code listing for his function.
|
|
- *
|
|
- * Fortunately, the automatic RETURN statement has a line-number of 0
|
|
- * so it's easy to spot.
|
|
+ * Make sure that we have all of the debug info that we need in this stack frame
|
|
*/
|
|
- if( stmt->lineno == 0 )
|
|
- return;
|
|
-
|
|
- /*
|
|
- * If we're in step mode, tell the debugger client, read a command from the client and
|
|
- * execute the command
|
|
+ completeFrame( frame );
|
|
+ /*
|
|
+ * We're in single-step mode (or at a breakpoint)
|
|
+ * send the current line number to the debugger client and report any
|
|
+ * variable modifications
|
|
*/
|
|
|
|
- if( dbg_info->stepping )
|
|
- {
|
|
- /*
|
|
- * Make sure that we have all of the debug info that we need in this stack frame
|
|
- */
|
|
- completeFrame( frame );
|
|
-
|
|
- /*
|
|
- * We're in single-step mode (or at a breakpoint)
|
|
- * send the current line number to the debugger client and report any
|
|
- * variable modifications
|
|
- */
|
|
-
|
|
- if (!plugin_debugger_main_loop())
|
|
- dbg_info->stepping = FALSE;
|
|
- }
|
|
+ if (!plugin_debugger_main_loop())
|
|
+ dbg_info->stepping = FALSE;
|
|
}
|
|
|
|
return;
|
|
diff --git a/gpl_dependency/pldebugger/gplsrc/pldebugger_3_0/plugin_debugger.cpp b/gpl_dependency/pldebugger/gplsrc/pldebugger_3_0/plugin_debugger.cpp
|
|
index 4f5f9b0..1aa33f7 100644
|
|
--- a/gpl_dependency/pldebugger/gplsrc/pldebugger_3_0/plugin_debugger.cpp
|
|
+++ b/gpl_dependency/pldebugger/gplsrc/pldebugger_3_0/plugin_debugger.cpp
|
|
@@ -33,7 +33,7 @@
|
|
#include "parser/parser.h"
|
|
#include "parser/parse_func.h"
|
|
#include "globalbp.h"
|
|
-#include "storage/proc.h" /* For MyProc */
|
|
+#include "storage/proc.h" /* For MyProc */
|
|
#include "storage/procarray.h" /* For BackendPidGetProc */
|
|
#include "utils/array.h"
|
|
#include "utils/builtins.h"
|
|
@@ -86,11 +86,11 @@ typedef enum
|
|
/* Global breakpoint data. */
|
|
typedef struct
|
|
{
|
|
-#if (PG_VERSION_NUM >= 90600)
|
|
- int tranche_id;
|
|
+#if (PG_VERSION_NUM >= 90204)
|
|
+ int tranche_id;
|
|
LWLock lock;
|
|
#else
|
|
- LWLockId lockid;
|
|
+ LWLockId lockid;
|
|
#endif
|
|
} GlobalBreakpointData;
|
|
|
|
@@ -98,9 +98,6 @@ typedef struct
|
|
* Local (static) variables
|
|
**********************************************************************/
|
|
|
|
-
|
|
-per_session_ctx_t per_session_ctx;
|
|
-
|
|
errorHandlerCtx client_lost;
|
|
|
|
static debugger_language_t *debugger_languages[] = {
|
|
@@ -115,13 +112,11 @@ static debugger_language_t *debugger_languages[] = {
|
|
* Function declarations
|
|
**********************************************************************/
|
|
|
|
-void _PG_init( void ); /* initialize this module when we are dynamically loaded */
|
|
+extern "C" void _PG_init( void ); /* initialize this module when we are dynamically loaded */
|
|
|
|
/**********************************************************************
|
|
* Local (hidden) function prototypes
|
|
**********************************************************************/
|
|
-
|
|
-//static char ** fetchArgNames( PLpgSQL_function * func, int * nameCount );
|
|
static void * writen( int peer, void * src, size_t len );
|
|
static bool connectAsServer( void );
|
|
static bool connectAsClient( Breakpoint * breakpoint );
|
|
@@ -159,11 +154,14 @@ void _PG_init( void )
|
|
* CREATE OR REPLACE FUNCTION pldbg_oid_debug( functionOID OID ) RETURNS INTEGER AS 'pldbg_oid_debug' LANGUAGE C;
|
|
*/
|
|
|
|
-Datum pldbg_oid_debug(PG_FUNCTION_ARGS);
|
|
+extern "C" Datum pldbg_oid_debug(PG_FUNCTION_ARGS);
|
|
PG_FUNCTION_INFO_V1(pldbg_oid_debug);
|
|
|
|
Datum pldbg_oid_debug(PG_FUNCTION_ARGS)
|
|
{
|
|
+ if (!IS_PLDEBUGGER_SERVER) {
|
|
+ init_pldebugger_role(PLDBG_SERVER);
|
|
+ }
|
|
Oid funcOid;
|
|
HeapTuple tuple;
|
|
Oid userid;
|
|
@@ -256,7 +254,7 @@ char *dbg_read_str( void )
|
|
|
|
len = readUInt32( sock );
|
|
|
|
- dst = palloc(len + 1);
|
|
+ dst = (char*)palloc(len + 1);
|
|
readn( sock, dst, len );
|
|
|
|
dst[len] = '\0';
|
|
@@ -625,11 +623,13 @@ static bool parseBreakpoint( Oid * funcOID, int * lineNumber, char * breakpointS
|
|
static bool addLocalBreakpoint( Oid funcOID, int lineNo )
|
|
{
|
|
Breakpoint breakpoint;
|
|
+ errno_t rc = memset_s(&breakpoint.key, sizeof(BreakpointKey), 0, sizeof(BreakpointKey));
|
|
+ securec_check(rc, "", "");
|
|
|
|
- breakpoint.key.databaseId = MyProc->databaseId;
|
|
+ breakpoint.key.databaseId = t_thrd.proc->databaseId;
|
|
breakpoint.key.functionId = funcOID;
|
|
breakpoint.key.lineNumber = lineNo;
|
|
- breakpoint.key.targetPid = MyProc->pid;
|
|
+ breakpoint.key.targetSessId = MY_SESS_ID;
|
|
breakpoint.data.isTmp = FALSE;
|
|
breakpoint.data.proxyPort = -1;
|
|
breakpoint.data.proxyPid = -1;
|
|
@@ -691,11 +691,13 @@ void clearBreakpoint( char * command )
|
|
if( parseBreakpoint( &funcOID, &lineNo, command + 2 ))
|
|
{
|
|
Breakpoint breakpoint;
|
|
+ errno_t rc = memset_s(&breakpoint.key, sizeof(BreakpointKey), 0, sizeof(BreakpointKey));
|
|
+ securec_check(rc, "", "");
|
|
|
|
- breakpoint.key.databaseId = MyProc->databaseId;
|
|
+ breakpoint.key.databaseId = t_thrd.proc->databaseId;
|
|
breakpoint.key.functionId = funcOID;
|
|
breakpoint.key.lineNumber = lineNo;
|
|
- breakpoint.key.targetPid = MyProc->pid;
|
|
+ breakpoint.key.targetSessId = MY_SESS_ID;
|
|
|
|
if( BreakpointDelete( BP_LOCAL, &breakpoint.key ))
|
|
dbg_send( "t" );
|
|
@@ -711,8 +713,10 @@ void clearBreakpoint( char * command )
|
|
bool breakAtThisLine( Breakpoint ** dst, eBreakpointScope * scope, Oid funcOid, int lineNumber )
|
|
{
|
|
BreakpointKey key;
|
|
+ errno_t rc = memset_s(&key, sizeof(BreakpointKey), 0, sizeof(BreakpointKey));
|
|
+ securec_check(rc, "", "");
|
|
|
|
- key.databaseId = MyProc->databaseId;
|
|
+ key.databaseId = t_thrd.proc->databaseId;
|
|
key.functionId = funcOid;
|
|
key.lineNumber = lineNumber;
|
|
|
|
@@ -723,48 +727,7 @@ bool breakAtThisLine( Breakpoint ** dst, eBreakpointScope * scope, Oid funcOid,
|
|
return( TRUE );
|
|
}
|
|
|
|
- /*
|
|
- * We conduct 3 searches here.
|
|
- *
|
|
- * First, we look for a global breakpoint at this line, targeting our
|
|
- * specific backend process.
|
|
- *
|
|
- * Next, we look for a global breakpoint (at this line) that does
|
|
- * not target a specific backend process.
|
|
- *
|
|
- * Finally, we look for a local breakpoint at this line (implicitly
|
|
- * targeting our specific backend process).
|
|
- *
|
|
- * NOTE: We must do the local-breakpoint search last because, when the
|
|
- * proxy attaches to our process, it marks all of its global
|
|
- * breakpoints as busy (so other potential targets will ignore
|
|
- * those breakpoints) and we copy all of those global breakpoints
|
|
- * into our local breakpoint hash. If the debugger client exits
|
|
- * and the user starts another debugger session, we want to see the
|
|
- * new breakpoints instead of our obsolete local breakpoints (we
|
|
- * don't have a good way to detect that the proxy has disconnected
|
|
- * until it's inconvenient - we have to read-from or write-to the
|
|
- * proxy before we can tell that it's died).
|
|
- */
|
|
-
|
|
- key.targetPid = MyProc->pid; /* Search for a global breakpoint targeted at our process ID */
|
|
-
|
|
- if((( *dst = BreakpointLookup( BP_GLOBAL, &key )) != NULL ) && ((*dst)->data.busy == FALSE ))
|
|
- {
|
|
- *scope = BP_GLOBAL;
|
|
- return( TRUE );
|
|
- }
|
|
-
|
|
- key.targetPid = -1; /* Search for a global breakpoint targeted at any process ID */
|
|
-
|
|
- if((( *dst = BreakpointLookup( BP_GLOBAL, &key )) != NULL ) && ((*dst)->data.busy == FALSE ))
|
|
- {
|
|
- *scope = BP_GLOBAL;
|
|
- return( TRUE );
|
|
- }
|
|
-
|
|
- key.targetPid = MyProc->pid; /* Search for a local breakpoint (targeted at our process ID) */
|
|
-
|
|
+ key.targetSessId = MY_SESS_ID; /* Search for a local breakpoint (targeted at our process ID) */
|
|
if(( *dst = BreakpointLookup( BP_LOCAL, &key )) != NULL )
|
|
{
|
|
*scope = BP_LOCAL;
|
|
@@ -776,7 +739,7 @@ bool breakAtThisLine( Breakpoint ** dst, eBreakpointScope * scope, Oid funcOid,
|
|
|
|
bool breakpointsForFunction( Oid funcOid )
|
|
{
|
|
- if( BreakpointOnId( BP_LOCAL, funcOid ) || BreakpointOnId( BP_GLOBAL, funcOid ))
|
|
+ if(BreakpointOnId( BP_LOCAL, funcOid ))
|
|
return( TRUE );
|
|
else
|
|
return( FALSE );
|
|
@@ -939,7 +902,7 @@ plugin_debugger_main_loop(void)
|
|
|
|
/* Initially, set focus on the topmost frame in the stack */
|
|
|
|
- for( frame = error_context_stack; frame; frame = frame->previous )
|
|
+ for( frame = t_thrd.log_cxt.error_context_stack; frame; frame = frame->previous )
|
|
{
|
|
/*
|
|
* ignore unrecognized stack frames.
|
|
@@ -1076,7 +1039,14 @@ plugin_debugger_main_loop(void)
|
|
lang->send_vars( frame );
|
|
break;
|
|
}
|
|
-
|
|
+ case PLDBG_DISCONNECT:
|
|
+ {
|
|
+ closesocket(per_session_ctx.client_r);
|
|
+ per_session_ctx.client_r = per_session_ctx.client_w = 0;
|
|
+ connectAsServer();
|
|
+ lang->send_cur_line(frame);
|
|
+ break;
|
|
+ }
|
|
case PLDBG_RESTART:
|
|
case PLDBG_STOP:
|
|
{
|
|
@@ -1157,24 +1127,12 @@ send_breakpoints(Oid funcOid)
|
|
Breakpoint * breakpoint;
|
|
HASH_SEQ_STATUS scan;
|
|
|
|
- BreakpointGetList( BP_GLOBAL, &scan );
|
|
-
|
|
- while(( breakpoint = (Breakpoint *) hash_seq_search( &scan )) != NULL )
|
|
- {
|
|
- if(( breakpoint->key.targetPid == -1 ) || ( breakpoint->key.targetPid == MyProc->pid ))
|
|
- if( breakpoint->key.databaseId == MyProc->databaseId )
|
|
- if( breakpoint->key.functionId == funcOid )
|
|
- dbg_send( "%d:%d:%s", funcOid, breakpoint->key.lineNumber, "" );
|
|
- }
|
|
-
|
|
- BreakpointReleaseList( BP_GLOBAL );
|
|
-
|
|
BreakpointGetList( BP_LOCAL, &scan );
|
|
|
|
while(( breakpoint = (Breakpoint *) hash_seq_search( &scan )) != NULL )
|
|
{
|
|
- if(( breakpoint->key.targetPid == -1 ) || ( breakpoint->key.targetPid == MyProc->pid ))
|
|
- if( breakpoint->key.databaseId == MyProc->databaseId )
|
|
+ if ((breakpoint->key.targetSessId == InvalidSessId) || (breakpoint->key.targetSessId == MY_SESS_ID))
|
|
+ if( breakpoint->key.databaseId == t_thrd.proc->databaseId )
|
|
if( breakpoint->key.functionId == funcOid )
|
|
dbg_send( "%d:%d:%s", funcOid, breakpoint->key.lineNumber, "" );
|
|
}
|
|
@@ -1206,7 +1164,7 @@ select_frame(int frameNo, ErrorContextCallback **frame_p, debugger_language_t **
|
|
{
|
|
ErrorContextCallback *frame;
|
|
|
|
- for( frame = error_context_stack; frame; frame = frame->previous )
|
|
+ for( frame = t_thrd.log_cxt.error_context_stack; frame; frame = frame->previous )
|
|
{
|
|
debugger_language_t *lang = language_of_frame(frame);
|
|
if (!lang)
|
|
@@ -1256,7 +1214,7 @@ send_stack( void )
|
|
{
|
|
ErrorContextCallback * entry;
|
|
|
|
- for( entry = error_context_stack; entry; entry = entry->previous )
|
|
+ for( entry = t_thrd.log_cxt.error_context_stack; entry; entry = entry->previous )
|
|
{
|
|
/*
|
|
* ignore frames we don't recognize
|
|
@@ -1273,32 +1231,22 @@ send_stack( void )
|
|
|
|
|
|
/*-------------------------------------------------------------------------------------
|
|
- * The shared hash table for global breakpoints. It is protected by
|
|
- * breakpointLock
|
|
- *-------------------------------------------------------------------------------------
|
|
- */
|
|
-static LWLockId breakpointLock;
|
|
-static HTAB * globalBreakpoints = NULL;
|
|
-static HTAB * localBreakpoints = NULL;
|
|
-
|
|
-/*-------------------------------------------------------------------------------------
|
|
- * The size of Breakpoints is determined by globalBreakpointCount (should be a GUC)
|
|
- *-------------------------------------------------------------------------------------
|
|
- */
|
|
-static int globalBreakpointCount = 20;
|
|
-static Size breakpoint_hash_size;
|
|
-static Size breakcount_hash_size;
|
|
-
|
|
-/*-------------------------------------------------------------------------------------
|
|
+ * The shared hash table for global breakpoints. It is protected by breakpointLock
|
|
+ *
|
|
* Another shared hash table which tracks number of breakpoints created
|
|
* against each entity.
|
|
- *
|
|
* It is also protected by breakpointLock, thus making operations on Breakpoints
|
|
* BreakCounts atomic.
|
|
+ *
|
|
+ * The size of Breakpoints is determined by globalBreakpointCount (should be a GUC)
|
|
*-------------------------------------------------------------------------------------
|
|
*/
|
|
-static HTAB *globalBreakCounts;
|
|
-static HTAB *localBreakCounts;
|
|
+static LWLockId breakpointLock;
|
|
+static HTAB* globalBreakpoints = NULL;
|
|
+static HTAB* globalBreakCounts = NULL;
|
|
+static int globalBreakpointCount = 20;
|
|
+static Size breakpoint_hash_size;
|
|
+static Size breakcount_hash_size;
|
|
|
|
typedef struct BreakCountKey
|
|
{
|
|
@@ -1312,13 +1260,6 @@ typedef struct BreakCount
|
|
int count;
|
|
} BreakCount;
|
|
|
|
-/*-------------------------------------------------------------------------------------
|
|
- * Prototypes for functions which operate on GlobalBreakCounts.
|
|
- *-------------------------------------------------------------------------------------
|
|
- */
|
|
-static void initLocalBreakpoints(void);
|
|
-static void initLocalBreakCounts(void);
|
|
-
|
|
static void breakCountInsert(eBreakpointScope scope, BreakCountKey *key);
|
|
static void breakCountDelete(eBreakpointScope scope, BreakCountKey *key);
|
|
static int breakCountLookup(eBreakpointScope scope, BreakCountKey *key, bool *found);
|
|
@@ -1337,33 +1278,42 @@ static void reserveBreakpoints( void )
|
|
#endif
|
|
}
|
|
|
|
-static void
|
|
-initializeHashTables(void)
|
|
-{
|
|
- LWLockAcquire(AddinShmemInitLock, LW_EXCLUSIVE);
|
|
-
|
|
- initGlobalBreakpoints();
|
|
-
|
|
- LWLockRelease(AddinShmemInitLock);
|
|
-
|
|
- initLocalBreakpoints();
|
|
- initLocalBreakCounts();
|
|
-}
|
|
-
|
|
-static void
|
|
-initLocalBreakpoints(void)
|
|
+/*
|
|
+ * here we init:
|
|
+ * 1) local Breakpoint hatb
|
|
+ * 2) local breakpoint count hatb
|
|
+ */
|
|
+void initLocalBreakpoints(void)
|
|
{
|
|
HASHCTL ctl = {0};
|
|
-
|
|
ctl.keysize = sizeof(BreakpointKey);
|
|
ctl.entrysize = sizeof(Breakpoint);
|
|
ctl.hash = tag_hash;
|
|
+ ctl.hcxt = PldbgMemoryContext;
|
|
|
|
- localBreakpoints = hash_create("Local Breakpoints", 128, &ctl, HASH_ELEM | HASH_FUNCTION);
|
|
+ localBreakpoints = hash_create("Local Breakpoints", 128, &ctl, HASH_CONTEXT | HASH_ELEM | HASH_FUNCTION);
|
|
+ if (!localBreakpoints)
|
|
+ elog(ERROR, "could not initialize local breakpoints hash table");
|
|
+
|
|
+ HASHCTL ctlc = {0};
|
|
+ ctlc.keysize = sizeof(BreakCountKey);
|
|
+ ctlc.entrysize = sizeof(BreakCount);
|
|
+ ctlc.hash = tag_hash;
|
|
+ ctlc.hcxt = PldbgMemoryContext;
|
|
+
|
|
+ localBreakCounts = hash_create("Local Breakpoint Count Table", 32, &ctlc, HASH_CONTEXT | HASH_ELEM | HASH_FUNCTION );
|
|
+ if (!localBreakCounts)
|
|
+ elog(ERROR, "could not initialize local breakpoints count hash table");
|
|
}
|
|
|
|
-void
|
|
-initGlobalBreakpoints(void)
|
|
+/*
|
|
+ * here we init:
|
|
+ * 1) Global breakpoint Lock
|
|
+ * 2) Global Breakpoint list
|
|
+ * 3) Global BreakCounts Table
|
|
+ * in share memory.
|
|
+ */
|
|
+void initGlobalBreakpoints(void)
|
|
{
|
|
bool found;
|
|
int tableEntries = globalBreakpointCount;
|
|
@@ -1371,24 +1321,17 @@ initGlobalBreakpoints(void)
|
|
HASHCTL breakpointCtl = {0};
|
|
HASHCTL breakcountCtl = {0};
|
|
|
|
- gbpd = ShmemInitStruct("Global Breakpoint Data",
|
|
- sizeof(GlobalBreakpointData), &found);
|
|
+ LWLockAcquire(AddinShmemInitLock, LW_EXCLUSIVE);
|
|
+ gbpd = (GlobalBreakpointData*)ShmemInitStruct("Global Breakpoint Data", sizeof(GlobalBreakpointData), &found);
|
|
+
|
|
if (gbpd == NULL)
|
|
elog(ERROR, "out of shared memory");
|
|
|
|
-#if (PG_VERSION_NUM >= 90600)
|
|
- if (!found)
|
|
- {
|
|
- gbpd->tranche_id = LWLockNewTrancheId();
|
|
- LWLockInitialize(&gbpd->lock, gbpd->tranche_id);
|
|
- }
|
|
- {
|
|
- static LWLockTranche tranche;
|
|
-
|
|
- tranche.name = "pldebugger";
|
|
- tranche.array_base = &gbpd->lock;
|
|
- tranche.array_stride = sizeof(LWLock);
|
|
- LWLockRegisterTranche(gbpd->tranche_id, &tranche);
|
|
+#if (PG_VERSION_NUM >= 90204)
|
|
+ if (!found) {
|
|
+ /* Convert to array index. */
|
|
+ LWLockRegisterTranche((int)LWTRANCHE_PLDEBUG, "pldebugger");
|
|
+ LWLockInitialize(&gbpd->lock, (int)LWTRANCHE_PLDEBUG);
|
|
|
|
breakpointLock = &gbpd->lock;
|
|
}
|
|
@@ -1419,6 +1362,8 @@ initGlobalBreakpoints(void)
|
|
|
|
globalBreakCounts = ShmemInitHash("Global BreakCounts Table", tableEntries, tableEntries, &breakcountCtl, HASH_ELEM | HASH_FUNCTION);
|
|
|
|
+ LWLockRelease(AddinShmemInitLock);
|
|
+
|
|
if (!globalBreakCounts)
|
|
elog(FATAL, "could not initialize global breakpoints count hash table");
|
|
}
|
|
@@ -1427,7 +1372,7 @@ initGlobalBreakpoints(void)
|
|
/* ---------------------------------------------------------
|
|
* getPLDebuggerLock()
|
|
*
|
|
- * Returns the lockid of the lock used to protect pldebugger shared memory
|
|
+ * Returns the lock used to protect pldebugger shared memory
|
|
* structures. The lock is called breakpointLock in this file, but it's
|
|
* also shared by dbgcommm.c.
|
|
*/
|
|
@@ -1435,8 +1380,8 @@ initGlobalBreakpoints(void)
|
|
LWLockId
|
|
getPLDebuggerLock(void)
|
|
{
|
|
- if( localBreakpoints == NULL )
|
|
- initializeHashTables();
|
|
+ if( breakpointLock == NULL )
|
|
+ initGlobalBreakpoints();
|
|
|
|
return breakpointLock;
|
|
}
|
|
@@ -1455,8 +1400,8 @@ getPLDebuggerLock(void)
|
|
static void
|
|
acquireLock(eBreakpointScope scope, LWLockMode mode)
|
|
{
|
|
- if( localBreakpoints == NULL )
|
|
- initializeHashTables();
|
|
+ if( breakpointLock == NULL )
|
|
+ initGlobalBreakpoints();
|
|
|
|
if (scope == BP_GLOBAL)
|
|
LWLockAcquire(breakpointLock, mode);
|
|
@@ -1517,7 +1462,7 @@ BreakpointOnId(eBreakpointScope scope, Oid funcOid)
|
|
bool found = false;
|
|
BreakCountKey key;
|
|
|
|
- key.databaseId = MyProc->databaseId;
|
|
+ key.databaseId = t_thrd.proc->databaseId;
|
|
key.functionId = funcOid;
|
|
|
|
acquireLock(scope, LW_SHARED);
|
|
@@ -1648,7 +1593,7 @@ BreakpointBusySession(int pid)
|
|
* will ignore it)
|
|
*/
|
|
|
|
- localCopy.key.targetPid = MyProc->pid;
|
|
+ localCopy.key.targetSessId = t_thrd.proc->pid;
|
|
|
|
BreakpointInsertOrUpdate(BP_LOCAL, &localCopy.key, &localCopy.data );
|
|
}
|
|
@@ -1763,11 +1708,11 @@ BreakpointShowAll(eBreakpointScope scope)
|
|
|
|
while((entry = (Breakpoint *) hash_seq_search(&status)))
|
|
{
|
|
- elog(INFO, "Database(%d) function(%d) lineNumber(%d) targetPid(%d) proxyPort(%d) proxyPid(%d) busy(%c) tmp(%c)",
|
|
+ elog(INFO, "Database(%d) function(%d) lineNumber(%d) targetSessId(%ld) proxyPort(%d) proxyPid(%d) busy(%c) tmp(%c)",
|
|
entry->key.databaseId,
|
|
entry->key.functionId,
|
|
entry->key.lineNumber,
|
|
- entry->key.targetPid,
|
|
+ entry->key.targetSessId,
|
|
entry->data.proxyPort,
|
|
entry->data.proxyPid,
|
|
entry->data.busy ? 'T' : 'F',
|
|
@@ -1823,32 +1768,6 @@ void BreakpointCleanupProc(int pid)
|
|
releaseLock(BP_GLOBAL);
|
|
}
|
|
|
|
-/* ==========================================================================
|
|
- * Function definitions for BreakCounts hash table
|
|
- *
|
|
- * Note: All the underneath functions assume that the caller has taken care
|
|
- * of all concurrency issues and thus does not do any locking
|
|
- * ==========================================================================
|
|
- */
|
|
-
|
|
-static void
|
|
-initLocalBreakCounts(void)
|
|
-{
|
|
- HASHCTL ctl = {0};
|
|
-
|
|
- ctl.keysize = sizeof(BreakCountKey);
|
|
- ctl.entrysize = sizeof(BreakCount);
|
|
- ctl.hash = tag_hash;
|
|
-
|
|
- localBreakCounts = hash_create("Local Breakpoint Count Table",
|
|
- 32,
|
|
- &ctl,
|
|
- HASH_ELEM | HASH_FUNCTION );
|
|
-
|
|
- if (!globalBreakCounts)
|
|
- elog(FATAL, "could not initialize global breakpoints count hash table");
|
|
-}
|
|
-
|
|
/* ---------------------------------------------------------
|
|
* breakCountInsert()
|
|
*
|
|
@@ -1860,7 +1779,7 @@ breakCountInsert(eBreakpointScope scope, BreakCountKey *key)
|
|
BreakCount *entry;
|
|
bool found;
|
|
|
|
- entry = hash_search(getBreakCountHash(scope), key, HASH_ENTER, &found);
|
|
+ entry = (BreakCount*)hash_search(getBreakCountHash(scope), key, HASH_ENTER, &found);
|
|
|
|
if (found)
|
|
entry->count++;
|
|
@@ -1878,7 +1797,7 @@ breakCountDelete(eBreakpointScope scope, BreakCountKey *key)
|
|
{
|
|
BreakCount *entry;
|
|
|
|
- entry = hash_search(getBreakCountHash(scope), key, HASH_FIND, NULL);
|
|
+ entry = (BreakCount*)hash_search(getBreakCountHash(scope), key, HASH_FIND, NULL);
|
|
|
|
if (entry)
|
|
{
|
|
@@ -1900,7 +1819,7 @@ breakCountLookup(eBreakpointScope scope, BreakCountKey *key, bool *found)
|
|
{
|
|
BreakCount *entry;
|
|
|
|
- entry = hash_search(getBreakCountHash(scope), key, HASH_FIND, found);
|
|
+ entry = (BreakCount*)hash_search(getBreakCountHash(scope), key, HASH_FIND, found);
|
|
|
|
if (entry)
|
|
return entry->count;
|
|
@@ -1914,12 +1833,11 @@ breakCountLookup(eBreakpointScope scope, BreakCountKey *key, bool *found)
|
|
* Returns a pointer to the global or local breakpoint hash,
|
|
* depending on the given scope.
|
|
*/
|
|
-
|
|
static HTAB *
|
|
getBreakpointHash(eBreakpointScope scope )
|
|
{
|
|
- if( localBreakpoints == NULL )
|
|
- initializeHashTables();
|
|
+ if( globalBreakpoints == NULL )
|
|
+ initGlobalBreakpoints();
|
|
|
|
if (scope == BP_GLOBAL)
|
|
return globalBreakpoints;
|
|
@@ -1933,12 +1851,11 @@ getBreakpointHash(eBreakpointScope scope )
|
|
* Returns a pointer to the global or local breakcount hash,
|
|
* depending on the given scope.
|
|
*/
|
|
-
|
|
static HTAB *
|
|
getBreakCountHash(eBreakpointScope scope)
|
|
{
|
|
- if( localBreakCounts == NULL )
|
|
- initializeHashTables();
|
|
+ if( globalBreakCounts == NULL )
|
|
+ initGlobalBreakpoints();
|
|
|
|
if (scope == BP_GLOBAL)
|
|
return globalBreakCounts;
|
|
diff --git a/gpl_dependency/pldebugger/gplsrc/pldebugger_3_0/uninstall_pldbgapi.sql b/gpl_dependency/pldebugger/gplsrc/pldebugger_3_0/uninstall_pldbgapi.sql
|
|
index 568d053..fa8ab8c 100644
|
|
--- a/gpl_dependency/pldebugger/gplsrc/pldebugger_3_0/uninstall_pldbgapi.sql
|
|
+++ b/gpl_dependency/pldebugger/gplsrc/pldebugger_3_0/uninstall_pldbgapi.sql
|
|
@@ -7,27 +7,22 @@
|
|
-- versions, however.
|
|
--
|
|
|
|
-DROP FUNCTION pldbg_get_target_info(TEXT, "char");
|
|
-DROP FUNCTION pldbg_wait_for_target(INTEGER);
|
|
-DROP FUNCTION pldbg_wait_for_breakpoint(INTEGER);
|
|
DROP FUNCTION pldbg_step_over(INTEGER);
|
|
DROP FUNCTION pldbg_step_into(INTEGER);
|
|
-DROP FUNCTION pldbg_set_global_breakpoint(INTEGER, OID, INTEGER, INTEGER);
|
|
DROP FUNCTION pldbg_set_breakpoint(INTEGER, OID, INTEGER);
|
|
-DROP FUNCTION pldbg_select_frame(INTEGER, INTEGER);
|
|
DROP FUNCTION pldbg_get_variables(INTEGER);
|
|
DROP FUNCTION pldbg_get_proxy_info();
|
|
DROP FUNCTION pldbg_get_stack(INTEGER);
|
|
DROP FUNCTION pldbg_get_source(INTEGER, OID);
|
|
DROP FUNCTION pldbg_get_breakpoints(INTEGER);
|
|
DROP FUNCTION pldbg_drop_breakpoint(INTEGER, OID, INTEGER);
|
|
-DROP FUNCTION pldbg_deposit_value(INTEGER, TEXT, INTEGER, TEXT);
|
|
-DROP FUNCTION pldbg_create_listener();
|
|
DROP FUNCTION pldbg_continue(INTEGER);
|
|
DROP FUNCTION pldbg_attach_to_port(INTEGER);
|
|
DROP FUNCTION pldbg_abort_target(INTEGER);
|
|
DROP FUNCTION pldbg_oid_debug(OID);
|
|
DROP FUNCTION plpgsql_oid_debug(OID);
|
|
+DROP FUNCTION plpgsql_off();
|
|
+DROP FUNCTION plpgsql_on();
|
|
|
|
DROP TYPE proxyInfo;
|
|
DROP TYPE var;
|