Client 4—An Interactive Query Processor

To wrap up this chapter, you'll convert the interactive query processor from the previous chapter into a libpgeasy client.

Most of the code remains the same, so I'll point out only the differences. The most important change is that you no longer have to pass the PGconn * (connection handle) to every function-libpgeasy is managing the connection handle for you.

 1 /*
 2 ** File: client4.c
 3 */
 4
 5 #include <stdlib.h>
 6 #include <string.h>
 7 #include <libpq-fe.h>
 8 #include <libpgeasy.h>
 9 #include <readline/readline.h>
10 #include <readline/history.h>
11
12 typedef enum { FALSE, TRUE } bool;
13
14 #define MAX_PRINT_LEN 40
15
16 static char separator[MAX_PRINT_LEN+1];
17
18 void print_result_set( PGresult * result )
19 {
20   int          col;
21   int          row;
22   int        * sizes;
23
24 /*
25 ** Compute the size for each column
26 */
27   sizes = (int *)calloc( PQnfields( result ), sizeof( int ));
28
29   for( col = 0; col < PQnfields( result ); col++ )
30   {
31     int   len = 0;
32
33     for( row = 0; row < PQntuples( result ); row++ )
34     {
35       if( PQgetisnull( result, row, col ))
36         len = 0;
37       else
38          len = PQgetlength( result, row, col );
39
40       if( len > sizes[col] )
41          sizes[col] = len;
42     }
43
44     if(( len = strlen( PQfname( result, col ))) > sizes[col] )
45       sizes[col] = len;
46
47     if( sizes[col] > MAX_PRINT_LEN )
48       sizes[col] = MAX_PRINT_LEN;
49   }
50
51 /*
52 ** Print the field names.
53 */
54   for( col = 0; col < PQnfields( result ); col++ )
55   {
56     printf( "%-*s ", sizes[col], PQfname( result, col ));
57   }
58
59   printf( "
" );
60
61 /*
62 ** Print the separator line
63 */
64   memset( separator, '-', MAX_PRINT_LEN );
65
66   for( col = 0; col < PQnfields( result ); col++ )
67   {
68     printf( "%*.*s ", sizes[col], sizes[col], separator );
69   }
70
71   printf( "
" );
72
73 /*
74 ** Now loop through each of the tuples returned by
75 ** our query and print the results.
76 */
77   for( row = 0; row < PQntuples( result ); row++ )
78   {
79     for( col = 0; col < PQnfields( result ); col++ )
80     {
81       if( PQgetisnull( result, row, col ))
82          printf( "%*s", sizes[col], "" );
83       else
84          printf( "%*s ", sizes[col], PQgetvalue(result, row, col));
85     }
86
87     printf( "
" );
88
89   }
90   printf( "(%d rows)
", PQntuples( result ));
91
92   free( sizes );
93 }

You can't use the fetch() or fetchwithnulls() in the print_result_set() function. There is no way to construct a call to these functions because you can't know (at the time the program is compiled) how many columns will be returned by a query.

The process_query() function is very simple. The call to doquery() sends the command to the server and returns a pointer to the result set.

 95 void process_query( char * buf )
 96 {
 97   PGresult *  result;
 98
 99   result = doquery( buf );
100
101   if( PQresultStatus( result ) == PGRES_TUPLES_OK )
102   {
103     print_result_set( result );
104   }
105   else if( PQresultStatus( result ) == PGRES_COMMAND_OK )
106   {
107     printf( "%s", PQcmdStatus( result ));
108
109     if( strlen( PQcmdTuples( result )))
110       printf( " - %s rows
", PQcmdTuples( result ));
111     else
112       printf( "
" );
113   }
114   else
115   {
116       printf( "%s
", PQresultErrorMessage( result ));
117   }
118 }

The main() function is largely unchanged. I don't bother to save the connection handle returned by connectdb() because libpgeasy remembers it for me. The only other change in main() is that you set the error-handling mode calling on_error_continue(). If you don't set the error-handling mode, libpgeasy assumes that it should terminate your application if an error is encountered.

120 int main( int argc, char * argv[] )
121 {
122   char    * buf;
123
124   connectdb( argc > 1 ? argv[1] : "" );
125
126   on_error_continue();
127
128   using_history();
129   read_history( ".pg_history" );
130
131   while(( buf = readline( "->" )) != NULL )
132   {
133     if( strncmp( buf, "quit", sizeof( "quit" ) - 1  ) == 0 )
134     {
135       break;
136     }
137     else
138     {
139       if( strlen( buf ) != 0 )
140       {
141          add_history( buf );
142          process_query( buf );
143       }
144       free( buf );
145     }
146   }
147
148   write_history( ".pg_history" );
149
150   disconnectdb();
151
152   exit( EXIT_SUCCESS );
153 }

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

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