Extracting Data from Query Results

Một phần của tài liệu Beginning Databases with Postgre SQL phần 7 docx (Trang 25 - 28)

Up until now, we have been concerned only with SQL statements that have not returned any data. Now it is time to consider how to deal with data returned by calls to PQexec, the results of SELECT statements.

When we perform a SELECT with PQexec, the result set will contain information about the data the query has returned. Query results can seem a little tiresome to handle, as we do not always know exactly what to expect. If we execute a SELECT, we do not know in advance whether we will be returned zero, one, or several millions of rows. If we use a wildcard (*) in the SELECT query, we do not even know which columns will be returned or what their names are. In general, we will want to program our application so that it selects specified columns only. That way, if the database design changes, perhaps when new columns are added, a function that does not rely on the new column will still work as expected.

Sometimes (for example, if we are writing a general-purpose SQL program that is accepting statements from the user and displaying results), it would be better if we could program in a general way, and with libpq, we can. There are just a few more functions to learn:

• When PQexec executes a SELECT without an error, we expect to see a result status of PGRES_TUPLES_OK. The next step is to determine how many rows are present in the result set. We do this by calling PQntuples to get the total number of rows in our result (which may be zero):

int PQntuples(const PGresult *result);

• We can retrieve the number of fields (attributes or columns) in our tuples by calling PQnfields:

int PQnfields(const PGresult *result);

• The fields in the result are numbered starting from zero, and we can retrieve their names by calling PQfname:

char *PQfname(const PGresult *result, int index);

• The size of the field is given by PQfsize:

int PQfsize(const PGresult *result, int index);

• For fixed-sized fields, PQfsize returns the number of bytes that a value in that particular column would occupy. For variable-length fields, PQfsize returns –1.

• The index number for a column with a given name can be retrieved by calling PQfnumber:

int PQfnumber(const PGresult *result, const char *field);

Let’s modify our doSQL function to print out some information about the data returned from a SELECT query. Here’s our next version:

void doSQL(PGconn *conn, char *command);

{

PGresult *result;

printf("%s\n", command);

result = PQexec(conn, command);

printf("status is %s\n", PQresStatus(PQresultStatus(result)));

printf("#rows affected %s\n", PQcmdTuples(result));

printf("result message: %s\n", PQresultErrorMessage(result));

switch(PQresultStatus(result)) { case PGRES_TUPLES_OK:

{

int n = 0;

int nrows = PQntuples(result);

int nfields = PQnfields(result);

printf("number of rows returned = %d\n", nrows);

printf("number of fields returned = %d\n", nfields);

/* Print the field names */

for(n = 0; n < nfields; n++) { printf(" %s:%d",

PQfname(result, n), PQfsize(result, n));

}

printf("\n");

} }

PQclear(result);

}

Now when executing a SELECT, we can see the characteristics of the data being returned:

doSQL(conn, "SELECT * FROM number WHERE value = 29");

This call results in the following output:

status is PGRES_TUPLES_OK

#rows affected result message:

number of rows returned = 2 number of fields returned = 2 value:4 name:-1

Notice that an empty string is returned by PQcmdTuples for queries that cannot affect rows, and PQresultErrorMessage returns an empty string where there is no error. Now we are ready to extract the data from the fields returned in the rows of our result set. The rows are numbered, starting from zero.

Normally, all data is transferred from the server as strings. We can get at a character repre- sentation of the data by calling the PQgetvalue function:

char *PQgetvalue(const PGresult *result, int tuple, int field);

If we need to know in advance how long the string returned by PQgetvalue is going to be, we can call PQgetlength:

int PQgetlength(const PGresult *result, int tuple, int field);

As mentioned earlier, both the tuple (row) number and field (column) number start at zero.

Let’s add some data display to our doSQL function:

void doSQL(PGconn *conn, char *command) {

PGresult *result;

printf("%s\n", command);

result = PQexec(conn, command);

printf("status is %s\n", PQresStatus(PQresultStatus(result)));

printf("#rows affected %s\n", PQcmdTuples(result));

printf("result message: %s\n", PQresultErrorMessage(result));

switch(PQresultStatus(result)) { case PGRES_TUPLES_OK:

{

int r, n;

int nrows = PQntuples(result);

int nfields = PQnfields(result);

printf("number of rows returned = %d\n", nrows);

printf("number of fields returned = %d\n", nfields);

for(r = 0; r < nrows; r++) {

for(n = 0; n < nfields; n++) printf(" %s = %s(%d),", PQfname(result, n), PQgetvalue(result, r, n), PQgetlength(result, r, n));

printf("\n");

} } }

PQclear(result);

}

The complete result of the SELECT query is printed, including the lengths of the strings containing the data:

SELECT * FROM number WHERE value = 29 Status is PGRES_TUPLES_OK

#rows affected result message:

number of rows returned = 2 number of fields returned = 2 value = 29(2), name = My Age(6), value = 29(2), name = Anniversary(11),

Note that the length of the data string does not include a trailing null (the character '\0', not the SQL value NULL), which is present in the string returned by PQgetvalue.

Caution String data, such as that used in columns defined as char(n), is padded with spaces. This can give unexpected results if you are checking for a particular string value or comparing values for a sort. If you insert the value Zaphod into a column defined as char(8), you will get back Zaphod<space><space>, which will not compare as equal to Zaphod if you use the C library function strcmp. This little problem has been known to plague even very experienced developers.

Một phần của tài liệu Beginning Databases with Postgre SQL phần 7 docx (Trang 25 - 28)

Tải bản đầy đủ (PDF)

(66 trang)