Tải bản đầy đủ - 0 (trang)
Chapter 9. A Simpler C API - libpgeasy

Chapter 9. A Simpler C API - libpgeasy

Tải bản đầy đủ - 0trang

Prerequisites

Asmentionedpreviously,libpgeasyisawrapperaroundlibpq.

Thebasicrequirementsforbuildingalibpqclientwere

describedinChapter8,"ThePostgreSQLCAPIlibpq(Client

Applications),"andsoIwon'trepeatthemhere.

Besidesthelibpqheaderfilesandobjectlibraries,youwillneed

to#includethelibpgeasy.hfileandlinktothelibpgeasy

objectlibrary(-lpgeasy).



Client1ConnectingtotheServer

Connectingtoadatabaseusinglibpgeasyissimple.libpgeasy

providesasingleconnectionfunction:

PGconn*connectdb(char*options);

Thesingleargumenttoconnectdb()isaconnectionstringin

thesameformexpectedbythelibpqPQconnectdb()function.

Anexampleconnectionstringmightlooklikethis:

char*connectString="dbname=moviesuser=sheila";

Let'slookatasimpleclientthatusestheconnectdb()function:

/*client1.c*/



#include

#include

#include



intmain(intargc,char*argv[])

{



connectdb(argv[1]?argv[1]:"");

disconnectdb();

exit(EXIT_SUCCESS);



}

Thisexampleshowstheminimumrequiredcodeforalibpgeasy

application.Youmust#includetwofiles:libpq-fe.hand

libpgeasy.h,andyoumust#includetheminthatorder[1].

[1]libpqeasyreferstoitemsin



libqp-fe,sotheymustbe#includedinthatorder.



Inthecalltoconnectdb(),I'vepassedinthefirstcommandlineargument(oranemptystringiftherearenocommand-line

arguments).Whenyourunthisprogram,youshouldprovidea

connectionstringastheonlyargument.Ifyouneedtospecify

morethanoneconnectionproperty,enclosethelistindouble

quotesandseparatethepropertieswithaspace.Herearetwo

examples:

$./client1dbname=movies

$./client1"dbname=moviesuser=sheila"

Aftertheconnectdb()functionreturns,Icalldisconnectdb().

Thefunctionprototypefordisconnectdb()is

voiddisconnectdb(void);



Noticethatdisconnectdb()doesnotexpectanyarguments.

YoumayhavealsonoticedthatIdidnotcaptureanyreturn

valuefromthecalltoconnectdb().

HowdoeslibpgeasyknowwhichconnectionIwantto

terminate?Inkeepingwiththegoalofsimplicity,libpgeasy

remembersthedatabaseconnectionforme.WhenIcall

connectdb(),libpgeasystores(inaprivatevariable)the

PGconnpointer.WhenIcalldisconnectdb(),itusesthestored

connectionpointer.Althoughlibpgeasyhasthecapacityto

rememberthedatabaseconnection,itwillrememberonlyone

connectionatatime.Thisisoneexampleofthetradeoffsmade

whenusinglibpgeasyversuslibpqyouhavegainedsimplicity,

butlostsomeflexibility.

Ifyouwant,youcancapturethereturnvaluefrom

connectdb()inaPGconnpointervariableanduseitinthe

samewaysthatyoucoulduseaPGconn*throughlibpq.

Nowlet'srunthisclientapplicationtoseewhatitdoes:

$./client1dbname=movies

$

Exciting,don'tyouthink?Let'strythatagain,feedingitan

erroneousdatabasenamethistime:

$./client1dbname=foofoo

Connectiontodatabaseusing'dbname=foofoo'failed.



FATAL1:Database"foofoo"doesnotexistinthesystemcatalo

$



Thistime,youcanseethatlibpgeasyproducedanerror

message.Theclient1.csourcecodedoesn'tincludeanyerror

handlingatallyoudidn'tincludeanycodetocheckforerrorsor

toprinterrormessages.Again,thisisconsistentwiththegoal

ofsimplicity.Ofcourse,inasophisticatedapplication,you

probablywantalittlemorecontroloverthehandlingoferror

conditions.



Client2AddingErrorChecking

Nowlet'saddalittleerror-handlingcodetotheclient:

/*client2a.c*/



#include

#include

#include



intmain(intargc,char*argv[])

{

PGconn*connection;



connection=connectdb(argv[1]?argv[1]:"");



if(PQstatus(connection)!=CONNECTION_OK)



printf("Caughtanerror:%s\n",PQerrorMessage(connection

else



printf("connectionok\n");



disconnectdb();



exit(EXIT_SUCCESS);

}

Thistimearound,IcapturedthePGconn*returnedby

connectdb().RememberthatthisPGconn*isthesametypeof

objectthatyouwouldfindinalibpqapplication.Callthe

PQstatus()functiontodeterminewhethertheconnection

attemptsucceededorfailed.Ifafailureoccurs,printanerror

message;otherwise,print"connectionok."

Let'srunthisacoupleoftimestoseehowitbehaves:

$./client2adbname=movies

connectionok

Asexpected,youseeafriendlylittleconfirmationthatthe

connectionattemptwassuccessful.Nowlet'sfeedinanerror

andseewhathappens:

$./client2adbname=foofoo

Connectiontodatabaseusing'dbname=foofoo'failed.



FATAL1:Database"foofoo"doesnotexistinthesystemcatalo



Thistime,youseeanerrormessage.Butlookcloselyandyou'll

seethattheerrormessagedoesn'tmatchyoursourcecodethe

errormessageshouldstartwiththetextCaughtanerror:.

Whathappened?Ifyoudon'tmakeanyotherarrangements,

connectdb()willprintanerrormessageandterminatethe

callingprogramifitencountersafailure.So,thisprogramdidn't

evengettothepointwhereitcouldcallPQstatus()the

programterminatedbeforeconnectdb()everreturned.

So,howdoyoumakethese"otherarrangements?"libpgeasy

providestwofunctionsthatyoucanusetocontroltheerrorhandlingmode:

voidon_error_stop(void);

voidon_error_continue(void);

Theon_error_stop()functiontellslibpgeasythatyouwantit

tohandleerrorconditions.Callingon_error_continue()tells

libpgeasythatyouwanttohandleerrorconditionsyourself.

on_error_stop()isthedefaulterror-handlingmode.

Ishouldpointoutherethatcallingon_error_continue()has

noeffectontheconnectdb()function.Iftheconnection

attemptfails,connectdb()willterminatetheprogram

regardlessofwhicherror-handlingmodeisineffect.

Inthenextsection,youwillseethatlibpgeasydoesinfactlet

youconstructyourownerror-handlingcodeonceaconnection

hasbeenestablished.



Client3ProcessingQueries

Queryprocessingissimpleinlibpgeasy.ToexecuteaSQL

command,youcallthedoquery()function.Thefunction

prototypefordoquery()is

PGresult*doquery(char*query);

Noticethatdoquery()doesnotexpectaPGconn*libpgeasy

candealwithonlyasingledatabaseconnectionanditimplicitly

usestheonereturnedbyconnectdb().doquery()returnsa

PGresult*.Thisisthesamedatastructureyousawinthe

previouschapteritrepresentstheresultsetofthequery.

Afteryouhaveexecutedacommand,youwillneedtoprocess

theresultset.libpgeasyprovidesanumberoffunctionsfor

dealingwitharesultsetofcourse,youcanuseanyofthelibpq

functionsaswell.

Ifyouarereasonablysurethatyourquerysucceeded,youcan

usethefetch()functiontoretrieveasinglerowfromthe

resultset.Hereisthefunctionprototypeforfetch():

intfetch(void*param,...);

Thefetch()functionreturnstheindexoftherowthatyoujust

fetched.Thefirstrowreturnedisrow0,thesecondrowisrow

1,andsoon.Whentheresultsetisexhausted,fetch()will

returnEND_OF_TUPLES.Ifthequeryreturnszerorows,thefirst

calltofetch()willreturnEND_OF_TUPLES.Whenyoucall

fetch(),youpassalistofpointers.Eachargumentshould

pointtoabufferlargeenoughtoholdthecorrespondingfield



fromtheresultset.Youmustpassonepointerforeachcolumn

returnedbythequery.Ifyouaren'tinterestedinthevalueofa

column,youcanpassaNULLpointer.

Thismightbeagoodpointtoseeanexample:

/*client3a.c*/



#include

#include

#include



intmain(intargc,char*argv[])

{

chartape_id[8+1];

chartitle[80+1];

charduration[80+1];

PGconn*connection;



connection=connectdb(argv[1]?argv[1]:"");



on_error_stop();



doquery("SELECT*FROMtapes");



while(fetch(tape_id,title,duration)!=END_OF_TUPLES)

{

printf("%s-%-40s-%s\n",tape_id,title,duration);

}



disconnectdb();



exit(EXIT_SUCCESS);



}

Inclient3a.c,Iselectallcolumns(andallrows)fromthe

tapestable.Hereisthedefinitionoftapes:

movies=#\dtapes

Table"tapes"



Tài liệu bạn tìm kiếm đã sẵn sàng tải về

Chapter 9. A Simpler C API - libpgeasy

Tải bản đầy đủ ngay(0 tr)

×