diff --git a/doc/src/sgml/protocol.sgml b/doc/src/sgml/protocol.sgml index 70c255f00ce5930bcc3917e3a27b78d7840c4afc..635fc7715b4f8cf5ef18c4721d0b7da12e18c016 100644 --- a/doc/src/sgml/protocol.sgml +++ b/doc/src/sgml/protocol.sgml @@ -1,4 +1,4 @@ -<!-- $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> @@ -3870,6 +3870,11 @@ individual fields will typically not end with a newline, whereas the single 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 @@ -3877,7 +3882,7 @@ 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> @@ -3888,6 +3893,11 @@ Subsequently, a ParameterStatus message is sent whenever the active value 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. diff --git a/src/backend/access/common/printtup.c b/src/backend/access/common/printtup.c index c88dedd93fd62697ae96e68b8bee444986155136..160b703223f5d973f7d9eb6bfc6f93a44cac869b 100644 --- a/src/backend/access/common/printtup.c +++ b/src/backend/access/common/printtup.c @@ -9,7 +9,7 @@ * 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 $ * *------------------------------------------------------------------------- */ @@ -98,6 +98,7 @@ printtup_setup(DestReceiver *self, int operation, { Form_pg_attribute *attrs = typeinfo->attrs; int natts = typeinfo->natts; + int proto = PG_PROTOCOL_MAJOR(FrontendProtocol); int i; StringInfoData buf; @@ -107,11 +108,19 @@ printtup_setup(DestReceiver *self, int operation, 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)); } diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c index 598e3c880e5ed0e0bb345d4a153dcf34ba8d52b1..a15985d3bd787f808142ef00283c5b39f4ccf511 100644 --- a/src/backend/access/transam/xact.c +++ b/src/backend/access/transam/xact.c @@ -8,7 +8,7 @@ * * * 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: @@ -1705,17 +1705,44 @@ AbortOutOfAnyTransaction(void) 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 */ } diff --git a/src/backend/tcop/dest.c b/src/backend/tcop/dest.c index 5ccaa60995c5ae39a4693c4a8ae877eab5ff13c1..41906a348a461fdd3b590f7a8a63187d7bba553f 100644 --- a/src/backend/tcop/dest.c +++ b/src/backend/tcop/dest.c @@ -8,7 +8,7 @@ * 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 $ * *------------------------------------------------------------------------- */ @@ -29,6 +29,7 @@ #include "postgres.h" #include "access/printtup.h" +#include "access/xact.h" #include "executor/tstoreReceiver.h" #include "libpq/libpq.h" #include "libpq/pqformat.h" @@ -177,6 +178,7 @@ NullCommand(CommandDest dest) * * 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. @@ -189,7 +191,15 @@ ReadyForQuery(CommandDest dest) { 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(); diff --git a/src/include/access/xact.h b/src/include/access/xact.h index b3938c869e1f759a5df90b3ce6f7e16f37593935..5525ce74457eabd575a2ec6be2072f4a594e9343 100644 --- a/src/include/access/xact.h +++ b/src/include/access/xact.h @@ -7,7 +7,7 @@ * 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 $ * *------------------------------------------------------------------------- */ @@ -29,9 +29,35 @@ 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 @@ -43,33 +69,17 @@ typedef struct TransactionStateData 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 @@ -115,6 +125,7 @@ extern void AbortCurrentTransaction(void); 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); diff --git a/src/include/libpq/pqcomm.h b/src/include/libpq/pqcomm.h index 6a871c7c6f61ec427a0f327edc66b5f66586d8c1..d5374a68fe6d53edc0f5415194760165765d1160 100644 --- a/src/include/libpq/pqcomm.h +++ b/src/include/libpq/pqcomm.h @@ -9,7 +9,7 @@ * 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 $ * *------------------------------------------------------------------------- */ @@ -106,7 +106,7 @@ typedef union SockAddr /* 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 */ diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c index 53c4e2886225e7b6a1f3381ab9d77bec5c31fb0f..db513d64ef5df47c325c4be69d326a04fbc67b7c 100644 --- a/src/interfaces/libpq/fe-exec.c +++ b/src/interfaces/libpq/fe-exec.c @@ -8,7 +8,7 @@ * * * 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) 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 */ @@ -1222,11 +1224,15 @@ getRowDescriptions(PGconn *conn) /* 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)) @@ -1237,8 +1243,9 @@ getRowDescriptions(PGconn *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, @@ -1246,6 +1253,7 @@ getRowDescriptions(PGconn *conn) result->attDescs[i].typid = typid; result->attDescs[i].typlen = typlen; result->attDescs[i].atttypmod = atttypmod; + /* XXX todo: save tableid/columnid too */ } /* Success! */ @@ -2289,9 +2297,10 @@ PQfn(PGconn *conn, 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); diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h index 12670f3a0a4e694e22e3ce24de7ac87f47ea865d..a5e6bceef4216315b922b0f443b1faa1f0082100 100644 --- a/src/interfaces/libpq/libpq-int.h +++ b/src/interfaces/libpq/libpq-int.h @@ -12,7 +12,7 @@ * 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 $ * *------------------------------------------------------------------------- */ @@ -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. */ -#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. @@ -241,6 +241,7 @@ struct pg_conn /* 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