-<!-- $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">
<title>Frontend/Backend Protocol</title>
string sent in the older protocol always did.
</para>
+<para>
+The ReadyForQuery ('<literal>Z</>') message includes a transaction status
+indicator.
+</para>
+
<para>
COPY data is now encapsulated into CopyData and CopyDone messages. There
is a well-defined way to recover from errors during COPY. The special
during COPY OUT.
(It is still recognized as a terminator during COPY IN, but its use is
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.
</para>
changes for any of these parameters.
</para>
+<para>
+The RowDescription ('<literal>T</>') message carries new table OID and column
+number fields for each column of the described row.
+</para>
+
<para>
The CursorResponse ('<literal>P</>') message is no longer generated by
the backend.
* Portions Copyright (c) 1994, Regents of the University of California
*
* 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 $
*
*-------------------------------------------------------------------------
*/
{
Form_pg_attribute *attrs = typeinfo->attrs;
int natts = typeinfo->natts;
+ int proto = PG_PROTOCOL_MAJOR(FrontendProtocol);
int i;
StringInfoData buf;
for (i = 0; i < natts; ++i)
{
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,
sizeof(attrs[i]->atttypid));
pq_sendint(&buf, 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,
sizeof(attrs[i]->atttypmod));
}
*
*
* 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
* Transaction aborts can now occur two ways:
s->blockState = TBLOCK_DEFAULT;
}
+/*
+ * IsTransactionBlock --- are we within a transaction block?
+ */
bool
IsTransactionBlock(void)
{
TransactionState s = CurrentTransactionState;
- if (s->blockState == TBLOCK_INPROGRESS
- || s->blockState == TBLOCK_ABORT
- || s->blockState == TBLOCK_ENDABORT)
- return true;
+ if (s->blockState == TBLOCK_DEFAULT)
+ return false;
- 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 */
}
* Portions Copyright (c) 1994, Regents of the University of California
*
* 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 $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/printtup.h"
+#include "access/xact.h"
#include "executor/tstoreReceiver.h"
#include "libpq/libpq.h"
#include "libpq/pqformat.h"
*
* 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.
+ * 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
* most other places and thus reduce the number of separate packets sent.
{
case RemoteInternal:
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');
/* Flush output at end of cycle in any case. */
pq_flush();
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* 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 $
*
*-------------------------------------------------------------------------
*/
extern int DefaultXactIsoLevel;
extern int XactIsoLevel;
+
+/* Xact read-only state */
extern bool DefaultXactReadOnly;
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
CommandId commandId;
AbsoluteTime startTime;
int startTimeUsec;
- int state;
- int blockState;
+ TransState state;
+ TBlockState blockState;
} TransactionStateData;
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
extern void BeginTransactionBlock(void);
extern void EndTransactionBlock(void);
extern bool IsTransactionBlock(void);
+extern char TransactionBlockStatusCode(void);
extern void UserAbortTransactionBlock(void);
extern void AbortOutOfAnyTransaction(void);
extern void PreventTransactionChain(void *stmtNode, const char *stmtType);
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* 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 $
*
*-------------------------------------------------------------------------
*/
/* The earliest and latest frontend/backend protocol version supported. */
#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 */
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
conn->asyncStatus = PGASYNC_READY;
break;
case 'Z': /* backend is ready for new query */
+ if (pqGetc(&conn->xact_status, conn))
+ return;
conn->asyncStatus = PGASYNC_IDLE;
break;
case 'I': /* empty query */
/* get type info */
for (i = 0; i < nfields; i++)
{
+ int tableid;
+ int columnid;
int typid;
int typlen;
int atttypmod;
if (pqGets(&conn->workBuffer, conn) ||
+ pqGetInt(&tableid, 4, conn) ||
+ pqGetInt(&columnid, 2, conn) ||
pqGetInt(&typid, 4, conn) ||
pqGetInt(&typlen, 2, conn) ||
pqGetInt(&atttypmod, 4, conn))
/*
* 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);
result->attDescs[i].name = pqResultStrdup(result,
result->attDescs[i].typid = typid;
result->attDescs[i].typlen = typlen;
result->attDescs[i].atttypmod = atttypmod;
+ /* XXX todo: save tableid/columnid too */
}
/* Success! */
continue;
break;
case 'Z': /* backend is ready for new query */
+ if (pqGetc(&conn->xact_status, conn))
+ continue;
/* consume the message and exit */
conn->inStart += 5 + msgLength;
- /* XXX expect additional fields here */
/* if we saved a result object (probably an error), use it */
if (conn->result)
return prepareAsyncResult(conn);
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* 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 $
*
*-------------------------------------------------------------------------
*/
* 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.
/* Status indicators */
ConnStatusType status;
PGAsyncStatusType asyncStatus;
+ char xact_status; /* status flag from latest ReadyForQuery */
char copy_is_binary; /* 1 = copy binary, 0 = copy text */
int copy_already_done; /* # bytes already returned in COPY OUT */
int nonblocking; /* whether this connection is using a