Commit b05d3ae1 authored by Tom Lane's avatar Tom Lane

Error message editing in backend/libpq, backend/postmaster, backend/tcop.

Along the way, fix some logic problems in pgstat_initstats, notably the
bogus assumption that malloc returns zeroed memory.
parent 277dbb0c
<!-- <!--
$Header: /cvsroot/pgsql/doc/src/sgml/sources.sgml,v 2.9 2003/07/18 23:20:32 tgl Exp $ $Header: /cvsroot/pgsql/doc/src/sgml/sources.sgml,v 2.10 2003/07/22 19:00:07 tgl Exp $
--> -->
<chapter id="source"> <chapter id="source">
...@@ -234,6 +234,13 @@ less -x4 ...@@ -234,6 +234,13 @@ less -x4
primary error message text. primary error message text.
</para> </para>
</listitem> </listitem>
<listitem>
<para>
<function>errcode_for_socket_access</>() is a convenience function that
selects an appropriate SQLSTATE error identifier for a failure in a
socket-related system call.
</para>
</listitem>
</itemizedlist> </itemizedlist>
</para> </para>
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/alter.c,v 1.2 2003/07/20 21:56:32 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/alter.c,v 1.3 2003/07/22 19:00:07 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -29,41 +29,12 @@ ...@@ -29,41 +29,12 @@
#include "commands/user.h" #include "commands/user.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "parser/parse_clause.h" #include "parser/parse_clause.h"
#include "tcop/utility.h"
#include "utils/acl.h" #include "utils/acl.h"
#include "utils/lsyscache.h" #include "utils/lsyscache.h"
#include "utils/syscache.h" #include "utils/syscache.h"
static void
CheckOwnership(RangeVar *rel, bool noCatalogs)
{
Oid relOid;
HeapTuple tuple;
relOid = RangeVarGetRelid(rel, false);
tuple = SearchSysCache(RELOID,
ObjectIdGetDatum(relOid),
0, 0, 0);
if (!HeapTupleIsValid(tuple)) /* should not happen */
elog(ERROR, "cache lookup failed for relation %u", relOid);
if (!pg_class_ownercheck(relOid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, rel->relname);
if (noCatalogs)
{
if (!allowSystemTableMods &&
IsSystemClass((Form_pg_class) GETSTRUCT(tuple)))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("relation \"%s\" is a system catalog",
rel->relname)));
}
ReleaseSysCache(tuple);
}
void void
ExecRenameStmt(RenameStmt *stmt) ExecRenameStmt(RenameStmt *stmt)
{ {
...@@ -111,7 +82,7 @@ ExecRenameStmt(RenameStmt *stmt) ...@@ -111,7 +82,7 @@ ExecRenameStmt(RenameStmt *stmt)
{ {
Oid relid; Oid relid;
CheckOwnership(stmt->relation, true); CheckRelationOwnership(stmt->relation, true);
relid = RangeVarGetRelid(stmt->relation, false); relid = RangeVarGetRelid(stmt->relation, false);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.203 2003/07/21 17:04:58 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.204 2003/07/22 19:00:07 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1923,7 +1923,7 @@ CopyReadBinaryAttribute(int column_no, FmgrInfo *flinfo, Oid typelem, ...@@ -1923,7 +1923,7 @@ CopyReadBinaryAttribute(int column_no, FmgrInfo *flinfo, Oid typelem,
/* Trouble if it didn't eat the whole buffer */ /* Trouble if it didn't eat the whole buffer */
if (attribute_buf.cursor != attribute_buf.len) if (attribute_buf.cursor != attribute_buf.len)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
errmsg("incorrect binary data format in field %d", errmsg("incorrect binary data format in field %d",
column_no))); column_no)));
......
This diff is collapsed.
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/libpq/be-fsstubs.c,v 1.64 2003/05/27 17:49:46 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/libpq/be-fsstubs.c,v 1.65 2003/07/22 19:00:10 tgl Exp $
* *
* NOTES * NOTES
* This should be moved to a more appropriate place. It is here * This should be moved to a more appropriate place. It is here
...@@ -119,7 +119,9 @@ lo_close(PG_FUNCTION_ARGS) ...@@ -119,7 +119,9 @@ lo_close(PG_FUNCTION_ARGS)
if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL) if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL)
{ {
elog(ERROR, "lo_close: invalid large obj descriptor (%d)", fd); ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("invalid large-object descriptor: %d", fd)));
PG_RETURN_INT32(-1); PG_RETURN_INT32(-1);
} }
#if FSDB #if FSDB
...@@ -155,7 +157,9 @@ lo_read(int fd, char *buf, int len) ...@@ -155,7 +157,9 @@ lo_read(int fd, char *buf, int len)
if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL) if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL)
{ {
elog(ERROR, "lo_read: invalid large obj descriptor (%d)", fd); ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("invalid large-object descriptor: %d", fd)));
return -1; return -1;
} }
...@@ -177,7 +181,9 @@ lo_write(int fd, char *buf, int len) ...@@ -177,7 +181,9 @@ lo_write(int fd, char *buf, int len)
if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL) if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL)
{ {
elog(ERROR, "lo_write: invalid large obj descriptor (%d)", fd); ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("invalid large-object descriptor: %d", fd)));
return -1; return -1;
} }
...@@ -203,7 +209,9 @@ lo_lseek(PG_FUNCTION_ARGS) ...@@ -203,7 +209,9 @@ lo_lseek(PG_FUNCTION_ARGS)
if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL) if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL)
{ {
elog(ERROR, "lo_lseek: invalid large obj descriptor (%d)", fd); ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("invalid large-object descriptor: %d", fd)));
PG_RETURN_INT32(-1); PG_RETURN_INT32(-1);
} }
...@@ -258,7 +266,9 @@ lo_tell(PG_FUNCTION_ARGS) ...@@ -258,7 +266,9 @@ lo_tell(PG_FUNCTION_ARGS)
if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL) if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL)
{ {
elog(ERROR, "lo_tell: invalid large object descriptor (%d)", fd); ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("invalid large-object descriptor: %d", fd)));
PG_RETURN_INT32(-1); PG_RETURN_INT32(-1);
} }
...@@ -360,9 +370,10 @@ lo_import(PG_FUNCTION_ARGS) ...@@ -360,9 +370,10 @@ lo_import(PG_FUNCTION_ARGS)
#ifndef ALLOW_DANGEROUS_LO_FUNCTIONS #ifndef ALLOW_DANGEROUS_LO_FUNCTIONS
if (!superuser()) if (!superuser())
elog(ERROR, "You must have Postgres superuser privilege to use " ereport(ERROR,
"server-side lo_import().\n\tAnyone can use the " (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
"client-side lo_import() provided by libpq."); errmsg("must be superuser to use server-side lo_import()"),
errhint("Anyone can use the client-side lo_import() provided by libpq.")));
#endif #endif
/* /*
...@@ -375,16 +386,15 @@ lo_import(PG_FUNCTION_ARGS) ...@@ -375,16 +386,15 @@ lo_import(PG_FUNCTION_ARGS)
fnamebuf[nbytes] = '\0'; fnamebuf[nbytes] = '\0';
fd = PathNameOpenFile(fnamebuf, O_RDONLY | PG_BINARY, 0666); fd = PathNameOpenFile(fnamebuf, O_RDONLY | PG_BINARY, 0666);
if (fd < 0) if (fd < 0)
elog(ERROR, "lo_import: can't open unix file \"%s\": %m", ereport(ERROR,
fnamebuf); (errcode_for_file_access(),
errmsg("could not open server file \"%s\": %m",
fnamebuf)));
/* /*
* create an inversion "object" * create an inversion object
*/ */
lobj = inv_create(INV_READ | INV_WRITE); lobj = inv_create(INV_READ | INV_WRITE);
if (lobj == NULL)
elog(ERROR, "lo_import: can't create inv object for \"%s\"",
fnamebuf);
lobjOid = lobj->id; lobjOid = lobj->id;
/* /*
...@@ -393,11 +403,15 @@ lo_import(PG_FUNCTION_ARGS) ...@@ -393,11 +403,15 @@ lo_import(PG_FUNCTION_ARGS)
while ((nbytes = FileRead(fd, buf, BUFSIZE)) > 0) while ((nbytes = FileRead(fd, buf, BUFSIZE)) > 0)
{ {
tmp = inv_write(lobj, buf, nbytes); tmp = inv_write(lobj, buf, nbytes);
if (tmp != nbytes) Assert(tmp == nbytes);
elog(ERROR, "lo_import: error while reading \"%s\"",
fnamebuf);
} }
if (nbytes < 0)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not read server file \"%s\": %m",
fnamebuf)));
FileClose(fd); FileClose(fd);
inv_close(lobj); inv_close(lobj);
...@@ -423,17 +437,16 @@ lo_export(PG_FUNCTION_ARGS) ...@@ -423,17 +437,16 @@ lo_export(PG_FUNCTION_ARGS)
#ifndef ALLOW_DANGEROUS_LO_FUNCTIONS #ifndef ALLOW_DANGEROUS_LO_FUNCTIONS
if (!superuser()) if (!superuser())
elog(ERROR, "You must have Postgres superuser privilege to use " ereport(ERROR,
"server-side lo_export().\n\tAnyone can use the " (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
"client-side lo_export() provided by libpq."); errmsg("must be superuser to use server-side lo_export()"),
errhint("Anyone can use the client-side lo_export() provided by libpq.")));
#endif #endif
/* /*
* open the inversion "object" * open the inversion object (no need to test for failure)
*/ */
lobj = inv_open(lobjId, INV_READ); lobj = inv_open(lobjId, INV_READ);
if (lobj == NULL)
elog(ERROR, "lo_export: can't open inv object %u", lobjId);
/* /*
* open the file to be written to * open the file to be written to
...@@ -451,8 +464,10 @@ lo_export(PG_FUNCTION_ARGS) ...@@ -451,8 +464,10 @@ lo_export(PG_FUNCTION_ARGS)
fd = PathNameOpenFile(fnamebuf, O_CREAT | O_WRONLY | O_TRUNC | PG_BINARY, 0666); fd = PathNameOpenFile(fnamebuf, O_CREAT | O_WRONLY | O_TRUNC | PG_BINARY, 0666);
umask(oumask); umask(oumask);
if (fd < 0) if (fd < 0)
elog(ERROR, "lo_export: can't open unix file \"%s\": %m", ereport(ERROR,
fnamebuf); (errcode_for_file_access(),
errmsg("could not create server file \"%s\": %m",
fnamebuf)));
/* /*
* read in from the inversion file and write to the Unix file * read in from the inversion file and write to the Unix file
...@@ -461,12 +476,14 @@ lo_export(PG_FUNCTION_ARGS) ...@@ -461,12 +476,14 @@ lo_export(PG_FUNCTION_ARGS)
{ {
tmp = FileWrite(fd, buf, nbytes); tmp = FileWrite(fd, buf, nbytes);
if (tmp != nbytes) if (tmp != nbytes)
elog(ERROR, "lo_export: error while writing \"%s\"", ereport(ERROR,
fnamebuf); (errcode_for_file_access(),
errmsg("could not write server file \"%s\": %m",
fnamebuf)));
} }
inv_close(lobj);
FileClose(fd); FileClose(fd);
inv_close(lobj);
PG_RETURN_INT32(1); PG_RETURN_INT32(1);
} }
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/libpq/be-secure.c,v 1.35 2003/07/01 13:49:47 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/libpq/be-secure.c,v 1.36 2003/07/22 19:00:10 tgl Exp $
* *
* Since the server static private key ($DataDir/server.key) * Since the server static private key ($DataDir/server.key)
* will normally be stored unencrypted so that the database * will normally be stored unencrypted so that the database
...@@ -277,12 +277,18 @@ secure_read(Port *port, void *ptr, size_t len) ...@@ -277,12 +277,18 @@ secure_read(Port *port, void *ptr, size_t len)
goto rloop; goto rloop;
case SSL_ERROR_SYSCALL: case SSL_ERROR_SYSCALL:
if (n == -1) if (n == -1)
elog(COMMERROR, "SSL SYSCALL error: %m"); ereport(COMMERROR,
(errcode_for_socket_access(),
errmsg("SSL SYSCALL error: %m")));
else else
elog(COMMERROR, "SSL SYSCALL error: EOF detected"); ereport(COMMERROR,
(errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("SSL SYSCALL error: EOF detected")));
break; break;
case SSL_ERROR_SSL: case SSL_ERROR_SSL:
elog(COMMERROR, "SSL error: %s", SSLerrmessage()); ereport(COMMERROR,
(errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("SSL error: %s", SSLerrmessage())));
/* fall through */ /* fall through */
case SSL_ERROR_ZERO_RETURN: case SSL_ERROR_ZERO_RETURN:
secure_close(port); secure_close(port);
...@@ -290,7 +296,9 @@ secure_read(Port *port, void *ptr, size_t len) ...@@ -290,7 +296,9 @@ secure_read(Port *port, void *ptr, size_t len)
n = -1; n = -1;
break; break;
default: default:
elog(COMMERROR, "Unknown SSL error code"); ereport(COMMERROR,
(errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("unrecognized SSL error code")));
break; break;
} }
} }
...@@ -317,15 +325,23 @@ secure_write(Port *port, void *ptr, size_t len) ...@@ -317,15 +325,23 @@ secure_write(Port *port, void *ptr, size_t len)
SSL_set_session_id_context(port->ssl, (void *) &SSL_context, SSL_set_session_id_context(port->ssl, (void *) &SSL_context,
sizeof(SSL_context)); sizeof(SSL_context));
if (SSL_renegotiate(port->ssl) <= 0) if (SSL_renegotiate(port->ssl) <= 0)
elog(COMMERROR, "SSL renegotiation failure"); ereport(COMMERROR,
(errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("SSL renegotiation failure")));
if (SSL_do_handshake(port->ssl) <= 0) if (SSL_do_handshake(port->ssl) <= 0)
elog(COMMERROR, "SSL renegotiation failure"); ereport(COMMERROR,
(errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("SSL renegotiation failure")));
if (port->ssl->state != SSL_ST_OK) if (port->ssl->state != SSL_ST_OK)
elog(COMMERROR, "SSL failed to send renegotiation request"); ereport(COMMERROR,
(errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("SSL failed to send renegotiation request")));
port->ssl->state |= SSL_ST_ACCEPT; port->ssl->state |= SSL_ST_ACCEPT;
SSL_do_handshake(port->ssl); SSL_do_handshake(port->ssl);
if (port->ssl->state != SSL_ST_OK) if (port->ssl->state != SSL_ST_OK)
elog(COMMERROR, "SSL renegotiation failure"); ereport(COMMERROR,
(errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("SSL renegotiation failure")));
port->count = 0; port->count = 0;
} }
...@@ -341,12 +357,18 @@ secure_write(Port *port, void *ptr, size_t len) ...@@ -341,12 +357,18 @@ secure_write(Port *port, void *ptr, size_t len)
goto wloop; goto wloop;
case SSL_ERROR_SYSCALL: case SSL_ERROR_SYSCALL:
if (n == -1) if (n == -1)
elog(COMMERROR, "SSL SYSCALL error: %m"); ereport(COMMERROR,
(errcode_for_socket_access(),
errmsg("SSL SYSCALL error: %m")));
else else
elog(COMMERROR, "SSL SYSCALL error: EOF detected"); ereport(COMMERROR,
(errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("SSL SYSCALL error: EOF detected")));
break; break;
case SSL_ERROR_SSL: case SSL_ERROR_SSL:
elog(COMMERROR, "SSL error: %s", SSLerrmessage()); ereport(COMMERROR,
(errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("SSL error: %s", SSLerrmessage())));
/* fall through */ /* fall through */
case SSL_ERROR_ZERO_RETURN: case SSL_ERROR_ZERO_RETURN:
secure_close(port); secure_close(port);
...@@ -354,7 +376,9 @@ secure_write(Port *port, void *ptr, size_t len) ...@@ -354,7 +376,9 @@ secure_write(Port *port, void *ptr, size_t len)
n = -1; n = -1;
break; break;
default: default:
elog(COMMERROR, "Unknown SSL error code"); ereport(COMMERROR,
(errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("unrecognized SSL error code")));
break; break;
} }
} }
...@@ -419,7 +443,7 @@ load_dh_file(int keylength) ...@@ -419,7 +443,7 @@ load_dh_file(int keylength)
(codes & DH_CHECK_P_NOT_SAFE_PRIME)) (codes & DH_CHECK_P_NOT_SAFE_PRIME))
{ {
elog(LOG, elog(LOG,
"DH error (%s): neither suitable generator or safe prime", "DH error (%s): neither suitable generator or safe prime",
fnbuf); fnbuf);
return NULL; return NULL;
} }
...@@ -690,7 +714,10 @@ open_server_SSL(Port *port) ...@@ -690,7 +714,10 @@ open_server_SSL(Port *port)
!SSL_set_fd(port->ssl, port->sock) || !SSL_set_fd(port->ssl, port->sock) ||
SSL_accept(port->ssl) <= 0) SSL_accept(port->ssl) <= 0)
{ {
elog(COMMERROR, "failed to initialize SSL connection: %s", SSLerrmessage()); ereport(COMMERROR,
(errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("failed to initialize SSL connection: %s",
SSLerrmessage())));
close_SSL(port); close_SSL(port);
return -1; return -1;
} }
...@@ -712,7 +739,7 @@ open_server_SSL(Port *port) ...@@ -712,7 +739,7 @@ open_server_SSL(Port *port)
NID_commonName, port->peer_cn, sizeof(port->peer_cn)); NID_commonName, port->peer_cn, sizeof(port->peer_cn));
port->peer_cn[sizeof(port->peer_cn) - 1] = '\0'; port->peer_cn[sizeof(port->peer_cn) - 1] = '\0';
} }
elog(DEBUG2, "secure connection from '%s'", port->peer_cn); elog(DEBUG2, "secure connection from \"%s\"", port->peer_cn);
/* set up debugging/info callback */ /* set up debugging/info callback */
SSL_CTX_set_info_callback(SSL_context, info_cb); SSL_CTX_set_info_callback(SSL_context, info_cb);
......
...@@ -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
* *
* $Header: /cvsroot/pgsql/src/backend/libpq/crypt.c,v 1.53 2003/05/12 23:08:50 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/libpq/crypt.c,v 1.54 2003/07/22 19:00:10 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -58,8 +58,8 @@ md5_crypt_verify(const Port *port, const char *user, char *client_pass) ...@@ -58,8 +58,8 @@ md5_crypt_verify(const Port *port, const char *user, char *client_pass)
/* We can't do crypt with pg_shadow MD5 passwords */ /* We can't do crypt with pg_shadow MD5 passwords */
if (isMD5(shadow_pass) && port->auth_method == uaCrypt) if (isMD5(shadow_pass) && port->auth_method == uaCrypt)
{ {
elog(LOG, "Password is stored MD5 encrypted. " ereport(LOG,
"'crypt' auth method cannot be used."); (errmsg("cannot use CRYPT auth method because password is MD5-encrypted")));
return STATUS_ERROR; return STATUS_ERROR;
} }
......
This diff is collapsed.
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* Unfortunately, COPY OUT was designed to commandeer the communication * Unfortunately, COPY OUT was designed to commandeer the communication
* channel (it just transfers data without wrapping it into messages). * channel (it just transfers data without wrapping it into messages).
* No other messages can be sent while COPY OUT is in progress; and if the * No other messages can be sent while COPY OUT is in progress; and if the
* copy is aborted by an elog(ERROR), we need to close out the copy so that * copy is aborted by an ereport(ERROR), we need to close out the copy so that
* the frontend gets back into sync. Therefore, these routines have to be * the frontend gets back into sync. Therefore, these routines have to be
* aware of COPY OUT state. (New COPY-OUT is message-based and does *not* * aware of COPY OUT state. (New COPY-OUT is message-based and does *not*
* set the DoingCopyOut flag.) * set the DoingCopyOut flag.)
...@@ -20,8 +20,8 @@ ...@@ -20,8 +20,8 @@
* to send. Instead, use the routines in pqformat.c to construct the message * to send. Instead, use the routines in pqformat.c to construct the message
* in a buffer and then emit it in one call to pq_putmessage. This ensures * in a buffer and then emit it in one call to pq_putmessage. This ensures
* that the channel will not be clogged by an incomplete message if execution * that the channel will not be clogged by an incomplete message if execution
* is aborted by elog(ERROR) partway through the message. The only non-libpq * is aborted by ereport(ERROR) partway through the message. The only
* code that should call pq_putbytes directly is old-style COPY OUT. * non-libpq code that should call pq_putbytes directly is old-style COPY OUT.
* *
* At one time, libpq was shared between frontend and backend, but now * At one time, libpq was shared between frontend and backend, but now
* the backend's "backend/libpq" is quite separate from "interfaces/libpq". * the backend's "backend/libpq" is quite separate from "interfaces/libpq".
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,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
* *
* $Header: /cvsroot/pgsql/src/backend/libpq/pqcomm.c,v 1.157 2003/06/12 07:36:51 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/libpq/pqcomm.c,v 1.158 2003/07/22 19:00:10 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -237,8 +237,9 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber, ...@@ -237,8 +237,9 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber,
ret = getaddrinfo2(hostName, service, &hint, &addrs); ret = getaddrinfo2(hostName, service, &hint, &addrs);
if (ret || addrs == NULL) if (ret || addrs == NULL)
{ {
elog(LOG, "server socket failure: getaddrinfo2(): %s", ereport(LOG,
gai_strerror(ret)); (errmsg("failed to translate hostname to address: %s",
gai_strerror(ret))));
freeaddrinfo2(hint.ai_family, addrs); freeaddrinfo2(hint.ai_family, addrs);
return STATUS_ERROR; return STATUS_ERROR;
} }
...@@ -269,8 +270,9 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber, ...@@ -269,8 +270,9 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber,
if ((fd = socket(addr->ai_family, addr->ai_socktype, if ((fd = socket(addr->ai_family, addr->ai_socktype,
addr->ai_protocol)) < 0) addr->ai_protocol)) < 0)
{ {
elog(LOG, "server socket failure: socket(): %s", ereport(LOG,
strerror(errno)); (errcode_for_socket_access(),
errmsg("failed to create socket: %m")));
continue; continue;
} }
...@@ -281,9 +283,9 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber, ...@@ -281,9 +283,9 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber,
if ((setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, if ((setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
(char *) &one, sizeof(one))) == -1) (char *) &one, sizeof(one))) == -1)
{ {
elog(LOG, "server socket failure: " ereport(LOG,
"setsockopt(SO_REUSEADDR): %s", (errcode_for_socket_access(),
strerror(errno)); errmsg("setsockopt(SO_REUSEADDR) failed: %m")));
closesocket(fd); closesocket(fd);
continue; continue;
} }
...@@ -295,9 +297,9 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber, ...@@ -295,9 +297,9 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber,
if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY,
(char *)&one, sizeof(one)) == -1) (char *)&one, sizeof(one)) == -1)
{ {
elog(LOG, "server socket failure: " ereport(LOG,
"setsockopt(IPV6_V6ONLY): %s", (errcode_for_socket_access(),
strerror(errno)); errmsg("setsockopt(IPV6_V6ONLY) failed: %m")));
closesocket(fd); closesocket(fd);
continue; continue;
} }
...@@ -313,19 +315,16 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber, ...@@ -313,19 +315,16 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber,
err = bind(fd, addr->ai_addr, addr->ai_addrlen); err = bind(fd, addr->ai_addr, addr->ai_addrlen);
if (err < 0) if (err < 0)
{ {
elog(LOG, "server socket failure: bind(): %s\n" ereport(LOG,
"\tIs another postmaster already running on " (errcode_for_socket_access(),
"port %d?", strerror(errno), (int) portNumber); errmsg("failed to bind server socket: %m"),
if (addr->ai_family == AF_UNIX) (addr->ai_family == AF_UNIX) ?
{ errhint("Is another postmaster already running on port %d?"
elog(LOG, "\tIf not, remove socket node (%s) " " If not, remove socket node \"%s\" and retry.",
"and retry.", sock_path); (int) portNumber, sock_path) :
} errhint("Is another postmaster already running on port %d?"
else " If not, wait a few seconds and retry.",
{ (int) portNumber)));
elog(LOG, "\tIf not, wait a few seconds and "
"retry.");
}
closesocket(fd); closesocket(fd);
continue; continue;
} }
...@@ -354,8 +353,9 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber, ...@@ -354,8 +353,9 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber,
err = listen(fd, maxconn); err = listen(fd, maxconn);
if (err < 0) if (err < 0)
{ {
elog(LOG, "server socket failure: listen(): %s", ereport(LOG,
strerror(errno)); (errcode_for_socket_access(),
errmsg("failed to listen on server socket: %m")));
closesocket(fd); closesocket(fd);
continue; continue;
} }
...@@ -417,7 +417,7 @@ Setup_AF_UNIX(void) ...@@ -417,7 +417,7 @@ Setup_AF_UNIX(void)
if (Unix_socket_group[0] != '\0') if (Unix_socket_group[0] != '\0')
{ {
#ifdef WIN32 #ifdef WIN32
elog(FATAL, "Config value 'unix_socket_group' not supported on this platform"); elog(WARNING, "configuration item unix_socket_group is not supported on this platform");
#else #else
char *endptr; char *endptr;
unsigned long int val; unsigned long int val;
...@@ -435,16 +435,19 @@ Setup_AF_UNIX(void) ...@@ -435,16 +435,19 @@ Setup_AF_UNIX(void)
gr = getgrnam(Unix_socket_group); gr = getgrnam(Unix_socket_group);
if (!gr) if (!gr)
{ {
elog(LOG, "server socket failure: no such group '%s'", ereport(LOG,
Unix_socket_group); (errmsg("group \"%s\" does not exist",
Unix_socket_group)));
return STATUS_ERROR; return STATUS_ERROR;
} }
gid = gr->gr_gid; gid = gr->gr_gid;
} }
if (chown(sock_path, -1, gid) == -1) if (chown(sock_path, -1, gid) == -1)
{ {
elog(LOG, "server socket failure: could not set group of %s: %s", ereport(LOG,
sock_path, strerror(errno)); (errcode_for_file_access(),
errmsg("could not set group of \"%s\": %m",
sock_path)));
return STATUS_ERROR; return STATUS_ERROR;
} }
#endif #endif
...@@ -452,8 +455,10 @@ Setup_AF_UNIX(void) ...@@ -452,8 +455,10 @@ Setup_AF_UNIX(void)
if (chmod(sock_path, Unix_socket_permissions) == -1) if (chmod(sock_path, Unix_socket_permissions) == -1)
{ {
elog(LOG, "server socket failure: could not set permissions on %s: %s", ereport(LOG,
sock_path, strerror(errno)); (errcode_for_file_access(),
errmsg("could not set permissions of \"%s\": %m",
sock_path)));
return STATUS_ERROR; return STATUS_ERROR;
} }
return STATUS_OK; return STATUS_OK;
...@@ -475,13 +480,15 @@ Setup_AF_UNIX(void) ...@@ -475,13 +480,15 @@ Setup_AF_UNIX(void)
int int
StreamConnection(int server_fd, Port *port) StreamConnection(int server_fd, Port *port)
{ {
/* accept connection (and fill in the client (remote) address) */ /* accept connection and fill in the client (remote) address */
port->raddr.salen = sizeof(port->raddr.addr); port->raddr.salen = sizeof(port->raddr.addr);
if ((port->sock = accept(server_fd, if ((port->sock = accept(server_fd,
(struct sockaddr *) &port->raddr.addr, (struct sockaddr *) &port->raddr.addr,
&port->raddr.salen)) < 0) &port->raddr.salen)) < 0)
{ {
elog(LOG, "StreamConnection: accept() failed: %m"); ereport(LOG,
(errcode_for_socket_access(),
errmsg("could not accept new connection: %m")));
return STATUS_ERROR; return STATUS_ERROR;
} }
...@@ -496,30 +503,33 @@ StreamConnection(int server_fd, Port *port) ...@@ -496,30 +503,33 @@ StreamConnection(int server_fd, Port *port)
/* fill in the server (local) address */ /* fill in the server (local) address */
port->laddr.salen = sizeof(port->laddr.addr); port->laddr.salen = sizeof(port->laddr.addr);
if (getsockname(port->sock, (struct sockaddr *) & port->laddr.addr, if (getsockname(port->sock,
(struct sockaddr *) & port->laddr.addr,
&port->laddr.salen) < 0) &port->laddr.salen) < 0)
{ {
elog(LOG, "StreamConnection: getsockname() failed: %m"); elog(LOG, "getsockname() failed: %m");
return STATUS_ERROR; return STATUS_ERROR;
} }
/* select NODELAY and KEEPALIVE options if it's a TCP connection */ /* select NODELAY and KEEPALIVE options if it's a TCP connection */
if (!IS_AF_UNIX(port->laddr.addr.ss_family)) if (!IS_AF_UNIX(port->laddr.addr.ss_family))
{ {
int on = 1; int on;
#ifdef TCP_NODELAY #ifdef TCP_NODELAY
on = 1;
if (setsockopt(port->sock, IPPROTO_TCP, TCP_NODELAY, if (setsockopt(port->sock, IPPROTO_TCP, TCP_NODELAY,
(char *) &on, sizeof(on)) < 0) (char *) &on, sizeof(on)) < 0)
{ {
elog(LOG, "StreamConnection: setsockopt(TCP_NODELAY) failed: %m"); elog(LOG, "setsockopt(TCP_NODELAY) failed: %m");
return STATUS_ERROR; return STATUS_ERROR;
} }
#endif #endif
on = 1;
if (setsockopt(port->sock, SOL_SOCKET, SO_KEEPALIVE, if (setsockopt(port->sock, SOL_SOCKET, SO_KEEPALIVE,
(char *) &on, sizeof(on)) < 0) (char *) &on, sizeof(on)) < 0)
{ {
elog(LOG, "StreamConnection: setsockopt(SO_KEEPALIVE) failed: %m"); elog(LOG, "setsockopt(SO_KEEPALIVE) failed: %m");
return STATUS_ERROR; return STATUS_ERROR;
} }
} }
...@@ -622,11 +632,13 @@ pq_recvbuf(void) ...@@ -622,11 +632,13 @@ pq_recvbuf(void)
continue; /* Ok if interrupted */ continue; /* Ok if interrupted */
/* /*
* Careful: an elog() that tries to write to the client would * Careful: an ereport() that tries to write to the client would
* cause recursion to here, leading to stack overflow and core * cause recursion to here, leading to stack overflow and core
* dump! This message must go *only* to the postmaster log. * dump! This message must go *only* to the postmaster log.
*/ */
elog(COMMERROR, "pq_recvbuf: recv() failed: %m"); ereport(COMMERROR,
(errcode_for_socket_access(),
errmsg("could not receive data from client: %m")));
return EOF; return EOF;
} }
if (r == 0) if (r == 0)
...@@ -787,7 +799,9 @@ pq_getmessage(StringInfo s, int maxlen) ...@@ -787,7 +799,9 @@ pq_getmessage(StringInfo s, int maxlen)
/* Read message length word */ /* Read message length word */
if (pq_getbytes((char *) &len, 4) == EOF) if (pq_getbytes((char *) &len, 4) == EOF)
{ {
elog(COMMERROR, "unexpected EOF within message length word"); ereport(COMMERROR,
(errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("unexpected EOF within message length word")));
return EOF; return EOF;
} }
...@@ -797,7 +811,9 @@ pq_getmessage(StringInfo s, int maxlen) ...@@ -797,7 +811,9 @@ pq_getmessage(StringInfo s, int maxlen)
if (len < 0 || if (len < 0 ||
(maxlen > 0 && len > maxlen)) (maxlen > 0 && len > maxlen))
{ {
elog(COMMERROR, "invalid message length"); ereport(COMMERROR,
(errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("invalid message length")));
return EOF; return EOF;
} }
...@@ -809,7 +825,9 @@ pq_getmessage(StringInfo s, int maxlen) ...@@ -809,7 +825,9 @@ pq_getmessage(StringInfo s, int maxlen)
/* And grab the message */ /* And grab the message */
if (pq_getbytes(s->data, len) == EOF) if (pq_getbytes(s->data, len) == EOF)
{ {
elog(COMMERROR, "incomplete client message"); ereport(COMMERROR,
(errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("incomplete message from client")));
return EOF; return EOF;
} }
s->len = len; s->len = len;
...@@ -874,7 +892,7 @@ pq_flush(void) ...@@ -874,7 +892,7 @@ pq_flush(void)
continue; /* Ok if we were interrupted */ continue; /* Ok if we were interrupted */
/* /*
* Careful: an elog() that tries to write to the client would * Careful: an ereport() that tries to write to the client would
* cause recursion to here, leading to stack overflow and core * cause recursion to here, leading to stack overflow and core
* dump! This message must go *only* to the postmaster log. * dump! This message must go *only* to the postmaster log.
* *
...@@ -885,7 +903,9 @@ pq_flush(void) ...@@ -885,7 +903,9 @@ pq_flush(void)
if (errno != last_reported_send_errno) if (errno != last_reported_send_errno)
{ {
last_reported_send_errno = errno; last_reported_send_errno = errno;
elog(COMMERROR, "pq_flush: send() failed: %m"); ereport(COMMERROR,
(errcode_for_socket_access(),
errmsg("could not send data to client: %m")));
} }
/* /*
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,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
* *
* $Header: /cvsroot/pgsql/src/backend/libpq/pqformat.c,v 1.31 2003/05/09 21:19:49 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/libpq/pqformat.c,v 1.32 2003/07/22 19:00:10 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -231,7 +231,7 @@ pq_sendint(StringInfo buf, int i, int b) ...@@ -231,7 +231,7 @@ pq_sendint(StringInfo buf, int i, int b)
appendBinaryStringInfo(buf, (char *) &n32, 4); appendBinaryStringInfo(buf, (char *) &n32, 4);
break; break;
default: default:
elog(ERROR, "pq_sendint: unsupported size %d", b); elog(ERROR, "unsupported integer size %d", b);
break; break;
} }
} }
...@@ -440,7 +440,9 @@ int ...@@ -440,7 +440,9 @@ int
pq_getmsgbyte(StringInfo msg) pq_getmsgbyte(StringInfo msg)
{ {
if (msg->cursor >= msg->len) if (msg->cursor >= msg->len)
elog(ERROR, "pq_getmsgbyte: no data left in message"); ereport(ERROR,
(errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("no data left in message")));
return (unsigned char) msg->data[msg->cursor++]; return (unsigned char) msg->data[msg->cursor++];
} }
...@@ -473,7 +475,7 @@ pq_getmsgint(StringInfo msg, int b) ...@@ -473,7 +475,7 @@ pq_getmsgint(StringInfo msg, int b)
result = ntohl(n32); result = ntohl(n32);
break; break;
default: default:
elog(ERROR, "pq_getmsgint: unsupported size %d", b); elog(ERROR, "unsupported integer size %d", b);
result = 0; /* keep compiler quiet */ result = 0; /* keep compiler quiet */
break; break;
} }
...@@ -586,7 +588,9 @@ pq_getmsgbytes(StringInfo msg, int datalen) ...@@ -586,7 +588,9 @@ pq_getmsgbytes(StringInfo msg, int datalen)
const char *result; const char *result;
if (datalen < 0 || datalen > (msg->len - msg->cursor)) if (datalen < 0 || datalen > (msg->len - msg->cursor))
elog(ERROR, "pq_getmsgbytes: insufficient data left in message"); ereport(ERROR,
(errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("insufficient data left in message")));
result = &msg->data[msg->cursor]; result = &msg->data[msg->cursor];
msg->cursor += datalen; msg->cursor += datalen;
return result; return result;
...@@ -602,7 +606,9 @@ void ...@@ -602,7 +606,9 @@ void
pq_copymsgbytes(StringInfo msg, char *buf, int datalen) pq_copymsgbytes(StringInfo msg, char *buf, int datalen)
{ {
if (datalen < 0 || datalen > (msg->len - msg->cursor)) if (datalen < 0 || datalen > (msg->len - msg->cursor))
elog(ERROR, "pq_copymsgbytes: insufficient data left in message"); ereport(ERROR,
(errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("insufficient data left in message")));
memcpy(buf, &msg->data[msg->cursor], datalen); memcpy(buf, &msg->data[msg->cursor], datalen);
msg->cursor += datalen; msg->cursor += datalen;
} }
...@@ -621,7 +627,9 @@ pq_getmsgtext(StringInfo msg, int rawbytes, int *nbytes) ...@@ -621,7 +627,9 @@ pq_getmsgtext(StringInfo msg, int rawbytes, int *nbytes)
char *p; char *p;
if (rawbytes < 0 || rawbytes > (msg->len - msg->cursor)) if (rawbytes < 0 || rawbytes > (msg->len - msg->cursor))
elog(ERROR, "pq_getmsgtext: insufficient data left in message"); ereport(ERROR,
(errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("insufficient data left in message")));
str = &msg->data[msg->cursor]; str = &msg->data[msg->cursor];
msg->cursor += rawbytes; msg->cursor += rawbytes;
...@@ -661,7 +669,9 @@ pq_getmsgstring(StringInfo msg) ...@@ -661,7 +669,9 @@ pq_getmsgstring(StringInfo msg)
*/ */
slen = strlen(str); slen = strlen(str);
if (msg->cursor + slen >= msg->len) if (msg->cursor + slen >= msg->len)
elog(ERROR, "pq_getmsgstring: invalid string in message"); ereport(ERROR,
(errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("invalid string in message")));
msg->cursor += slen + 1; msg->cursor += slen + 1;
return (const char *) pg_client_to_server((unsigned char *) str, slen); return (const char *) pg_client_to_server((unsigned char *) str, slen);
...@@ -675,5 +685,7 @@ void ...@@ -675,5 +685,7 @@ void
pq_getmsgend(StringInfo msg) pq_getmsgend(StringInfo msg)
{ {
if (msg->cursor != msg->len) if (msg->cursor != msg->len)
elog(ERROR, "pq_getmsgend: invalid message format"); ereport(ERROR,
(errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("invalid message format")));
} }
This diff is collapsed.
This diff is collapsed.
...@@ -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.58 2003/05/08 18:16:36 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/tcop/dest.c,v 1.59 2003/07/22 19:00:11 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -104,7 +104,7 @@ CreateDestReceiver(CommandDest dest, Portal portal) ...@@ -104,7 +104,7 @@ CreateDestReceiver(CommandDest dest, Portal portal)
case Remote: case Remote:
case RemoteExecute: case RemoteExecute:
if (portal == NULL) if (portal == NULL)
elog(ERROR, "CreateDestReceiver: no portal specified"); elog(ERROR, "no portal specified for Remote receiver");
return printtup_create_DR(dest, portal); return printtup_create_DR(dest, portal);
case None: case None:
...@@ -118,10 +118,10 @@ CreateDestReceiver(CommandDest dest, Portal portal) ...@@ -118,10 +118,10 @@ CreateDestReceiver(CommandDest dest, Portal portal)
case Tuplestore: case Tuplestore:
if (portal == NULL) if (portal == NULL)
elog(ERROR, "CreateDestReceiver: no portal specified"); elog(ERROR, "no portal specified for Tuplestore receiver");
if (portal->holdStore == NULL || if (portal->holdStore == NULL ||
portal->holdContext == NULL) portal->holdContext == NULL)
elog(ERROR, "CreateDestReceiver: portal has no holdStore"); elog(ERROR, "portal has no holdStore");
return CreateTuplestoreDestReceiver(portal->holdStore, return CreateTuplestoreDestReceiver(portal->holdStore,
portal->holdContext); portal->holdContext);
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/fastpath.c,v 1.64 2003/05/09 18:18:54 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/tcop/fastpath.c,v 1.65 2003/07/22 19:00:11 tgl Exp $
* *
* NOTES * NOTES
* This cruft is the server side of PQfn. * This cruft is the server side of PQfn.
...@@ -101,8 +101,10 @@ GetOldFunctionMessage(StringInfo buf) ...@@ -101,8 +101,10 @@ GetOldFunctionMessage(StringInfo buf)
if (argsize < -1) if (argsize < -1)
{ {
/* FATAL here since no hope of regaining message sync */ /* FATAL here since no hope of regaining message sync */
elog(FATAL, "HandleFunctionRequest: bogus argsize %d", ereport(FATAL,
argsize); (errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("invalid argument size %d in function call message",
argsize)));
} }
/* and arg contents */ /* and arg contents */
if (argsize > 0) if (argsize > 0)
...@@ -180,7 +182,9 @@ SendFunctionResult(Datum retval, bool isnull, Oid rettype, int16 format) ...@@ -180,7 +182,9 @@ SendFunctionResult(Datum retval, bool isnull, Oid rettype, int16 format)
pfree(outputbytes); pfree(outputbytes);
} }
else else
elog(ERROR, "Invalid format code %d", format); ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("unsupported format code: %d", format)));
} }
if (!newstyle) if (!newstyle)
...@@ -208,7 +212,7 @@ fetch_fp_info(Oid func_id, struct fp_info * fip) ...@@ -208,7 +212,7 @@ fetch_fp_info(Oid func_id, struct fp_info * fip)
* Since the validity of this structure is determined by whether the * Since the validity of this structure is determined by whether the
* funcid is OK, we clear the funcid here. It must not be set to the * funcid is OK, we clear the funcid here. It must not be set to the
* correct value until we are about to return with a good struct * correct value until we are about to return with a good struct
* fp_info, since we can be interrupted (i.e., with an elog(ERROR, * fp_info, since we can be interrupted (i.e., with an ereport(ERROR,
* ...)) at any time. [No longer really an issue since we don't save * ...)) at any time. [No longer really an issue since we don't save
* the struct fp_info across transactions anymore, but keep it * the struct fp_info across transactions anymore, but keep it
* anyway.] * anyway.]
...@@ -222,8 +226,9 @@ fetch_fp_info(Oid func_id, struct fp_info * fip) ...@@ -222,8 +226,9 @@ fetch_fp_info(Oid func_id, struct fp_info * fip)
ObjectIdGetDatum(func_id), ObjectIdGetDatum(func_id),
0, 0, 0); 0, 0, 0);
if (!HeapTupleIsValid(func_htp)) if (!HeapTupleIsValid(func_htp))
elog(ERROR, "fetch_fp_info: cache lookup for function %u failed", ereport(ERROR,
func_id); (errcode(ERRCODE_UNDEFINED_FUNCTION),
errmsg("function with OID %u does not exist", func_id)));
pp = (Form_pg_proc) GETSTRUCT(func_htp); pp = (Form_pg_proc) GETSTRUCT(func_htp);
fip->namespace = pp->pronamespace; fip->namespace = pp->pronamespace;
...@@ -254,8 +259,8 @@ fetch_fp_info(Oid func_id, struct fp_info * fip) ...@@ -254,8 +259,8 @@ fetch_fp_info(Oid func_id, struct fp_info * fip)
* RETURNS: * RETURNS:
* 0 if successful completion, EOF if frontend connection lost. * 0 if successful completion, EOF if frontend connection lost.
* *
* Note: All ordinary errors result in elog(ERROR,...). However, * Note: All ordinary errors result in ereport(ERROR,...). However,
* if we lose the frontend connection there is no one to elog to, * if we lose the frontend connection there is no one to ereport to,
* and no use in proceeding... * and no use in proceeding...
* *
* Note: palloc()s done here and in the called function do not need to be * Note: palloc()s done here and in the called function do not need to be
...@@ -282,19 +287,23 @@ HandleFunctionRequest(StringInfo msgBuf) ...@@ -282,19 +287,23 @@ HandleFunctionRequest(StringInfo msgBuf)
{ {
if (GetOldFunctionMessage(msgBuf)) if (GetOldFunctionMessage(msgBuf))
{ {
elog(COMMERROR, "unexpected EOF on client connection"); ereport(COMMERROR,
(errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("unexpected EOF on client connection")));
return EOF; return EOF;
} }
} }
/* /*
* Now that we've eaten the input message, check to see if we actually * Now that we've eaten the input message, check to see if we actually
* want to do the function call or not. It's now safe to elog(); we won't * want to do the function call or not. It's now safe to ereport();
* lose sync with the frontend. * we won't lose sync with the frontend.
*/ */
if (IsAbortedTransactionBlockState()) if (IsAbortedTransactionBlockState())
elog(ERROR, "current transaction is aborted, " ereport(ERROR,
"queries ignored until end of transaction block"); (errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION),
errmsg("current transaction is aborted, "
"queries ignored until end of transaction block")));
/* /*
* Begin parsing the buffer contents. * Begin parsing the buffer contents.
...@@ -404,14 +413,18 @@ parse_fcall_arguments(StringInfo msgBuf, struct fp_info *fip, ...@@ -404,14 +413,18 @@ parse_fcall_arguments(StringInfo msgBuf, struct fp_info *fip,
nargs = pq_getmsgint(msgBuf, 2); /* # of arguments */ nargs = pq_getmsgint(msgBuf, 2); /* # of arguments */
if (fip->flinfo.fn_nargs != nargs || nargs > FUNC_MAX_ARGS) if (fip->flinfo.fn_nargs != nargs || nargs > FUNC_MAX_ARGS)
elog(ERROR, "HandleFunctionRequest: actual arguments (%d) != registered arguments (%d)", ereport(ERROR,
nargs, fip->flinfo.fn_nargs); (errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("function call message contains %d arguments but function requires %d",
nargs, fip->flinfo.fn_nargs)));
fcinfo->nargs = nargs; fcinfo->nargs = nargs;
if (numAFormats > 1 && numAFormats != nargs) if (numAFormats > 1 && numAFormats != nargs)
elog(ERROR, "Function Call message has %d argument formats but %d arguments", ereport(ERROR,
numAFormats, nargs); (errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("function call message contains %d argument formats but %d arguments",
numAFormats, nargs)));
initStringInfo(&abuf); initStringInfo(&abuf);
...@@ -430,8 +443,10 @@ parse_fcall_arguments(StringInfo msgBuf, struct fp_info *fip, ...@@ -430,8 +443,10 @@ parse_fcall_arguments(StringInfo msgBuf, struct fp_info *fip,
continue; continue;
} }
if (argsize < 0) if (argsize < 0)
elog(ERROR, "HandleFunctionRequest: bogus argsize %d", ereport(ERROR,
argsize); (errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("invalid argument size %d in function call message",
argsize)));
/* Reset abuf to empty, and insert raw data into it */ /* Reset abuf to empty, and insert raw data into it */
abuf.len = 0; abuf.len = 0;
...@@ -489,11 +504,15 @@ parse_fcall_arguments(StringInfo msgBuf, struct fp_info *fip, ...@@ -489,11 +504,15 @@ parse_fcall_arguments(StringInfo msgBuf, struct fp_info *fip,
/* Trouble if it didn't eat the whole buffer */ /* Trouble if it didn't eat the whole buffer */
if (abuf.cursor != abuf.len) if (abuf.cursor != abuf.len)
elog(ERROR, "Improper binary format in function argument %d", ereport(ERROR,
i + 1); (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
errmsg("incorrect binary data format in function argument %d",
i + 1)));
} }
else else
elog(ERROR, "Invalid format code %d", aformat); ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("unsupported format code: %d", aformat)));
} }
/* Return result format code */ /* Return result format code */
...@@ -517,8 +536,10 @@ parse_fcall_arguments_20(StringInfo msgBuf, struct fp_info *fip, ...@@ -517,8 +536,10 @@ parse_fcall_arguments_20(StringInfo msgBuf, struct fp_info *fip,
nargs = pq_getmsgint(msgBuf, 4); /* # of arguments */ nargs = pq_getmsgint(msgBuf, 4); /* # of arguments */
if (fip->flinfo.fn_nargs != nargs || nargs > FUNC_MAX_ARGS) if (fip->flinfo.fn_nargs != nargs || nargs > FUNC_MAX_ARGS)
elog(ERROR, "HandleFunctionRequest: actual arguments (%d) != registered arguments (%d)", ereport(ERROR,
nargs, fip->flinfo.fn_nargs); (errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("function call message contains %d arguments but function requires %d",
nargs, fip->flinfo.fn_nargs)));
fcinfo->nargs = nargs; fcinfo->nargs = nargs;
...@@ -545,8 +566,10 @@ parse_fcall_arguments_20(StringInfo msgBuf, struct fp_info *fip, ...@@ -545,8 +566,10 @@ parse_fcall_arguments_20(StringInfo msgBuf, struct fp_info *fip,
continue; continue;
} }
if (argsize < 0) if (argsize < 0)
elog(ERROR, "HandleFunctionRequest: bogus argsize %d", ereport(ERROR,
argsize); (errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("invalid argument size %d in function call message",
argsize)));
/* Reset abuf to empty, and insert raw data into it */ /* Reset abuf to empty, and insert raw data into it */
abuf.len = 0; abuf.len = 0;
...@@ -566,8 +589,10 @@ parse_fcall_arguments_20(StringInfo msgBuf, struct fp_info *fip, ...@@ -566,8 +589,10 @@ parse_fcall_arguments_20(StringInfo msgBuf, struct fp_info *fip,
/* Trouble if it didn't eat the whole buffer */ /* Trouble if it didn't eat the whole buffer */
if (abuf.cursor != abuf.len) if (abuf.cursor != abuf.len)
elog(ERROR, "Improper binary format in function argument %d", ereport(ERROR,
i + 1); (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
errmsg("incorrect binary data format in function argument %d",
i + 1)));
} }
/* Desired result format is always binary in protocol 2.0 */ /* Desired result format is always binary in protocol 2.0 */
......
This diff is collapsed.
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.66 2003/05/28 16:03:58 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.67 2003/07/22 19:00:12 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -341,8 +341,10 @@ PortalSetResultFormat(Portal portal, int nFormats, int16 *formats) ...@@ -341,8 +341,10 @@ PortalSetResultFormat(Portal portal, int nFormats, int16 *formats)
{ {
/* format specified for each column */ /* format specified for each column */
if (nFormats != natts) if (nFormats != natts)
elog(ERROR, "BIND message has %d result formats but query has %d columns", ereport(ERROR,
nFormats, natts); (errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("bind message has %d result formats but query has %d columns",
nFormats, natts)));
memcpy(portal->formats, formats, natts * sizeof(int16)); memcpy(portal->formats, formats, natts * sizeof(int16));
} else if (nFormats > 0) } else if (nFormats > 0)
{ {
...@@ -401,9 +403,13 @@ PortalRun(Portal portal, long count, ...@@ -401,9 +403,13 @@ PortalRun(Portal portal, long count,
* Check for improper portal use, and mark portal active. * Check for improper portal use, and mark portal active.
*/ */
if (portal->portalDone) if (portal->portalDone)
elog(ERROR, "Portal \"%s\" cannot be run anymore", portal->name); ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("portal \"%s\" cannot be run anymore", portal->name)));
if (portal->portalActive) if (portal->portalActive)
elog(ERROR, "Portal \"%s\" already active", portal->name); ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("portal \"%s\" already active", portal->name)));
portal->portalActive = true; portal->portalActive = true;
/* /*
...@@ -468,7 +474,8 @@ PortalRun(Portal portal, long count, ...@@ -468,7 +474,8 @@ PortalRun(Portal portal, long count,
break; break;
default: default:
elog(ERROR, "PortalRun: bogus portal strategy"); elog(ERROR, "unrecognized portal strategy: %d",
(int) portal->strategy);
result = false; /* keep compiler quiet */ result = false; /* keep compiler quiet */
break; break;
} }
...@@ -577,8 +584,10 @@ PortalRunSelect(Portal portal, ...@@ -577,8 +584,10 @@ PortalRunSelect(Portal portal,
else else
{ {
if (portal->cursorOptions & CURSOR_OPT_NO_SCROLL) if (portal->cursorOptions & CURSOR_OPT_NO_SCROLL)
elog(ERROR, "Cursor can only scan forward" ereport(ERROR,
"\n\tDeclare it with SCROLL option to enable backward scan"); (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("cursor can only scan forward"),
errhint("Declare it with SCROLL option to enable backward scan.")));
if (portal->atStart || count <= 0) if (portal->atStart || count <= 0)
direction = NoMovementScanDirection; direction = NoMovementScanDirection;
...@@ -900,9 +909,13 @@ PortalRunFetch(Portal portal, ...@@ -900,9 +909,13 @@ PortalRunFetch(Portal portal,
* Check for improper portal use, and mark portal active. * Check for improper portal use, and mark portal active.
*/ */
if (portal->portalDone) if (portal->portalDone)
elog(ERROR, "Portal \"%s\" cannot be run anymore", portal->name); ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("portal \"%s\" cannot be run anymore", portal->name)));
if (portal->portalActive) if (portal->portalActive)
elog(ERROR, "Portal \"%s\" already active", portal->name); ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("portal \"%s\" already active", portal->name)));
portal->portalActive = true; portal->portalActive = true;
/* /*
...@@ -922,7 +935,7 @@ PortalRunFetch(Portal portal, ...@@ -922,7 +935,7 @@ PortalRunFetch(Portal portal,
break; break;
default: default:
elog(ERROR, "PortalRunFetch: unsupported portal strategy"); elog(ERROR, "unsupported portal strategy");
result = 0; /* keep compiler quiet */ result = 0; /* keep compiler quiet */
break; break;
} }
...@@ -1053,7 +1066,7 @@ DoPortalRunFetch(Portal portal, ...@@ -1053,7 +1066,7 @@ DoPortalRunFetch(Portal portal,
} }
break; break;
default: default:
elog(ERROR, "PortalRunFetch: bogus direction"); elog(ERROR, "bogus direction");
break; break;
} }
......
This diff is collapsed.
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/error/elog.c,v 1.113 2003/07/18 23:20:32 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/error/elog.c,v 1.114 2003/07/22 19:00:12 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -572,6 +572,42 @@ errcode_for_file_access(void) ...@@ -572,6 +572,42 @@ errcode_for_file_access(void)
return 0; /* return value does not matter */ return 0; /* return value does not matter */
} }
/*
* errcode_for_socket_access --- add SQLSTATE error code to the current error
*
* The SQLSTATE code is chosen based on the saved errno value. We assume
* that the failing operation was some type of socket access.
*
* NOTE: the primary error message string should generally include %m
* when this is used.
*/
int
errcode_for_socket_access(void)
{
ErrorData *edata = &errordata[errordata_stack_depth];
/* we don't bother incrementing recursion_depth */
CHECK_STACK_DEPTH();
switch (edata->saved_errno)
{
/* Loss of connection */
case EPIPE:
#ifdef ECONNRESET
case ECONNRESET:
#endif
edata->sqlerrcode = ERRCODE_CONNECTION_FAILURE;
break;
/* All else is classified as internal errors */
default:
edata->sqlerrcode = ERRCODE_INTERNAL_ERROR;
break;
}
return 0; /* return value does not matter */
}
/* /*
* This macro handles expansion of a format string and associated parameters; * This macro handles expansion of a format string and associated parameters;
......
...@@ -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: utility.h,v 1.18 2003/05/06 20:26:28 tgl Exp $ * $Id: utility.h,v 1.19 2003/07/22 19:00:12 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -25,4 +25,6 @@ extern TupleDesc UtilityTupleDescriptor(Node *parsetree); ...@@ -25,4 +25,6 @@ extern TupleDesc UtilityTupleDescriptor(Node *parsetree);
extern const char *CreateCommandTag(Node *parsetree); extern const char *CreateCommandTag(Node *parsetree);
extern void CheckRelationOwnership(RangeVar *rel, bool noCatalogs);
#endif /* UTILITY_H */ #endif /* UTILITY_H */
...@@ -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: elog.h,v 1.53 2003/07/21 20:29:39 tgl Exp $ * $Id: elog.h,v 1.54 2003/07/22 19:00:12 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -155,6 +155,8 @@ ...@@ -155,6 +155,8 @@
#define ERRCODE_UNTERMINATED_C_STRING MAKE_SQLSTATE('2','2', '0','2','4') #define ERRCODE_UNTERMINATED_C_STRING MAKE_SQLSTATE('2','2', '0','2','4')
#define ERRCODE_ZERO_LENGTH_CHARACTER_STRING MAKE_SQLSTATE('2','2', '0','0','F') #define ERRCODE_ZERO_LENGTH_CHARACTER_STRING MAKE_SQLSTATE('2','2', '0','0','F')
#define ERRCODE_BAD_COPY_FILE_FORMAT MAKE_SQLSTATE('2','2', 'P','0','1') #define ERRCODE_BAD_COPY_FILE_FORMAT MAKE_SQLSTATE('2','2', 'P','0','1')
#define ERRCODE_INVALID_BINARY_REPRESENTATION MAKE_SQLSTATE('2','2', 'P','0','2')
#define ERRCODE_FLOATING_POINT_EXCEPTION MAKE_SQLSTATE('2','2', 'P','0','3')
/* Class 23 - Integrity Constraint Violation */ /* Class 23 - Integrity Constraint Violation */
#define ERRCODE_INTEGRITY_CONSTRAINT_VIOLATION MAKE_SQLSTATE('2','3', '0','0','0') #define ERRCODE_INTEGRITY_CONSTRAINT_VIOLATION MAKE_SQLSTATE('2','3', '0','0','0')
...@@ -178,6 +180,7 @@ ...@@ -178,6 +180,7 @@
#define ERRCODE_READ_ONLY_SQL_TRANSACTION MAKE_SQLSTATE('2','5', '0','0','6') #define ERRCODE_READ_ONLY_SQL_TRANSACTION MAKE_SQLSTATE('2','5', '0','0','6')
#define ERRCODE_SCHEMA_AND_DATA_STATEMENT_MIXING_NOT_SUPPORTED MAKE_SQLSTATE('2','5', '0','0','7') #define ERRCODE_SCHEMA_AND_DATA_STATEMENT_MIXING_NOT_SUPPORTED MAKE_SQLSTATE('2','5', '0','0','7')
#define ERRCODE_NO_ACTIVE_SQL_TRANSACTION MAKE_SQLSTATE('2','5', 'P','0','1') #define ERRCODE_NO_ACTIVE_SQL_TRANSACTION MAKE_SQLSTATE('2','5', 'P','0','1')
#define ERRCODE_IN_FAILED_SQL_TRANSACTION MAKE_SQLSTATE('2','5', 'P','0','2')
/* Class 26 - Invalid SQL Statement Name */ /* Class 26 - Invalid SQL Statement Name */
/* (we take this to mean prepared statements) */ /* (we take this to mean prepared statements) */
...@@ -244,6 +247,7 @@ ...@@ -244,6 +247,7 @@
#define ERRCODE_NAME_TOO_LONG MAKE_SQLSTATE('4','2', '6','2','2') #define ERRCODE_NAME_TOO_LONG MAKE_SQLSTATE('4','2', '6','2','2')
#define ERRCODE_RESERVED_NAME MAKE_SQLSTATE('4','2', '9','3','9') #define ERRCODE_RESERVED_NAME MAKE_SQLSTATE('4','2', '9','3','9')
#define ERRCODE_DATATYPE_MISMATCH MAKE_SQLSTATE('4','2', '8','0','4') #define ERRCODE_DATATYPE_MISMATCH MAKE_SQLSTATE('4','2', '8','0','4')
#define ERRCODE_INDETERMINATE_DATATYPE MAKE_SQLSTATE('4','2', 'P','1','8')
#define ERRCODE_WRONG_OBJECT_TYPE MAKE_SQLSTATE('4','2', '8','0','9') #define ERRCODE_WRONG_OBJECT_TYPE MAKE_SQLSTATE('4','2', '8','0','9')
/* /*
* Note: for ERRCODE purposes, we divide namable objects into these categories: * Note: for ERRCODE purposes, we divide namable objects into these categories:
...@@ -314,11 +318,17 @@ ...@@ -314,11 +318,17 @@
/* Class 57 - Operator Intervention (class borrowed from DB2) */ /* Class 57 - Operator Intervention (class borrowed from DB2) */
#define ERRCODE_OPERATOR_INTERVENTION MAKE_SQLSTATE('5','7', '0','0','0') #define ERRCODE_OPERATOR_INTERVENTION MAKE_SQLSTATE('5','7', '0','0','0')
#define ERRCODE_QUERY_CANCELED MAKE_SQLSTATE('5','7', '0','1','4') #define ERRCODE_QUERY_CANCELED MAKE_SQLSTATE('5','7', '0','1','4')
#define ERRCODE_ADMIN_SHUTDOWN MAKE_SQLSTATE('5','7', 'P','0','1')
#define ERRCODE_CRASH_SHUTDOWN MAKE_SQLSTATE('5','7', 'P','0','2')
#define ERRCODE_CANNOT_CONNECT_NOW MAKE_SQLSTATE('5','7', 'P','0','3')
/* Class 58 - System Error (class borrowed from DB2) */ /* Class 58 - System Error (class borrowed from DB2) */
/* (we define this as errors external to PostgreSQL itself) */ /* (we define this as errors external to PostgreSQL itself) */
#define ERRCODE_IO_ERROR MAKE_SQLSTATE('5','8', '0','3','0') #define ERRCODE_IO_ERROR MAKE_SQLSTATE('5','8', '0','3','0')
/* Class F0 - Configuration File Error (PostgreSQL-specific error class) */
#define ERRCODE_CONFIG_FILE_ERROR MAKE_SQLSTATE('F','0', '0','0','0')
/* Class XX - Internal Error (PostgreSQL-specific error class) */ /* Class XX - Internal Error (PostgreSQL-specific error class) */
/* (this is for "can't-happen" conditions and software bugs) */ /* (this is for "can't-happen" conditions and software bugs) */
#define ERRCODE_INTERNAL_ERROR MAKE_SQLSTATE('X','X', '0','0','0') #define ERRCODE_INTERNAL_ERROR MAKE_SQLSTATE('X','X', '0','0','0')
...@@ -361,6 +371,7 @@ extern void errfinish(int dummy, ...); ...@@ -361,6 +371,7 @@ extern void errfinish(int dummy, ...);
extern int errcode(int sqlerrcode); extern int errcode(int sqlerrcode);
extern int errcode_for_file_access(void); extern int errcode_for_file_access(void);
extern int errcode_for_socket_access(void);
extern int errmsg(const char *fmt, ...) extern int errmsg(const char *fmt, ...)
/* This extension allows gcc to check the format string for consistency with /* This extension allows gcc to check the format string for consistency with
......
...@@ -689,8 +689,8 @@ FETCH 1 FROM foo24; ...@@ -689,8 +689,8 @@ FETCH 1 FROM foo24;
(1 row) (1 row)
FETCH BACKWARD 1 FROM foo24; -- should fail FETCH BACKWARD 1 FROM foo24; -- should fail
ERROR: Cursor can only scan forward ERROR: cursor can only scan forward
Declare it with SCROLL option to enable backward scan HINT: Declare it with SCROLL option to enable backward scan.
END; END;
-- --
-- Cursors outside transaction blocks -- Cursors outside transaction blocks
......
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