PgDatabase

This is the basic database access class. It is derived from PgConnection and adds facilities to handle the results of data manipulation commands. These additional methods should be used only after a query has been sent to the backend and results are being received.

Besides the methods inherited from PgConnection, PgDatabase provides the methods listed in the table that follows. These methods are described later in this section.

Table 2-2. PgDatabase Interface

MethodDescription
PgDatabaseMakes a new connection to a backend database server.
TuplesObtain the number of rows in the result.
FieldsObtain the number of columns in each result tuple.
FieldNameObtain the name of the given column.
FieldNumObtain the column index associated with the given column name.
FieldTypeObtain the oid of the type of the given column.
FieldSizeObtain the size (in bytes) of the given column.
GetValueRetrieves a single column value.
GetIsNullTest if the value of the given column is null.
GetLengthRetrieves the length (in bytes) of a column value.
CmdTuplesObtain the number of rows affected by an INSERT, UPDATE, or DELETE.
GetLineReads a newline-terminated line of characters (transmitted by the backend).
PutLineSends a null-terminated string to the backend.
EndCopySynchronizes with the backend.

Database Connection Methods

Retrieving SELECT Result Information

The PgDatabase object encapsulates a PGresult structure (see Chapter 1). You can use the following methods to retrieve data after a query has been sent to the backend and results are being received.

Note

Only one PGresult exists per PgDatabase object. (That is, only one result per connection can be handled at one time.)

Retrieving SELECT Result Values

GetValue

GetValue retrieves a single column value.

const char * PgDatabase::GetValue(int tup_num, int field_num)

const char * PgDatabase::GetValue(int tup_num, const char * field_name)

Returns a single column value of one row (tup_num) of a result. You can specify the column by index or by name. Row and column indexes start at 0. It is a wrapper for the libpq function PQgetvalue (see the Section called PQgetvalue in Chapter 1).

For most queries, the value returned by GetValue is a null-terminated string representation of the attribute value. But if BinaryTuples is true, the value returned by GetValue is the binary representation of the type in the internal format of the backend server (but not including the size word, if the field is variable-length). It is then the programmer's responsibility to cast and convert the data to the correct C type. The pointer returned by GetValue points to storage that is part of the PGresult structure. You should not modify it, and you must explicitly copy the value into other storage if it is to be used past the lifetime of the PGresult structure itself. BinaryTuples is not yet implemented.

Note that for NULL fields GetValue returns the empty string, not the NULL pointer. Use GetIsNull (described below) to check for NULL values.

Retrieving Non-SELECT Result Information

Methods Associated with the COPY Command

The COPY command in Red Hat Database has options to read from or to write to the network connection used by libpq++. Special methods are provided so that applications can take advantage of this capability.

EndCopy

EndCopy synchronizes with the backend.

int PgDatabase::EndCopy()

This function blocks until the backend has finished processing the copy. It should either be issued when the last string has been sent to the backend using PutLine or when the last string has been received from the backend using GetLine. It must be issued to avoid synchronization problems with the backend/frontend connection.

The return value is 0 on successful completion, nonzero on failure.

For example, a table can be created and populated as follows:

/* COPY Example */
/* Description: CREATE and populate it using COPY */
/* Create an instance */
PgDatabase data("dbname=dbname");
/* Create the target table */
data.Exec("create table foo (a int4, b char(16), d double precision)");
/* Start the COPY operation to populate the table */
data.Exec("copy foo from stdin");
/* Send the COPY data */
data.PutLine("3\tHello World\t4.5\n");
data.PutLine("4\tGoodbye World\t7.11\n");
...
/* Send completion string for the end of the data */
data.PutLine("\\.\n");
/* Synchronize with the backend */
data.EndCopy();

Examples of PgDatabase Use

This first example implements a small interactive loop where queries can be entered interactively and sent to the backend. Note that the header file libpq++.h must be included. The program must also be linked with the libpq++ library (by using the -lpq++ linker option).

You can find additional libpq++ examples in src/interfaces/libpq++/examples

Example 2-2. libpq++ Example Program 2

The second example queries the template1 database for a list of database names.

#include <iostream.h>
#include <iomanip.h>
#include "libpq++.h"

int main()
{
  // Begin, by establishing a connection to the backend.
  // When no parameters are given then the system will
  // try to use reasonable defaults by 
  // looking up environment variables 
  // or, failing that, using hardwired constants
  const char* dbName = "dbname=template1";
  PgDatabase data(dbName);

  // check to see that the backend connection 
  // was successfully made
  if ( data.ConnectionBad() ) {
      cerr << "Connection to database '" 
           << dbName << "' failed." << endl
           << "Error returned: " 
           << data.ErrorMessage() << endl;
      exit(1);
  }

  // start a transaction block
  if ( !data.ExecCommandOk("BEGIN") ) {
    cerr << "BEGIN command failed" << endl;
    exit(1);
  }

  // submit command to the backend
  if ( !data.ExecCommandOk("DECLARE myportal CURSOR 
    FOR select * from pg_database") ) {
    cerr << "DECLARE CURSOR command failed" << endl;
    exit(1);
  }

  // fetch instances from the pg_database, 
  // the system catalog of databases
  if ( !data.ExecTuplesOk("FETCH ALL in myportal") ) {
    cerr << "FETCH ALL didn't return tuples properly" << endl;
    exit(1);
  }
 
  // first, print out the attribute names
  int nFields = data.Fields();
  for (int i=0; i < nFields; i++)
      cout << setiosflags(ios::right) 
           << setw(15) << data.FieldName(i);
  cout << endl << endl;

  // next, print out the instances
  for (int i=0; i < data.Tuples(); i++) {
       for (int j=0; j < nFields; j++)
            cout << setiosflags(ios::right) 
                 << setw(15) << data.GetValue(i,j);
       cout << endl;
  }

  // Close the portal
  data.Exec("CLOSE myportal");

  // End the transaction
  data.Exec("END");
  return 0;
}