pair of
Stream Start and Stream Stop messages. The last stream of such a transaction
contains a Stream Commit or Stream Abort message.
</para>
<para>
Every sent transaction contains zero or more DML messages (Insert,
Update, Delete). In case of a cascaded setup it can also contain Origin
messages. The origin message indicates that the transaction originated on
different replication node. Since a replication node in the scope of logical
replication protocol can be pretty much anything, the only identifier
is the origin name. It's downstream's responsibility to handle this as
needed (if needed). The Origin message is always sent before any DML
messages in the transaction.
</para>
<para>
Every DML message contains a relation OID, identifying the publisher's
relation that was acted on. Before the first DML message for a given
relation OID, a Relation message will be sent, describing the schema of
that relation. Subsequently, a new Relation message will be sent if
the relation's definition has changed since the last Relation message
was sent for it. (The protocol assumes that the client is capable of
remembering this metadata for as many relations as needed.)
</para>
<para>
Relation messages identify column types by their OIDs. In the case
of a built-in type, it is assumed that the client can look up that
type OID locally, so no additional data is needed. For a non-built-in
type OID, a Type message will be sent before the Relation message,
to provide the type name associated with that OID. Thus, a client that
needs to specifically identify the types of relation columns should
cache the contents of Type messages, and first consult that cache to
see if the type OID is defined there. If not, look up the type OID
locally.
</para>
</sect2>
</sect1>
<sect1 id="protocol-message-types">
<title>Message Data Types</title>
<para>
This section describes the base data types used in messages.
</para>
<variablelist>
<varlistentry>
<term>Int<replaceable>n</replaceable>(<replaceable>i</replaceable>)</term>
<listitem>
<para>
An <replaceable>n</replaceable>-bit integer in network byte
order (most significant byte first).
If <replaceable>i</replaceable> is specified it
is the exact value that will appear, otherwise the value
is variable. Eg. Int16, Int32(42).
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Int<replaceable>n</replaceable>[<replaceable>k</replaceable>]</term>
<listitem>
<para>
An array of <replaceable>k</replaceable>
<replaceable>n</replaceable>-bit integers, each in network
byte order. The array length <replaceable>k</replaceable>
is always determined by an earlier field in the message.
Eg. Int16[M].
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>String(<replaceable>s</replaceable>)</term>
<listitem>
<para>
A null-terminated string (C-style string). There is no
specific length limitation on strings.
If <replaceable>s</replaceable> is specified it is the exact
value that will appear, otherwise the value is variable.
Eg. String, String("user").
</para>
<note>
<para>
<emphasis>There is no predefined limit</emphasis> on the length of a string
that can be returned by the backend. Good coding strategy for a frontend
is to use an expandable buffer so that anything that fits in memory can be
accepted. If that's not feasible, read the full string and discard trailing
characters that don't fit into your fixed-size buffer.
</para>
</note>
</listitem>
</varlistentry>
<varlistentry>
<term>Byte<replaceable>n</replaceable>(<replaceable>c</replaceable>)</term>
<listitem>
<para>
Exactly <replaceable>n</replaceable> bytes. If the field
width <replaceable>n</replaceable>