diff options
Diffstat (limited to 'doc/src/sgml/html/libpq-copy.html')
-rw-r--r-- | doc/src/sgml/html/libpq-copy.html | 300 |
1 files changed, 300 insertions, 0 deletions
diff --git a/doc/src/sgml/html/libpq-copy.html b/doc/src/sgml/html/libpq-copy.html new file mode 100644 index 0000000..8530822 --- /dev/null +++ b/doc/src/sgml/html/libpq-copy.html @@ -0,0 +1,300 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>34.10. Functions Associated with the COPY Command</title><link rel="stylesheet" type="text/css" href="stylesheet.css" /><link rev="made" href="pgsql-docs@lists.postgresql.org" /><meta name="generator" content="DocBook XSL Stylesheets Vsnapshot" /><link rel="prev" href="libpq-notify.html" title="34.9. Asynchronous Notification" /><link rel="next" href="libpq-control.html" title="34.11. Control Functions" /></head><body id="docContent" class="container-fluid col-10"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="5" align="center">34.10. Functions Associated with the <code class="command">COPY</code> Command</th></tr><tr><td width="10%" align="left"><a accesskey="p" href="libpq-notify.html" title="34.9. Asynchronous Notification">Prev</a> </td><td width="10%" align="left"><a accesskey="u" href="libpq.html" title="Chapter 34. libpq — C Library">Up</a></td><th width="60%" align="center">Chapter 34. <span class="application">libpq</span> — C Library</th><td width="10%" align="right"><a accesskey="h" href="index.html" title="PostgreSQL 15.5 Documentation">Home</a></td><td width="10%" align="right"> <a accesskey="n" href="libpq-control.html" title="34.11. Control Functions">Next</a></td></tr></table><hr /></div><div class="sect1" id="LIBPQ-COPY"><div class="titlepage"><div><div><h2 class="title" style="clear: both">34.10. Functions Associated with the <code class="command">COPY</code> Command</h2></div></div></div><div class="toc"><dl class="toc"><dt><span class="sect2"><a href="libpq-copy.html#LIBPQ-COPY-SEND">34.10.1. Functions for Sending <code class="command">COPY</code> Data</a></span></dt><dt><span class="sect2"><a href="libpq-copy.html#LIBPQ-COPY-RECEIVE">34.10.2. Functions for Receiving <code class="command">COPY</code> Data</a></span></dt><dt><span class="sect2"><a href="libpq-copy.html#LIBPQ-COPY-DEPRECATED">34.10.3. Obsolete Functions for <code class="command">COPY</code></a></span></dt></dl></div><a id="id-1.7.3.17.2" class="indexterm"></a><p> + The <code class="command">COPY</code> command in + <span class="productname">PostgreSQL</span> has options to read from or write + to the network connection used by <span class="application">libpq</span>. + The functions described in this section allow applications to take + advantage of this capability by supplying or consuming copied data. + </p><p> + The overall process is that the application first issues the SQL + <code class="command">COPY</code> command via <a class="xref" href="libpq-exec.html#LIBPQ-PQEXEC"><code class="function">PQexec</code></a> or one + of the equivalent functions. The response to this (if there is no + error in the command) will be a <code class="structname">PGresult</code> object bearing + a status code of <code class="literal">PGRES_COPY_OUT</code> or + <code class="literal">PGRES_COPY_IN</code> (depending on the specified copy + direction). The application should then use the functions of this + section to receive or transmit data rows. When the data transfer is + complete, another <code class="structname">PGresult</code> object is returned to indicate + success or failure of the transfer. Its status will be + <code class="literal">PGRES_COMMAND_OK</code> for success or + <code class="literal">PGRES_FATAL_ERROR</code> if some problem was encountered. + At this point further SQL commands can be issued via + <a class="xref" href="libpq-exec.html#LIBPQ-PQEXEC"><code class="function">PQexec</code></a>. (It is not possible to execute other SQL + commands using the same connection while the <code class="command">COPY</code> + operation is in progress.) + </p><p> + If a <code class="command">COPY</code> command is issued via + <a class="xref" href="libpq-exec.html#LIBPQ-PQEXEC"><code class="function">PQexec</code></a> in a string that could contain additional + commands, the application must continue fetching results via + <a class="xref" href="libpq-async.html#LIBPQ-PQGETRESULT"><code class="function">PQgetResult</code></a> after completing the <code class="command">COPY</code> + sequence. Only when <a class="xref" href="libpq-async.html#LIBPQ-PQGETRESULT"><code class="function">PQgetResult</code></a> returns + <code class="symbol">NULL</code> is it certain that the <a class="xref" href="libpq-exec.html#LIBPQ-PQEXEC"><code class="function">PQexec</code></a> + command string is done and it is safe to issue more commands. + </p><p> + The functions of this section should be executed only after obtaining + a result status of <code class="literal">PGRES_COPY_OUT</code> or + <code class="literal">PGRES_COPY_IN</code> from <a class="xref" href="libpq-exec.html#LIBPQ-PQEXEC"><code class="function">PQexec</code></a> or + <a class="xref" href="libpq-async.html#LIBPQ-PQGETRESULT"><code class="function">PQgetResult</code></a>. + </p><p> + A <code class="structname">PGresult</code> object bearing one of these status values + carries some additional data about the <code class="command">COPY</code> operation + that is starting. This additional data is available using functions + that are also used in connection with query results: + + </p><div class="variablelist"><dl class="variablelist"><dt id="LIBPQ-PQNFIELDS-1"><span class="term"><code class="function">PQnfields</code><a id="id-1.7.3.17.7.3.1.1.2" class="indexterm"></a></span></dt><dd><p> + Returns the number of columns (fields) to be copied. + </p></dd><dt id="LIBPQ-PQBINARYTUPLES-1"><span class="term"><code class="function">PQbinaryTuples</code><a id="id-1.7.3.17.7.3.2.1.2" class="indexterm"></a></span></dt><dd><p> + 0 indicates the overall copy format is textual (rows separated by + newlines, columns separated by separator characters, etc.). 1 + indicates the overall copy format is binary. See <a class="xref" href="sql-copy.html" title="COPY"><span class="refentrytitle">COPY</span></a> for more information. + </p></dd><dt id="LIBPQ-PQFFORMAT-1"><span class="term"><code class="function">PQfformat</code><a id="id-1.7.3.17.7.3.3.1.2" class="indexterm"></a></span></dt><dd><p> + Returns the format code (0 for text, 1 for binary) associated with + each column of the copy operation. The per-column format codes + will always be zero when the overall copy format is textual, but + the binary format can support both text and binary columns. + (However, as of the current implementation of <code class="command">COPY</code>, + only binary columns appear in a binary copy; so the per-column + formats always match the overall format at present.) + </p></dd></dl></div><p> + </p><div class="sect2" id="LIBPQ-COPY-SEND"><div class="titlepage"><div><div><h3 class="title">34.10.1. Functions for Sending <code class="command">COPY</code> Data</h3></div></div></div><p> + These functions are used to send data during <code class="literal">COPY FROM + STDIN</code>. They will fail if called when the connection is not in + <code class="literal">COPY_IN</code> state. + </p><div class="variablelist"><dl class="variablelist"><dt id="LIBPQ-PQPUTCOPYDATA"><span class="term"><code class="function">PQputCopyData</code><a id="id-1.7.3.17.8.3.1.1.2" class="indexterm"></a></span></dt><dd><p> + Sends data to the server during <code class="literal">COPY_IN</code> state. +</p><pre class="synopsis"> +int PQputCopyData(PGconn *conn, + const char *buffer, + int nbytes); +</pre><p> + </p><p> + Transmits the <code class="command">COPY</code> data in the specified + <em class="parameter"><code>buffer</code></em>, of length <em class="parameter"><code>nbytes</code></em>, to the server. + The result is 1 if the data was queued, zero if it was not queued + because of full buffers (this will only happen in nonblocking mode), + or -1 if an error occurred. + (Use <a class="xref" href="libpq-status.html#LIBPQ-PQERRORMESSAGE"><code class="function">PQerrorMessage</code></a> to retrieve details if + the return value is -1. If the value is zero, wait for write-ready + and try again.) + </p><p> + The application can divide the <code class="command">COPY</code> data stream + into buffer loads of any convenient size. Buffer-load boundaries + have no semantic significance when sending. The contents of the + data stream must match the data format expected by the + <code class="command">COPY</code> command; see <a class="xref" href="sql-copy.html" title="COPY"><span class="refentrytitle">COPY</span></a> for details. + </p></dd><dt id="LIBPQ-PQPUTCOPYEND"><span class="term"><code class="function">PQputCopyEnd</code><a id="id-1.7.3.17.8.3.2.1.2" class="indexterm"></a></span></dt><dd><p> + Sends end-of-data indication to the server during <code class="literal">COPY_IN</code> state. +</p><pre class="synopsis"> +int PQputCopyEnd(PGconn *conn, + const char *errormsg); +</pre><p> + </p><p> + Ends the <code class="literal">COPY_IN</code> operation successfully if + <em class="parameter"><code>errormsg</code></em> is <code class="symbol">NULL</code>. If + <em class="parameter"><code>errormsg</code></em> is not <code class="symbol">NULL</code> then the + <code class="command">COPY</code> is forced to fail, with the string pointed to by + <em class="parameter"><code>errormsg</code></em> used as the error message. (One should not + assume that this exact error message will come back from the server, + however, as the server might have already failed the + <code class="command">COPY</code> for its own reasons.) + </p><p> + The result is 1 if the termination message was sent; or in + nonblocking mode, this may only indicate that the termination + message was successfully queued. (In nonblocking mode, to be + certain that the data has been sent, you should next wait for + write-ready and call <a class="xref" href="libpq-async.html#LIBPQ-PQFLUSH"><code class="function">PQflush</code></a>, repeating until it + returns zero.) Zero indicates that the function could not queue + the termination message because of full buffers; this will only + happen in nonblocking mode. (In this case, wait for + write-ready and try the <a class="xref" href="libpq-copy.html#LIBPQ-PQPUTCOPYEND"><code class="function">PQputCopyEnd</code></a> call + again.) If a hard error occurs, -1 is returned; you can use + <a class="xref" href="libpq-status.html#LIBPQ-PQERRORMESSAGE"><code class="function">PQerrorMessage</code></a> to retrieve details. + </p><p> + After successfully calling <a class="xref" href="libpq-copy.html#LIBPQ-PQPUTCOPYEND"><code class="function">PQputCopyEnd</code></a>, call + <a class="xref" href="libpq-async.html#LIBPQ-PQGETRESULT"><code class="function">PQgetResult</code></a> to obtain the final result status of the + <code class="command">COPY</code> command. One can wait for this result to be + available in the usual way. Then return to normal operation. + </p></dd></dl></div></div><div class="sect2" id="LIBPQ-COPY-RECEIVE"><div class="titlepage"><div><div><h3 class="title">34.10.2. Functions for Receiving <code class="command">COPY</code> Data</h3></div></div></div><p> + These functions are used to receive data during <code class="literal">COPY TO + STDOUT</code>. They will fail if called when the connection is not in + <code class="literal">COPY_OUT</code> state. + </p><div class="variablelist"><dl class="variablelist"><dt id="LIBPQ-PQGETCOPYDATA"><span class="term"><code class="function">PQgetCopyData</code><a id="id-1.7.3.17.9.3.1.1.2" class="indexterm"></a></span></dt><dd><p> + Receives data from the server during <code class="literal">COPY_OUT</code> state. +</p><pre class="synopsis"> +int PQgetCopyData(PGconn *conn, + char **buffer, + int async); +</pre><p> + </p><p> + Attempts to obtain another row of data from the server during a + <code class="command">COPY</code>. Data is always returned one data row at + a time; if only a partial row is available, it is not returned. + Successful return of a data row involves allocating a chunk of + memory to hold the data. The <em class="parameter"><code>buffer</code></em> parameter must + be non-<code class="symbol">NULL</code>. <em class="parameter"><code>*buffer</code></em> is set to + point to the allocated memory, or to <code class="symbol">NULL</code> in cases + where no buffer is returned. A non-<code class="symbol">NULL</code> result + buffer should be freed using <a class="xref" href="libpq-misc.html#LIBPQ-PQFREEMEM"><code class="function">PQfreemem</code></a> when no longer + needed. + </p><p> + When a row is successfully returned, the return value is the number + of data bytes in the row (this will always be greater than zero). + The returned string is always null-terminated, though this is + probably only useful for textual <code class="command">COPY</code>. A result + of zero indicates that the <code class="command">COPY</code> is still in + progress, but no row is yet available (this is only possible when + <em class="parameter"><code>async</code></em> is true). A result of -1 indicates that the + <code class="command">COPY</code> is done. A result of -2 indicates that an + error occurred (consult <a class="xref" href="libpq-status.html#LIBPQ-PQERRORMESSAGE"><code class="function">PQerrorMessage</code></a> for the reason). + </p><p> + When <em class="parameter"><code>async</code></em> is true (not zero), + <a class="xref" href="libpq-copy.html#LIBPQ-PQGETCOPYDATA"><code class="function">PQgetCopyData</code></a> will not block waiting for input; it + will return zero if the <code class="command">COPY</code> is still in progress + but no complete row is available. (In this case wait for read-ready + and then call <a class="xref" href="libpq-async.html#LIBPQ-PQCONSUMEINPUT"><code class="function">PQconsumeInput</code> + </a> before calling + <a class="xref" href="libpq-copy.html#LIBPQ-PQGETCOPYDATA"><code class="function">PQgetCopyData</code></a> again.) When <em class="parameter"><code>async</code></em> is + false (zero), <a class="xref" href="libpq-copy.html#LIBPQ-PQGETCOPYDATA"><code class="function">PQgetCopyData</code></a> will block until data is + available or the operation completes. + </p><p> + After <a class="xref" href="libpq-copy.html#LIBPQ-PQGETCOPYDATA"><code class="function">PQgetCopyData</code></a> returns -1, call + <a class="xref" href="libpq-async.html#LIBPQ-PQGETRESULT"><code class="function">PQgetResult</code></a> to obtain the final result status of the + <code class="command">COPY</code> command. One can wait for this result to be + available in the usual way. Then return to normal operation. + </p></dd></dl></div></div><div class="sect2" id="LIBPQ-COPY-DEPRECATED"><div class="titlepage"><div><div><h3 class="title">34.10.3. Obsolete Functions for <code class="command">COPY</code></h3></div></div></div><p> + These functions represent older methods of handling <code class="command">COPY</code>. + Although they still work, they are deprecated due to poor error handling, + inconvenient methods of detecting end-of-data, and lack of support for binary + or nonblocking transfers. + </p><div class="variablelist"><dl class="variablelist"><dt id="LIBPQ-PQGETLINE"><span class="term"><code class="function">PQgetline</code><a id="id-1.7.3.17.10.3.1.1.2" class="indexterm"></a></span></dt><dd><p> + Reads a newline-terminated line of characters (transmitted + by the server) into a buffer string of size <em class="parameter"><code>length</code></em>. +</p><pre class="synopsis"> +int PQgetline(PGconn *conn, + char *buffer, + int length); +</pre><p> + </p><p> + This function copies up to <em class="parameter"><code>length</code></em>-1 characters into + the buffer and converts the terminating newline into a zero byte. + <a class="xref" href="libpq-copy.html#LIBPQ-PQGETLINE"><code class="function">PQgetline</code></a> returns <code class="symbol">EOF</code> at the + end of input, 0 if the entire line has been read, and 1 if the + buffer is full but the terminating newline has not yet been read. + </p><p> + Note that the application must check to see if a new line consists + of the two characters <code class="literal">\.</code>, which indicates + that the server has finished sending the results of the + <code class="command">COPY</code> command. If the application might receive + lines that are more than <em class="parameter"><code>length</code></em>-1 characters long, + care is needed to be sure it recognizes the <code class="literal">\.</code> + line correctly (and does not, for example, mistake the end of a + long data line for a terminator line). + </p></dd><dt id="LIBPQ-PQGETLINEASYNC"><span class="term"><code class="function">PQgetlineAsync</code><a id="id-1.7.3.17.10.3.2.1.2" class="indexterm"></a></span></dt><dd><p> + Reads a row of <code class="command">COPY</code> data (transmitted by the + server) into a buffer without blocking. +</p><pre class="synopsis"> +int PQgetlineAsync(PGconn *conn, + char *buffer, + int bufsize); +</pre><p> + </p><p> + This function is similar to <a class="xref" href="libpq-copy.html#LIBPQ-PQGETLINE"><code class="function">PQgetline</code></a>, but it can be used + by applications + that must read <code class="command">COPY</code> data asynchronously, that is, without blocking. + Having issued the <code class="command">COPY</code> command and gotten a <code class="literal">PGRES_COPY_OUT</code> + response, the + application should call <a class="xref" href="libpq-async.html#LIBPQ-PQCONSUMEINPUT"><code class="function">PQconsumeInput</code> + </a> and + <a class="xref" href="libpq-copy.html#LIBPQ-PQGETLINEASYNC"><code class="function">PQgetlineAsync</code></a> until the + end-of-data signal is detected. + </p><p> + Unlike <a class="xref" href="libpq-copy.html#LIBPQ-PQGETLINE"><code class="function">PQgetline</code></a>, this function takes + responsibility for detecting end-of-data. + </p><p> + On each call, <a class="xref" href="libpq-copy.html#LIBPQ-PQGETLINEASYNC"><code class="function">PQgetlineAsync</code></a> will return data if a + complete data row is available in <span class="application">libpq</span>'s input buffer. + Otherwise, no data is returned until the rest of the row arrives. + The function returns -1 if the end-of-copy-data marker has been recognized, + or 0 if no data is available, or a positive number giving the number of + bytes of data returned. If -1 is returned, the caller must next call + <a class="xref" href="libpq-copy.html#LIBPQ-PQENDCOPY"><code class="function">PQendcopy</code></a>, and then return to normal processing. + </p><p> + The data returned will not extend beyond a data-row boundary. If possible + a whole row will be returned at one time. But if the buffer offered by + the caller is too small to hold a row sent by the server, then a partial + data row will be returned. With textual data this can be detected by testing + whether the last returned byte is <code class="literal">\n</code> or not. (In a binary + <code class="command">COPY</code>, actual parsing of the <code class="command">COPY</code> data format will be needed to make the + equivalent determination.) + The returned string is not null-terminated. (If you want to add a + terminating null, be sure to pass a <em class="parameter"><code>bufsize</code></em> one smaller + than the room actually available.) + </p></dd><dt id="LIBPQ-PQPUTLINE"><span class="term"><code class="function">PQputline</code><a id="id-1.7.3.17.10.3.3.1.2" class="indexterm"></a></span></dt><dd><p> + Sends a null-terminated string to the server. Returns 0 if + OK and <code class="symbol">EOF</code> if unable to send the string. +</p><pre class="synopsis"> +int PQputline(PGconn *conn, + const char *string); +</pre><p> + </p><p> + The <code class="command">COPY</code> data stream sent by a series of calls + to <a class="xref" href="libpq-copy.html#LIBPQ-PQPUTLINE"><code class="function">PQputline</code></a> has the same format as that + returned by <a class="xref" href="libpq-copy.html#LIBPQ-PQGETLINEASYNC"><code class="function">PQgetlineAsync</code></a>, except that + applications are not obliged to send exactly one data row per + <a class="xref" href="libpq-copy.html#LIBPQ-PQPUTLINE"><code class="function">PQputline</code></a> call; it is okay to send a partial + line or multiple lines per call. + </p><div class="note"><h3 class="title">Note</h3><p> + Before <span class="productname">PostgreSQL</span> protocol 3.0, it was necessary + for the application to explicitly send the two characters + <code class="literal">\.</code> as a final line to indicate to the server that it had + finished sending <code class="command">COPY</code> data. While this still works, it is deprecated and the + special meaning of <code class="literal">\.</code> can be expected to be removed in a + future release. It is sufficient to call <a class="xref" href="libpq-copy.html#LIBPQ-PQENDCOPY"><code class="function">PQendcopy</code></a> after + having sent the actual data. + </p></div></dd><dt id="LIBPQ-PQPUTNBYTES"><span class="term"><code class="function">PQputnbytes</code><a id="id-1.7.3.17.10.3.4.1.2" class="indexterm"></a></span></dt><dd><p> + Sends a non-null-terminated string to the server. Returns + 0 if OK and <code class="symbol">EOF</code> if unable to send the string. +</p><pre class="synopsis"> +int PQputnbytes(PGconn *conn, + const char *buffer, + int nbytes); +</pre><p> + </p><p> + This is exactly like <a class="xref" href="libpq-copy.html#LIBPQ-PQPUTLINE"><code class="function">PQputline</code></a>, except that the data + buffer need not be null-terminated since the number of bytes to send is + specified directly. Use this procedure when sending binary data. + </p></dd><dt id="LIBPQ-PQENDCOPY"><span class="term"><code class="function">PQendcopy</code><a id="id-1.7.3.17.10.3.5.1.2" class="indexterm"></a></span></dt><dd><p> + Synchronizes with the server. +</p><pre class="synopsis"> +int PQendcopy(PGconn *conn); +</pre><p> + This function waits until the server has finished the copying. + It should either be issued when the last string has been sent + to the server using <a class="xref" href="libpq-copy.html#LIBPQ-PQPUTLINE"><code class="function">PQputline</code></a> or when the + last string has been received from the server using + <code class="function">PQgetline</code>. It must be issued or the server + will get <span class="quote">“<span class="quote">out of sync</span>”</span> with the client. Upon return + from this function, the server is ready to receive the next SQL + command. The return value is 0 on successful completion, + nonzero otherwise. (Use <a class="xref" href="libpq-status.html#LIBPQ-PQERRORMESSAGE"><code class="function">PQerrorMessage</code></a> to + retrieve details if the return value is nonzero.) + </p><p> + When using <a class="xref" href="libpq-async.html#LIBPQ-PQGETRESULT"><code class="function">PQgetResult</code></a>, the application should + respond to a <code class="literal">PGRES_COPY_OUT</code> result by executing + <a class="xref" href="libpq-copy.html#LIBPQ-PQGETLINE"><code class="function">PQgetline</code></a> repeatedly, followed by + <a class="xref" href="libpq-copy.html#LIBPQ-PQENDCOPY"><code class="function">PQendcopy</code></a> after the terminator line is seen. + It should then return to the <a class="xref" href="libpq-async.html#LIBPQ-PQGETRESULT"><code class="function">PQgetResult</code></a> loop + until <a class="xref" href="libpq-async.html#LIBPQ-PQGETRESULT"><code class="function">PQgetResult</code></a> returns a null pointer. + Similarly a <code class="literal">PGRES_COPY_IN</code> result is processed + by a series of <a class="xref" href="libpq-copy.html#LIBPQ-PQPUTLINE"><code class="function">PQputline</code></a> calls followed by + <a class="xref" href="libpq-copy.html#LIBPQ-PQENDCOPY"><code class="function">PQendcopy</code></a>, then return to the + <a class="xref" href="libpq-async.html#LIBPQ-PQGETRESULT"><code class="function">PQgetResult</code></a> loop. This arrangement will + ensure that a <code class="command">COPY</code> command embedded in a series + of <acronym class="acronym">SQL</acronym> commands will be executed correctly. + </p><p> + Older applications are likely to submit a <code class="command">COPY</code> + via <a class="xref" href="libpq-exec.html#LIBPQ-PQEXEC"><code class="function">PQexec</code></a> and assume that the transaction + is done after <a class="xref" href="libpq-copy.html#LIBPQ-PQENDCOPY"><code class="function">PQendcopy</code></a>. This will work + correctly only if the <code class="command">COPY</code> is the only + <acronym class="acronym">SQL</acronym> command in the command string. + </p></dd></dl></div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="libpq-notify.html" title="34.9. Asynchronous Notification">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="libpq.html" title="Chapter 34. libpq — C Library">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="libpq-control.html" title="34.11. Control Functions">Next</a></td></tr><tr><td width="40%" align="left" valign="top">34.9. Asynchronous Notification </td><td width="20%" align="center"><a accesskey="h" href="index.html" title="PostgreSQL 15.5 Documentation">Home</a></td><td width="40%" align="right" valign="top"> 34.11. Control Functions</td></tr></table></div></body></html>
\ No newline at end of file |