OK, updated patch, with output of text bind parameters. New output is:
LOG: prepare sel1: SELECT $1 + $2;
LOG: bind sel1: SELECT $1 + $2;
LOG: bind sel1: parameter 1: "8"
LOG: bind sel1: parameter 2: "5"
LOG: execute sel1: SELECT $1 + $2;
I put each bind parameter on a separate line. Is that OK?
I also updated the documentation. Test program also attached.
---------------------------------------------------------------------------
Bruce Momjian wrote:
> Tom Lane wrote:
> > Bruce Momjian <[EMAIL PROTECTED]> writes:
> > > I modified the code to store the user statement name in the portal for
> > > protocol execute, so I can print the user name at that time.
> >
> > Please forget that and print the portal name. I'm getting tired of
> > repeating it, but: there are two different names here and they are
> > both important. The bind message should print both names.
>
> OK, I added code to print an optional "/" and the portal name. However,
> I can't get libpq to show a portal name. Looking at libpq, does it only
> use "" portals, because the only place I see it sending a "B" shows a ""
> portal name? How can I test a portal name display?
>
> > > Here is
> > > the new output:
> >
> > > LOG: statement protocol prepare sel1: SELECT 1;
> > > LOG: statement protocol bind sel1: SELECT 1;
> > > LOG: statement protocol execute sel1: SELECT 1;
> >
> > If we could lose the noise words "statement protocol" we'd be getting
> > somewhere ...
>
> OK, as no one has said they like "statement protocol", the new output is:
>
> LOG: prepare sel1: SELECT 1;
> LOG: bind sel1: SELECT 1;
> LOG: execute sel1: SELECT 1;
>
> I will take a look at printing out bind text parameters.
>
> --
> Bruce Momjian [EMAIL PROTECTED]
> EnterpriseDB http://www.enterprisedb.com
>
> + If your life is a hard drive, Christ can be your backup. +
>
> ---------------------------(end of broadcast)---------------------------
> TIP 9: In versions below 8.0, the planner will ignore your desire to
> choose an index scan if your joining column's datatypes do not
> match
--
Bruce Momjian [EMAIL PROTECTED]
EnterpriseDB http://www.enterprisedb.com
+ If your life is a hard drive, Christ can be your backup. +
Index: doc/src/sgml/config.sgml
===================================================================
RCS file: /cvsroot/pgsql/doc/src/sgml/config.sgml,v
retrieving revision 1.71
diff -c -c -r1.71 config.sgml
*** doc/src/sgml/config.sgml 27 Jul 2006 08:30:41 -0000 1.71
--- doc/src/sgml/config.sgml 5 Aug 2006 04:55:50 -0000
***************
*** 2808,2814 ****
<literal>UPDATE</>, <literal>DELETE</>, <literal>TRUNCATE</>,
and <literal>COPY FROM</>. <literal>PREPARE</> and
<literal>EXPLAIN ANALYZE</> statements are also logged if their
! contained command is of an appropriate type.
</para>
<para>
The default is <literal>none</>. Only superusers can change this
--- 2808,2818 ----
<literal>UPDATE</>, <literal>DELETE</>, <literal>TRUNCATE</>,
and <literal>COPY FROM</>. <literal>PREPARE</> and
<literal>EXPLAIN ANALYZE</> statements are also logged if their
! contained command is of an appropriate type. Protocol-level
! prepare, bind, and execute commands are logged only if
! <varname>log_statement</> is <literal>all</>. Bind parameter
! values are also logged if they are supplied in <literal>text</>
! format.
</para>
<para>
The default is <literal>none</>. Only superusers can change this
Index: src/backend/commands/portalcmds.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/commands/portalcmds.c,v
retrieving revision 1.48
diff -c -c -r1.48 portalcmds.c
*** src/backend/commands/portalcmds.c 13 Jul 2006 16:49:14 -0000 1.48
--- src/backend/commands/portalcmds.c 5 Aug 2006 04:55:50 -0000
***************
*** 112,117 ****
--- 112,118 ----
* submitted more than one semicolon delimited queries.
*/
PortalDefineQuery(portal,
+ NULL,
pstrdup(debug_query_string),
"SELECT", /* cursor's query is always a SELECT */
list_make1(query),
Index: src/backend/commands/prepare.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/commands/prepare.c,v
retrieving revision 1.58
diff -c -c -r1.58 prepare.c
*** src/backend/commands/prepare.c 14 Jul 2006 14:52:18 -0000 1.58
--- src/backend/commands/prepare.c 5 Aug 2006 04:55:51 -0000
***************
*** 201,206 ****
--- 201,207 ----
}
PortalDefineQuery(portal,
+ NULL,
query_string,
entry->commandTag,
query_list,
Index: src/backend/executor/spi.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/executor/spi.c,v
retrieving revision 1.152
diff -c -c -r1.152 spi.c
*** src/backend/executor/spi.c 14 Jul 2006 14:52:19 -0000 1.152
--- src/backend/executor/spi.c 5 Aug 2006 04:55:51 -0000
***************
*** 919,924 ****
--- 919,925 ----
* Set up the portal.
*/
PortalDefineQuery(portal,
+ NULL,
spiplan->query,
"SELECT", /* don't have the raw parse tree... */
list_make1(queryTree),
Index: src/backend/tcop/postgres.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/tcop/postgres.c,v
retrieving revision 1.494
diff -c -c -r1.494 postgres.c
*** src/backend/tcop/postgres.c 4 Aug 2006 18:53:46 -0000 1.494
--- src/backend/tcop/postgres.c 5 Aug 2006 04:55:52 -0000
***************
*** 955,960 ****
--- 955,961 ----
portal->visible = false;
PortalDefineQuery(portal,
+ NULL,
query_string,
commandTag,
querytree_list,
***************
*** 1146,1152 ****
if (log_statement == LOGSTMT_ALL)
ereport(LOG,
! (errmsg("statement: <protocol> PREPARE %s AS %s",
*stmt_name ? stmt_name : "<unnamed>",
query_string)));
--- 1147,1153 ----
if (log_statement == LOGSTMT_ALL)
ereport(LOG,
! (errmsg("prepare %s: %s",
*stmt_name ? stmt_name : "<unnamed>",
query_string)));
***************
*** 1452,1460 ****
/* We need to output the parameter values someday */
if (log_statement == LOGSTMT_ALL)
ereport(LOG,
! (errmsg("statement: <protocol> <BIND> %s [PREPARE: %s]",
! *portal_name ? portal_name : "<unnamed>",
! portal->sourceText ? portal->sourceText : "")));
/*
* Fetch parameters, if any, and store in the portal's memory context.
--- 1453,1463 ----
/* We need to output the parameter values someday */
if (log_statement == LOGSTMT_ALL)
ereport(LOG,
! (errmsg("bind %s%s%s: %s",
! *stmt_name ? stmt_name : "<unnamed>",
! *portal->name ? "/" : "",
! *portal->name ? portal->name : "",
! pstmt->query_string ? pstmt->query_string : "")));
/*
* Fetch parameters, if any, and store in the portal's memory context.
***************
*** 1517,1523 ****
else
pformat = 0; /* default = text */
! if (pformat == 0)
{
Oid typinput;
Oid typioparam;
--- 1520,1526 ----
else
pformat = 0; /* default = text */
! if (pformat == 0) /* text mode */
{
Oid typinput;
Oid typioparam;
***************
*** 1538,1548 ****
pstring,
typioparam,
-1);
/* Free result of encoding conversion, if any */
if (pstring && pstring != pbuf.data)
pfree(pstring);
}
! else if (pformat == 1)
{
Oid typreceive;
Oid typioparam;
--- 1541,1559 ----
pstring,
typioparam,
-1);
+
+ if (log_statement == LOGSTMT_ALL)
+ ereport(LOG,
+ (errmsg("bind %s%s%s: parameter %d: \"%s\"",
+ *stmt_name ? stmt_name : "<unnamed>",
+ *portal->name ? "/" : "",
+ *portal->name ? portal->name : "", i + 1, pstring)));
+
/* Free result of encoding conversion, if any */
if (pstring && pstring != pbuf.data)
pfree(pstring);
}
! else if (pformat == 1) /* binary mode */
{
Oid typreceive;
Oid typioparam;
***************
*** 1624,1629 ****
--- 1635,1641 ----
* Define portal and start execution.
*/
PortalDefineQuery(portal,
+ *stmt_name ? pstrdup(stmt_name) : NULL,
pstmt->query_string,
pstmt->commandTag,
pstmt->query_list,
***************
*** 1720,1728 ****
if (log_statement == LOGSTMT_ALL)
/* We have the portal, so output the source query. */
ereport(LOG,
! (errmsg("statement: <protocol> %sEXECUTE %s [PREPARE: %s]",
! execute_is_fetch ? "FETCH from " : "",
! *portal_name ? portal_name : "<unnamed>",
portal->sourceText ? portal->sourceText : "")));
BeginCommand(portal->commandTag, dest);
--- 1732,1742 ----
if (log_statement == LOGSTMT_ALL)
/* We have the portal, so output the source query. */
ereport(LOG,
! (errmsg("execute %s%s%s%s: %s",
! execute_is_fetch ? "fetch from " : "",
! portal->prepStmtName ? portal->prepStmtName : "<unnamed>",
! *portal->name ? "/" : "",
! *portal->name ? portal->name : "",
portal->sourceText ? portal->sourceText : "")));
BeginCommand(portal->commandTag, dest);
***************
*** 1828,1837 ****
secs, msecs)));
else
ereport(LOG,
! (errmsg("duration: %ld.%03d ms statement: <protocol> %sEXECUTE %s [PREPARE: %s]",
secs, msecs,
! execute_is_fetch ? "FETCH from " : "",
! *portal_name ? portal_name : "<unnamed>",
portal->sourceText ? portal->sourceText : "")));
}
}
--- 1842,1853 ----
secs, msecs)));
else
ereport(LOG,
! (errmsg("duration: %ld.%03d ms execute %s%s%s%s: %s",
secs, msecs,
! execute_is_fetch ? "fetch from " : "",
! portal->prepStmtName ? portal->prepStmtName : "<unnamed>",
! *portal->name ? "/" : "",
! *portal->name ? portal->name : "",
portal->sourceText ? portal->sourceText : "")));
}
}
Index: src/backend/utils/mmgr/portalmem.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/utils/mmgr/portalmem.c,v
retrieving revision 1.90
diff -c -c -r1.90 portalmem.c
*** src/backend/utils/mmgr/portalmem.c 14 Jul 2006 14:52:25 -0000 1.90
--- src/backend/utils/mmgr/portalmem.c 5 Aug 2006 04:55:53 -0000
***************
*** 244,249 ****
--- 244,250 ----
*/
void
PortalDefineQuery(Portal portal,
+ const char *prepStmtName,
const char *sourceText,
const char *commandTag,
List *parseTrees,
***************
*** 257,262 ****
--- 258,264 ----
Assert(commandTag != NULL || parseTrees == NIL);
+ portal->prepStmtName = prepStmtName;
portal->sourceText = sourceText;
portal->commandTag = commandTag;
portal->parseTrees = parseTrees;
Index: src/include/utils/portal.h
===================================================================
RCS file: /cvsroot/pgsql/src/include/utils/portal.h,v
retrieving revision 1.63
diff -c -c -r1.63 portal.h
*** src/include/utils/portal.h 13 Jul 2006 18:01:02 -0000 1.63
--- src/include/utils/portal.h 5 Aug 2006 04:55:54 -0000
***************
*** 100,105 ****
--- 100,106 ----
{
/* Bookkeeping data */
const char *name; /* portal's name */
+ const char *prepStmtName; /* protocol prepare name */
MemoryContext heap; /* subsidiary memory for portal */
ResourceOwner resowner; /* resources owned by portal */
void (*cleanup) (Portal portal); /* cleanup hook */
***************
*** 202,207 ****
--- 203,209 ----
extern void DropDependentPortals(MemoryContext queryContext);
extern Portal GetPortalByName(const char *name);
extern void PortalDefineQuery(Portal portal,
+ const char *prepStmtName,
const char *sourceText,
const char *commandTag,
List *parseTrees,
/*
* testlibpq.c
*
* Test the C version of libpq, the PostgreSQL frontend library.
*/
#include <stdio.h>
#include <stdlib.h>
#include "libpq-fe.h"
static void
exit_nicely(PGconn *conn)
{
PQfinish(conn);
exit(1);
}
int
main(int argc, char **argv)
{
const char *conninfo;
PGconn *conn;
PGresult *res;
int nFields;
int i,
j;
const char *val[2];
int types[2];
/*
* If the user supplies a parameter on the command line, use it as the
* conninfo string; otherwise default to setting dbname=postgres and
using
* environment variables or defaults for all other connection
parameters.
*/
if (argc > 1)
conninfo = argv[1];
else
conninfo = "dbname = postgres";
/* Make a connection to the database */
conn = PQconnectdb(conninfo);
/* Check to see that the backend connection was successfully made */
if (PQstatus(conn) != CONNECTION_OK)
{
fprintf(stderr, "Connection to database failed: %s",
PQerrorMessage(conn));
exit_nicely(conn);
}
res = PQexec(conn, "SET log_statement = 'all';");
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "BEGIN command failed: %s", PQerrorMessage(conn));
PQclear(res);
exit_nicely(conn);
}
/*
* Should PQclear PGresult whenever it is no longer needed to avoid memory
* leaks
*/
PQclear(res);
/*
* Our test case here involves using a cursor, for which we must be
inside
* a transaction block. We could do the whole thing with a single
* PQexec() of "select * from pg_database", but that's too trivial to
make
* a good example.
*/
/*
* Fetch rows from pg_database, the system catalog of databases
*/
types[0] = 23;
types[1] = 23;
res = PQprepare(conn, "sel1", "SELECT $1 + $2;", 2, types);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "prepared failed: %s", PQerrorMessage(conn));
PQclear(res);
exit_nicely(conn);
}
PQclear(res);
val[0] = "8";
val[1] = "5";
res = PQexecPrepared(conn, "sel1", 2, val, NULL, NULL, 0);
if (PQresultStatus(res) != PGRES_TUPLES_OK)
{
fprintf(stderr, "exec failed: %s", PQerrorMessage(conn));
PQclear(res);
exit_nicely(conn);
}
/* first, print out the attribute names */
nFields = PQnfields(res);
for (i = 0; i < nFields; i++)
printf("%-15s", PQfname(res, i));
printf("\n\n");
/* next, print out the rows */
for (i = 0; i < PQntuples(res); i++)
{
for (j = 0; j < nFields; j++)
printf("%-15s", PQgetvalue(res, i, j));
printf("\n");
}
PQclear(res);
/* close the connection to the database and cleanup */
PQfinish(conn);
return 0;
}
---------------------------(end of broadcast)---------------------------
TIP 9: In versions below 8.0, the planner will ignore your desire to
choose an index scan if your joining column's datatypes do not
match