Files
openGauss-third_party/gpl_dependency/pldebugger/pldebugger_3_0_patch.patch
2021-03-08 11:29:47 +08:00

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;