Client 2Adding Error Checking

The client1.c application discussed has a fundamental flawthere 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 6 #include 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 6 #include 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 numberversion 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).

Категории