Client 2—Adding Error Checking

The client1.c application discussed has a fundamental flaw—there is no way to tell whether the connection attempt was successful. This next program attempts a connection and displays an error message if the attempt fails:

 1 /*
 2 ** File: client2.c
 3 */
 4
 5 #include <stdlib.h>
 6 #include <libpq-fe.h>
 7
 8 int main( int argc, char * argv[] )
 9 {
10   PGconn * connection;
11
12   if( argc != 2 )
13   {
14     printf( "usage  : %s "connection-string"
", argv[0] );
15     printf( "example: %s "user=myname password=cows"
", argv[0]);
16     exit( 1 );
17   }
18
19   if(( connection = PQconnectdb( argv[1] )) == NULL )
20   {
21     printf( "Fatal error - unable to allocate connection
" );
22     exit( 1 );
23   }
24
25   if( PQstatus( connection ) != CONNECTION_OK )
26     printf( "%s
", PQerrorMessage( connection ));
27   else
28     printf( "Connection ok, disconnecting
" );
29
30   PQfinish( connection );
31
32   exit( 0 );
33
34 }

You can specify a connection string on the command line when you run this program. If you want to include more than one connection attribute, enclose the entire connection string in double quotes. For example:

$ ./client2 user=korry
Connection ok, disconnecting

$ ./client2 "user=korry password=cows"
Connection ok, disconnecting

I recommend that you run this program a few times, feeding it a variety of invalid connect strings so you become familiar with the error messages that you might receive when things go wrong. For example:

$ ./client2 host=badhost
connectDBStart() --  unknown hostname: badhost

$ ./client2 port=1000
connectDBStart() -- connect() failed: No such file or directory
        Is the postmaster running locally
        and accepting connections on Unix socket '/tmp/.s.PGSQL.1000'?

$ ./client2 badparameter
ERROR: Missing '=' after 'badparameter' in conninfo

$ ./client2 badparameter=1000
ERROR: Unknown conninfo option 'badparameter'

Viewing Connection Attributes

In the get_dflts application I showed you how to use the PQconndefaults() function to view the default connection attributes that will be used to establish a connection.

libpq also provides a number of functions that you can use to retrieve the actual connection attributes after you have a PGconn object. These functions are useful because in most situations, you won't explicitly specify every connection attribute. Instead, many (perhaps all) of the connection attributes will be defaulted for you.

PQconnectdb() will return a PGconn pointer in almost every case (PQconnectdb() will return a NULL pointer only if libpq runs out of memory).

The following program attempts to make a connection and then print the set of connection parameters. I've modified client2.c to show the complete set of final connection parameters after a connection attempt. The new application is called client2b:

 1 /*
 2 ** File: client2b.c
 3 */
 4
 5 #include <stdlib.h>
 6 #include <libpq-fe.h>
 7
 8 static void show_connection_attributes( const PGconn * conn );
 9 static const char * check( const char * value );
10
11 int main( int argc, char * argv[] )
12 {
13   PGconn * connection;
14
15   if( argc != 2 )
16   {
17     printf( "usage  : %s "connection-string"
", argv[0] );
18     printf( "example: %s "user=myname password=cows"
", argv[0]);
19     exit( 1 );
20   }
21
22   if(( connection = PQconnectdb( argv[1] )) == NULL )
23   {
24     printf( "Fatal error - unable to allocate connection
" );
25     exit( 1 );
26   }
27
28   if( PQstatus( connection ) != CONNECTION_OK )
29     printf( "%s
", PQerrorMessage( connection ));
30   else
31     printf( "Connection ok
" );
32
33   show_connection_attributes( connection );
34
35   PQfinish( connection );
36
37   exit( 0 );
38
39 }
40
41 static const char * check( const char * value )
42 {
43     if( value )
44     return( value );
45     else
46     return( "(null)" );
47 }
48
49 static void show_connection_attributes( const PGconn * c )
50 {
51   printf( "dbname   = %s
", check( PQdb( c )));
52   printf( "user     = %s
", check( PQuser( c )));
53   printf( "password = %s
", check( PQpass( c )));
54   printf( "host     = %s
", check( PQhost( c )));
55   printf( "port     = %s
", check( PQport( c )));
56   printf( "tty      = %s
", check( PQtty( c )));
57   printf( "options  = %s
", check( PQoptions( c )));
58 }

Take a look at the show_connection_attributes() function (lines 49-58). Given a PGconn pointer, you can find the connection attributes that result after all the defaults are applied by calling PQdb(), PQuser(), and so on. In some cases, one or more of these functions may return a NULL pointer, so I wrapped each function invocation in a call to check() (lines 41-47) to avoid giving any bad pointers to printf().

If, for some reason, you need to know the process ID of the server that you're connected to, you can retrieve that value by calling the PQbackendPID() function. PQbackendPID() is particularly useful if you're debugging or exploring the PostgreSQL server. You can find the version number of the server using the PQserverVersion() function. PQserverVersion() returns an integer value that encodes the server's version number—version 7.3.2 is encoded as 70302, version 8.0.0 is encode as 80000, and so forth.

Remember that PQconnectdb() returns a PGconn pointer even when a connection attempt fails; it is often instructive to see the final connection attributes for a failed connection attempt. Here are the results when I try to connect to a nonexistent database on my system:

$ ./client2b user=korry
FATAL 1:  Database "korry" does not exist in the system catalog.

dbname   = korry
user     = korry
password =
host     = (null)
port     = 5432
tty      =
options  =

In this case, I can see that libpq chose an invalid database name (defaulted from my username).

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.188.181.163