Commit 4db9689d authored by Tom Lane's avatar Tom Lane

Add transaction status field to ReadyForQuery messages, and make room

for tableID/columnID in RowDescription.  (The latter isn't really
implemented yet though --- the backend always sends zeroes, and libpq
just throws away the data.)
parent 2b1e36c7
<!-- $Header: /cvsroot/pgsql/doc/src/sgml/protocol.sgml,v 1.31 2003/04/25 19:45:08 tgl Exp $ --> <!-- $Header: /cvsroot/pgsql/doc/src/sgml/protocol.sgml,v 1.32 2003/04/26 20:22:57 tgl Exp $ -->
<chapter id="protocol"> <chapter id="protocol">
<title>Frontend/Backend Protocol</title> <title>Frontend/Backend Protocol</title>
...@@ -3870,6 +3870,11 @@ individual fields will typically not end with a newline, whereas the single ...@@ -3870,6 +3870,11 @@ individual fields will typically not end with a newline, whereas the single
string sent in the older protocol always did. string sent in the older protocol always did.
</para> </para>
<para>
The ReadyForQuery ('<literal>Z</>') message includes a transaction status
indicator.
</para>
<para> <para>
COPY data is now encapsulated into CopyData and CopyDone messages. There COPY data is now encapsulated into CopyData and CopyDone messages. There
is a well-defined way to recover from errors during COPY. The special is a well-defined way to recover from errors during COPY. The special
...@@ -3877,7 +3882,7 @@ is a well-defined way to recover from errors during COPY. The special ...@@ -3877,7 +3882,7 @@ is a well-defined way to recover from errors during COPY. The special
during COPY OUT. during COPY OUT.
(It is still recognized as a terminator during COPY IN, but its use is (It is still recognized as a terminator during COPY IN, but its use is
deprecated and will eventually be removed.) Binary COPY is supported. deprecated and will eventually be removed.) Binary COPY is supported.
The CopyInResponse and CopyOutResponse messages carry a field indicating The CopyInResponse and CopyOutResponse messages include a field indicating
whether the COPY operation is text or binary. whether the COPY operation is text or binary.
</para> </para>
...@@ -3888,6 +3893,11 @@ Subsequently, a ParameterStatus message is sent whenever the active value ...@@ -3888,6 +3893,11 @@ Subsequently, a ParameterStatus message is sent whenever the active value
changes for any of these parameters. changes for any of these parameters.
</para> </para>
<para>
The RowDescription ('<literal>T</>') message carries new table OID and column
number fields for each column of the described row.
</para>
<para> <para>
The CursorResponse ('<literal>P</>') message is no longer generated by The CursorResponse ('<literal>P</>') message is no longer generated by
the backend. the backend.
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.66 2003/04/22 00:08:06 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.67 2003/04/26 20:22:58 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -98,6 +98,7 @@ printtup_setup(DestReceiver *self, int operation, ...@@ -98,6 +98,7 @@ printtup_setup(DestReceiver *self, int operation,
{ {
Form_pg_attribute *attrs = typeinfo->attrs; Form_pg_attribute *attrs = typeinfo->attrs;
int natts = typeinfo->natts; int natts = typeinfo->natts;
int proto = PG_PROTOCOL_MAJOR(FrontendProtocol);
int i; int i;
StringInfoData buf; StringInfoData buf;
...@@ -107,11 +108,19 @@ printtup_setup(DestReceiver *self, int operation, ...@@ -107,11 +108,19 @@ printtup_setup(DestReceiver *self, int operation,
for (i = 0; i < natts; ++i) for (i = 0; i < natts; ++i)
{ {
pq_sendstring(&buf, NameStr(attrs[i]->attname)); pq_sendstring(&buf, NameStr(attrs[i]->attname));
/* column ID info appears in protocol 3.0 and up */
if (proto >= 3)
{
/* XXX not yet implemented, send zeroes */
pq_sendint(&buf, 0, 4);
pq_sendint(&buf, 0, 2);
}
pq_sendint(&buf, (int) attrs[i]->atttypid, pq_sendint(&buf, (int) attrs[i]->atttypid,
sizeof(attrs[i]->atttypid)); sizeof(attrs[i]->atttypid));
pq_sendint(&buf, attrs[i]->attlen, pq_sendint(&buf, attrs[i]->attlen,
sizeof(attrs[i]->attlen)); sizeof(attrs[i]->attlen));
if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2) /* typmod appears in protocol 2.0 and up */
if (proto >= 2)
pq_sendint(&buf, attrs[i]->atttypmod, pq_sendint(&buf, attrs[i]->atttypmod,
sizeof(attrs[i]->atttypmod)); sizeof(attrs[i]->atttypmod));
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.145 2003/03/27 16:51:27 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.146 2003/04/26 20:22:59 tgl Exp $
* *
* NOTES * NOTES
* Transaction aborts can now occur two ways: * Transaction aborts can now occur two ways:
...@@ -1705,17 +1705,44 @@ AbortOutOfAnyTransaction(void) ...@@ -1705,17 +1705,44 @@ AbortOutOfAnyTransaction(void)
s->blockState = TBLOCK_DEFAULT; s->blockState = TBLOCK_DEFAULT;
} }
/*
* IsTransactionBlock --- are we within a transaction block?
*/
bool bool
IsTransactionBlock(void) IsTransactionBlock(void)
{ {
TransactionState s = CurrentTransactionState; TransactionState s = CurrentTransactionState;
if (s->blockState == TBLOCK_INPROGRESS if (s->blockState == TBLOCK_DEFAULT)
|| s->blockState == TBLOCK_ABORT return false;
|| s->blockState == TBLOCK_ENDABORT)
return true;
return false; return true;
}
/*
* TransactionBlockStatusCode - return status code to send in ReadyForQuery
*/
char
TransactionBlockStatusCode(void)
{
TransactionState s = CurrentTransactionState;
switch (s->blockState)
{
case TBLOCK_DEFAULT:
return 'I'; /* idle --- not in transaction */
case TBLOCK_BEGIN:
case TBLOCK_INPROGRESS:
case TBLOCK_END:
return 'T'; /* in transaction */
case TBLOCK_ABORT:
case TBLOCK_ENDABORT:
return 'E'; /* in failed transaction */
}
/* should never get here */
elog(ERROR, "bogus transaction block state");
return 0; /* keep compiler quiet */
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/dest.c,v 1.53 2003/04/22 00:08:07 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/tcop/dest.c,v 1.54 2003/04/26 20:22:59 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include "postgres.h" #include "postgres.h"
#include "access/printtup.h" #include "access/printtup.h"
#include "access/xact.h"
#include "executor/tstoreReceiver.h" #include "executor/tstoreReceiver.h"
#include "libpq/libpq.h" #include "libpq/libpq.h"
#include "libpq/pqformat.h" #include "libpq/pqformat.h"
...@@ -177,6 +178,7 @@ NullCommand(CommandDest dest) ...@@ -177,6 +178,7 @@ NullCommand(CommandDest dest)
* *
* The ReadyForQuery message is sent in protocol versions 2.0 and up * The ReadyForQuery message is sent in protocol versions 2.0 and up
* so that the FE can tell when we are done processing a query string. * so that the FE can tell when we are done processing a query string.
* In versions 3.0 and up, it also carries a transaction state indicator.
* *
* Note that by flushing the stdio buffer here, we can avoid doing it * Note that by flushing the stdio buffer here, we can avoid doing it
* most other places and thus reduce the number of separate packets sent. * most other places and thus reduce the number of separate packets sent.
...@@ -189,7 +191,15 @@ ReadyForQuery(CommandDest dest) ...@@ -189,7 +191,15 @@ ReadyForQuery(CommandDest dest)
{ {
case RemoteInternal: case RemoteInternal:
case Remote: case Remote:
if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2) if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3)
{
StringInfoData buf;
pq_beginmessage(&buf, 'Z');
pq_sendbyte(&buf, TransactionBlockStatusCode());
pq_endmessage(&buf);
}
else if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2)
pq_putemptymessage('Z'); pq_putemptymessage('Z');
/* Flush output at end of cycle in any case. */ /* Flush output at end of cycle in any case. */
pq_flush(); pq_flush();
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: xact.h,v 1.49 2003/01/10 22:03:30 petere Exp $ * $Id: xact.h,v 1.50 2003/04/26 20:22:59 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -29,9 +29,35 @@ ...@@ -29,9 +29,35 @@
extern int DefaultXactIsoLevel; extern int DefaultXactIsoLevel;
extern int XactIsoLevel; extern int XactIsoLevel;
/* Xact read-only state */
extern bool DefaultXactReadOnly; extern bool DefaultXactReadOnly;
extern bool XactReadOnly; extern bool XactReadOnly;
/*
* transaction states - transaction state from server perspective
*/
typedef enum TransState
{
TRANS_DEFAULT,
TRANS_START,
TRANS_INPROGRESS,
TRANS_COMMIT,
TRANS_ABORT
} TransState;
/*
* transaction block states - transaction state of client queries
*/
typedef enum TBlockState
{
TBLOCK_DEFAULT,
TBLOCK_BEGIN,
TBLOCK_INPROGRESS,
TBLOCK_END,
TBLOCK_ABORT,
TBLOCK_ENDABORT
} TBlockState;
/* ---------------- /* ----------------
* transaction state structure * transaction state structure
...@@ -43,33 +69,17 @@ typedef struct TransactionStateData ...@@ -43,33 +69,17 @@ typedef struct TransactionStateData
CommandId commandId; CommandId commandId;
AbsoluteTime startTime; AbsoluteTime startTime;
int startTimeUsec; int startTimeUsec;
int state; TransState state;
int blockState; TBlockState blockState;
} TransactionStateData; } TransactionStateData;
typedef TransactionStateData *TransactionState; typedef TransactionStateData *TransactionState;
/*
* transaction states - transaction state from server perspective
*
* Syntax error could cause transaction to abort, but client code thinks
* it is still in a transaction, so we have to wait for COMMIT/ROLLBACK.
*/
#define TRANS_DEFAULT 0
#define TRANS_START 1
#define TRANS_INPROGRESS 2
#define TRANS_COMMIT 3
#define TRANS_ABORT 4
/* /* ----------------
* transaction block states - transaction state of client queries * transaction-related XLOG entries
* ----------------
*/ */
#define TBLOCK_DEFAULT 0
#define TBLOCK_BEGIN 1
#define TBLOCK_INPROGRESS 2
#define TBLOCK_END 3
#define TBLOCK_ABORT 4
#define TBLOCK_ENDABORT 5
/* /*
* XLOG allows to store some information in high 4 bits of log * XLOG allows to store some information in high 4 bits of log
...@@ -115,6 +125,7 @@ extern void AbortCurrentTransaction(void); ...@@ -115,6 +125,7 @@ extern void AbortCurrentTransaction(void);
extern void BeginTransactionBlock(void); extern void BeginTransactionBlock(void);
extern void EndTransactionBlock(void); extern void EndTransactionBlock(void);
extern bool IsTransactionBlock(void); extern bool IsTransactionBlock(void);
extern char TransactionBlockStatusCode(void);
extern void UserAbortTransactionBlock(void); extern void UserAbortTransactionBlock(void);
extern void AbortOutOfAnyTransaction(void); extern void AbortOutOfAnyTransaction(void);
extern void PreventTransactionChain(void *stmtNode, const char *stmtType); extern void PreventTransactionChain(void *stmtNode, const char *stmtType);
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: pqcomm.h,v 1.80 2003/04/25 19:45:09 tgl Exp $ * $Id: pqcomm.h,v 1.81 2003/04/26 20:22:59 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -106,7 +106,7 @@ typedef union SockAddr ...@@ -106,7 +106,7 @@ typedef union SockAddr
/* The earliest and latest frontend/backend protocol version supported. */ /* The earliest and latest frontend/backend protocol version supported. */
#define PG_PROTOCOL_EARLIEST PG_PROTOCOL(1,0) #define PG_PROTOCOL_EARLIEST PG_PROTOCOL(1,0)
#define PG_PROTOCOL_LATEST PG_PROTOCOL(3,104) /* XXX temporary value */ #define PG_PROTOCOL_LATEST PG_PROTOCOL(3,105) /* XXX temporary value */
typedef uint32 ProtocolVersion; /* FE/BE protocol version number */ typedef uint32 ProtocolVersion; /* FE/BE protocol version number */
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.133 2003/04/25 19:45:09 tgl Exp $ * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.134 2003/04/26 20:22:59 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1027,6 +1027,8 @@ parseInput(PGconn *conn) ...@@ -1027,6 +1027,8 @@ parseInput(PGconn *conn)
conn->asyncStatus = PGASYNC_READY; conn->asyncStatus = PGASYNC_READY;
break; break;
case 'Z': /* backend is ready for new query */ case 'Z': /* backend is ready for new query */
if (pqGetc(&conn->xact_status, conn))
return;
conn->asyncStatus = PGASYNC_IDLE; conn->asyncStatus = PGASYNC_IDLE;
break; break;
case 'I': /* empty query */ case 'I': /* empty query */
...@@ -1222,11 +1224,15 @@ getRowDescriptions(PGconn *conn) ...@@ -1222,11 +1224,15 @@ getRowDescriptions(PGconn *conn)
/* get type info */ /* get type info */
for (i = 0; i < nfields; i++) for (i = 0; i < nfields; i++)
{ {
int tableid;
int columnid;
int typid; int typid;
int typlen; int typlen;
int atttypmod; int atttypmod;
if (pqGets(&conn->workBuffer, conn) || if (pqGets(&conn->workBuffer, conn) ||
pqGetInt(&tableid, 4, conn) ||
pqGetInt(&columnid, 2, conn) ||
pqGetInt(&typid, 4, conn) || pqGetInt(&typid, 4, conn) ||
pqGetInt(&typlen, 2, conn) || pqGetInt(&typlen, 2, conn) ||
pqGetInt(&atttypmod, 4, conn)) pqGetInt(&atttypmod, 4, conn))
...@@ -1237,8 +1243,9 @@ getRowDescriptions(PGconn *conn) ...@@ -1237,8 +1243,9 @@ getRowDescriptions(PGconn *conn)
/* /*
* Since pqGetInt treats 2-byte integers as unsigned, we need to * Since pqGetInt treats 2-byte integers as unsigned, we need to
* coerce the result to signed form. * coerce these results to signed form.
*/ */
columnid = (int) ((int16) columnid);
typlen = (int) ((int16) typlen); typlen = (int) ((int16) typlen);
result->attDescs[i].name = pqResultStrdup(result, result->attDescs[i].name = pqResultStrdup(result,
...@@ -1246,6 +1253,7 @@ getRowDescriptions(PGconn *conn) ...@@ -1246,6 +1253,7 @@ getRowDescriptions(PGconn *conn)
result->attDescs[i].typid = typid; result->attDescs[i].typid = typid;
result->attDescs[i].typlen = typlen; result->attDescs[i].typlen = typlen;
result->attDescs[i].atttypmod = atttypmod; result->attDescs[i].atttypmod = atttypmod;
/* XXX todo: save tableid/columnid too */
} }
/* Success! */ /* Success! */
...@@ -2289,9 +2297,10 @@ PQfn(PGconn *conn, ...@@ -2289,9 +2297,10 @@ PQfn(PGconn *conn,
continue; continue;
break; break;
case 'Z': /* backend is ready for new query */ case 'Z': /* backend is ready for new query */
if (pqGetc(&conn->xact_status, conn))
continue;
/* consume the message and exit */ /* consume the message and exit */
conn->inStart += 5 + msgLength; conn->inStart += 5 + msgLength;
/* XXX expect additional fields here */
/* if we saved a result object (probably an error), use it */ /* if we saved a result object (probably an error), use it */
if (conn->result) if (conn->result)
return prepareAsyncResult(conn); return prepareAsyncResult(conn);
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: libpq-int.h,v 1.65 2003/04/25 19:45:10 tgl Exp $ * $Id: libpq-int.h,v 1.66 2003/04/26 20:23:00 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -56,7 +56,7 @@ typedef int ssize_t; /* ssize_t doesn't exist in VC (atleast ...@@ -56,7 +56,7 @@ typedef int ssize_t; /* ssize_t doesn't exist in VC (atleast
* pqcomm.h describe what the backend knows, not what libpq knows. * pqcomm.h describe what the backend knows, not what libpq knows.
*/ */
#define PG_PROTOCOL_LIBPQ PG_PROTOCOL(3,104) /* XXX temporary value */ #define PG_PROTOCOL_LIBPQ PG_PROTOCOL(3,105) /* XXX temporary value */
/* /*
* POSTGRES backend dependent Constants. * POSTGRES backend dependent Constants.
...@@ -241,6 +241,7 @@ struct pg_conn ...@@ -241,6 +241,7 @@ struct pg_conn
/* Status indicators */ /* Status indicators */
ConnStatusType status; ConnStatusType status;
PGAsyncStatusType asyncStatus; PGAsyncStatusType asyncStatus;
char xact_status; /* status flag from latest ReadyForQuery */
char copy_is_binary; /* 1 = copy binary, 0 = copy text */ char copy_is_binary; /* 1 = copy binary, 0 = copy text */
int copy_already_done; /* # bytes already returned in COPY OUT */ int copy_already_done; /* # bytes already returned in COPY OUT */
int nonblocking; /* whether this connection is using a int nonblocking; /* whether this connection is using a
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment