postgresql server programming - second editionindex-of.co.uk/database/sql database/postgresql... ·...
TRANSCRIPT
![Page 1: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/1.jpg)
![Page 2: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/2.jpg)
![Page 3: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/3.jpg)
PostgreSQLServerProgrammingSecondEdition
![Page 4: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/4.jpg)
TableofContents
PostgreSQLServerProgrammingSecondEdition
Credits
AbouttheAuthors
AbouttheReviewers
www.PacktPub.com
Supportfiles,eBooks,discountoffers,andmore
Whysubscribe?
FreeaccessforPacktaccountholders
Preface
Whatthisbookcovers
Whatyouneedforthisbook
Whothisbookisfor
Conventions
Readerfeedback
Customersupport
Downloadingtheexamplecode
Errata
Piracy
Questions
1.WhatIsaPostgreSQLServer?
Whyprogramintheserver?
UsingPL/pgSQLforintegritychecks
Aboutthisbook’scodeexamples
Switchingtotheexpandeddisplay
Movingbeyondsimplefunctions
Datacomparisonsusingoperators
Managingrelateddatawithtriggers
Auditingchanges
Datacleaning
![Page 5: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/5.jpg)
Customsortorders
Programmingbestpractices
KISS–keepitsimplestupid
DRY–don’trepeatyourself
YAGNI–youain’tgonnaneedit
SOA–service-orientedarchitecture
Typeextensibility
Caching
Wrappingup–whyprogramintheserver?
Performance
Easeofmaintenance
Improvedproductivity
Simplewaystotightensecurity
Summary
2.ServerProgrammingEnvironments
Costofacquisition
Availabilityofdevelopers
Licensing
Predictability
Community
Procedurallanguages
Third-partytools
Platformcompatibility
Applicationdesign
Databasesareconsideredharmful
Encapsulation
WhatdoesPostgreSQLoffer?
Datalocality
Morebasics
Transactions
Generalerrorreportinganderrorhandling
![Page 6: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/6.jpg)
User-definedfunctions
Otherparameters
Morecontrol
Summary
3.YourFirstPL/pgSQLFunction
WhyPL/pgSQL?
ThestructureofaPL/pgSQLfunction
Accessingfunctionarguments
Conditionalexpressions
Loopswithcounters
Statementtermination
Loopingthroughqueryresults
PERFORMversusSELECT
LoopingThroughArrays
Returningarecord
Actingonthefunction’sresults
Summary
4.ReturningStructuredData
Setsandarrays
Returningsets
Returningasetofintegers
Usingasetreturningfunction
Functionsbasedonviews
OUTparametersandrecords
OUTparameters
Returningrecords
UsingRETURNSTABLE
Returningwithnopredefinedstructure
ReturningSETOFANY
Variadicargumentlists
AsummaryoftheRETURNSETOFvariants
![Page 7: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/7.jpg)
Returningcursors
Iteratingovercursorsreturnedfromanotherfunction
Wrappingupoffunctionsreturningcursors
Otherwaystoworkwithstructureddata
Complexdatatypesforthemodernworld–XMLandJSON
XMLdatatypeandreturningdataasXMLfromfunctions
ReturningdataintheJSONformat
Summary
5.PL/pgSQLTriggerFunctions
Creatingthetriggerfunction
Creatingthetrigger
Workingonasimple“Hey,I’mcalled”trigger
Theaudittrigger
DisallowingDELETE
DisallowingTRUNCATE
ModifyingtheNEWrecord
Thetimestampingtrigger
Theimmutablefieldstrigger
Controllingwhenatriggeriscalled
Conditionaltriggers
Triggersonspecificfieldchanges
Visibility
Mostimportantly–usetriggerscautiously!
VariablespassedtothePL/pgSQLTRIGGERfunction
Summary
6.PostgreSQLEventTriggers
Usecasesforcreatingeventtriggers
Creatingeventtriggers
Creatinganaudittrail
Preventingschemachanges
Aroadmapofeventtriggers
![Page 8: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/8.jpg)
Summary
7.DebuggingPL/pgSQL
ManualdebuggingwithRAISENOTICE
Throwingexceptions
Loggingtoafile
TheadvantagesofRAISENOTICE
ThedisadvantagesofRAISENOTICE
Visualdebugging
Installingthedebugger
Installingthedebuggerfromthesource
InstallingpgAdmin3
Usingthedebugger
Theadvantagesofthedebugger
Thedisadvantagesofthedebugger
Summary
8.UsingUnrestrictedLanguages
Areuntrustedlanguagesinferiortotrustedones?
Canyouuseuntrustedlanguagesforimportantfunctions?
Willuntrustedlanguagescorruptthedatabase?
Whyuntrusted?
WhyPL/Python?
QuickintroductiontoPL/Python
AminimalPL/Pythonfunction
Datatypeconversions
WritingsimplefunctionsinPL/Python
Asimplefunction
Functionsreturningarecord
Tablefunctions
Runningqueriesinthedatabase
Runningsimplequeries
Usingpreparedqueries
![Page 9: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/9.jpg)
Cachingpreparedqueries
WritingtriggerfunctionsinPL/Python
Exploringtheinputsofatrigger
Alogtrigger
Constructingqueries
Handlingexceptions
AtomicityinPython
DebuggingPL/Python
Usingplpy.notice()totrackthefunction’sprogress
Usingassert
Redirectingsys.stdoutandsys.stderr
Thinkingoutofthe“SQLdatabaseserver”box
Generatingthumbnailswhensavingimages
Sendingane-mail
Listingdirectorycontents
Summary
9.WritingAdvancedFunctionsinC
ThesimplestCfunction–return(a+b)
add_func.c
Version0callconventions
Makefile
CREATEFUNCTIONadd(int,int)
add_func.sql.in
SummaryforwritingaCfunction
Addingfunctionalitytoadd(int,int)
SmarthandlingofNULLarguments
Workingwithanynumberofarguments
BasicguidelinesforwritingCcode
Memoryallocation
Usepalloc()andpfree()
Zero-fillthestructures
![Page 10: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/10.jpg)
Includefiles
Publicsymbolnames
ErrorreportingfromCfunctions
“Error”statesthatarenoterrors
Whenaremessagessenttotheclient?
RunningqueriesandcallingPostgreSQLfunctions
AsampleCfunctionusingSPI
Visibilityofdatachanges
MoreinfoonSPI_*functions
Handlingrecordsasargumentsorreturnedvalues
Returningasingletupleofacomplextype
Extractingfieldsfromanargumenttuple
Constructingareturntuple
Interlude–whatisDatum?
Returningasetofrecords
Fastcapturingofdatabasechanges
Doingsomethingatcommit/rollback
Synchronizingbetweenbackends
WritingfunctionsinC++
AdditionalresourcesforC
Summary
10.ScalingYourDatabasewithPL/Proxy
Creatingasimplesingle-serverchat
Dealingwithsuccess–splittingtablesovermultipledatabases
Whatexpansionplansworkandwhen?
Movingtoabiggerserver
Master-slavereplication–movingreadstoslave
Multimasterreplication
Datapartitioningacrossmultipleservers
Splittingthedata
PL/Proxy–thepartitioninglanguage
![Page 11: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/11.jpg)
InstallingPL/Proxy
ThePL/Proxylanguagesyntax
CONNECT,CLUSTER,andRUNON
SELECTandTARGET
SPLIT–distributingarrayelementsoverseveralpartitions
Thedistributionofdata
ConfiguringthePL/Proxyclusterusingfunctions
ConfiguringthePL/ProxyclusterusingSQL/MED
Movingdatafromthesingletothepartitioneddatabase
ConnectionPooling
Summary
11.PL/Perl–PerlProceduralLanguage
WhentousePL/Perl
InstallingPL/Perl
AsimplePL/Perlfunction
Passingandreturningnon-scalartypes
WritingPL/Perltriggers
UntrustedPerl
Summary
12.PL/Tcl–TclProceduralLanguage
InstallingPL/Tcl
AsimplePL/Tclfunction
NullcheckingwithStrictfunctions
Theparameterformat
Passingandreturningarrays
Passingcomposite-typearguments
Accessingdatabases
WritingPL/Tcltriggers
UntrustedTcl
Summary
13.PublishingYourCodeasPostgreSQLExtensions
![Page 12: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/12.jpg)
Whentocreateanextension
Unpackagedextensions
Extensionversions
The.controlfile
Buildinganextension
Installinganextension
Viewingextensions
Publishingyourextension
IntroductiontoPostgreSQLExtensionNetwork
Signinguptopublishyourextension
Creatinganextensionprojecttheeasyway
Providingthemetadataabouttheextension
Writingyourextensioncode
Creatingthepackage
SubmittingthepackagetoPGXN
InstallinganextensionfromPGXN
Summary
14.PostgreSQLasanExtensibleRDBMS
Whatcan’tbeextended?
Creatinganewoperator
Overloadinganoperator
Optimizingoperators
COMMUTATOR
NEGATOR
Creatingindexaccessmethods
Creatinguser-definedaggregates
Usingforeigndatawrappers
Summary
Index
![Page 13: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/13.jpg)
![Page 14: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/14.jpg)
PostgreSQLServerProgrammingSecondEdition
![Page 15: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/15.jpg)
![Page 16: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/16.jpg)
PostgreSQLServerProgrammingSecondEditionCopyright©2015PacktPublishing
Allrightsreserved.Nopartofthisbookmaybereproduced,storedinaretrievalsystem,ortransmittedinanyformorbyanymeans,withoutthepriorwrittenpermissionofthepublisher,exceptinthecaseofbriefquotationsembeddedincriticalarticlesorreviews.
Everyefforthasbeenmadeinthepreparationofthisbooktoensuretheaccuracyoftheinformationpresented.However,theinformationcontainedinthisbookissoldwithoutwarranty,eitherexpressorimplied.Neithertheauthors,norPacktPublishing,anditsdealersanddistributorswillbeheldliableforanydamagescausedorallegedtobecauseddirectlyorindirectlybythisbook.
PacktPublishinghasendeavoredtoprovidetrademarkinformationaboutallofthecompaniesandproductsmentionedinthisbookbytheappropriateuseofcapitals.However,PacktPublishingcannotguaranteetheaccuracyofthisinformation.
Firstpublished:June2013
Secondedition:February2015
Productionreference:1210215
PublishedbyPacktPublishingLtd.
LiveryPlace
35LiveryStreet
BirminghamB32PB,UK.
ISBN978-1-78398-058-1
www.packtpub.com
![Page 17: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/17.jpg)
![Page 18: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/18.jpg)
CreditsAuthors
UsamaDar
HannuKrosing
JimMlodgenski
KirkRoybal
Reviewers
StephenFrost
RickvanHattem
VibhorKumar
JeffLawson
MarianoReingart
JulienTachoires
CommissioningEditor
UshaIyer
AcquisitionEditors
AntonyLowe
MeetaRajani
SamWood
ContentDevelopmentEditor
AdrianRaposo
TechnicalEditors
MrunmayeePatil
ChinmayPuranik
CopyEditors
DiptiKapadia
AartiSaldanha
ProjectCoordinator
KinjalBari
Proofreaders
MariaGould
![Page 19: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/19.jpg)
LindaMorris
Indexer
MonicaAjmeraMehta
ProductionCoordinator
NiteshThakur
CoverWork
NiteshThakur
![Page 20: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/20.jpg)
![Page 21: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/21.jpg)
AbouttheAuthorsUsamaDarisaseasonedsoftwaredeveloperandarchitect.Duringhis14years’career,hehasworkedextensivelywithPostgreSQLandotherdatabasetechnologies.HeworkedonPostgreSQLinternalsextensivelywhilehewasworkingforEnterpriseDB.Currently,helivesinMunichwhereheworksforHuawei’sEuropeanResearchCenter.Hedesignsthenextgenerationofhigh-performancedatabasesystemsbasedonopensourcetechnologies,suchasPostgreSQL,whichareusedunderhighworkloadsandstrictperformancerequirements.
HannuKrosingwasaPostgreSQLuserbeforeitwasrewrittentouseSQLasitsmainquerylanguagein1995.Therefore,hehasboththehistoricperspectiveofitsdevelopment,aswellasalmost20yearsofexperienceinusingittosolvevariousreal-lifeproblems.
HewasthefirstdatabaseadministratoranddatabasearchitectatSkype,whereheinventedtheshardinglanguagePL/Proxythatallowsyoutoscaletheuserdatabaseinordertoworkwithbillionsofusers.
AfterheleftSkypeattheendof2006—aboutayearafteritwasboughtbyeBay—hehasbeenworkingasaPostgreSQLconsultantwith2ndQuadrant,thepremierPostgreSQLconsultancywithaglobalreachandlocalpresenceinmostpartsoftheworld.
HehascoauthoredPostgreSQL9AdministrationCookbook,PacktPublishing,togetherwithoneofthemainPostgreSQLdevelopers,SimonRiggs.
Iwanttosincerelythankmywife,Evelyn,forhersupportwhilewritingthisbook.
JimMlodgenskiistheCTOofOpenSCG,aprofessionalservicescompanyfocusedonleveragingopensourcetechnologiesforstrategicadvantage.HewasformerlytheCEOofStormDB,adatabasecloudcompanyfocusedonhorizontalscalability.PriortoStormDB,hehasheldhighlytechnicalrolesatCirrusTechnology,Inc.,EnterpriseDB,andFusionTechnologies.
JimisalsoaferventadvocateofPostgreSQL.HeisontheboardoftheUnitedStatesPostgreSQLAssociationaswellasapartoftheorganizingteamsoftheNewYorkPostgreSQLUserGroupandPhiladelphiaPostgreSQLUserGroup.
KirkRoybalhasbeenanactivememberofthePostgreSQLcommunitysince1998.HehashelpedorganizeusergroupsinHouston,Dallas,andBloomington,IL.Hehasmentoredmanyjuniordatabaseadministratorsandprovidedcross-trainingtoseniordatabaseengineers.HehasprovidedsolutionsusingPostgreSQLforreporting,businessintelligence,datawarehousing,applications,anddevelopmentsupport.
HesawthescopeofPostgreSQLwhenhisfirstsmall-scalebusinesscustomeraskedforawebapplication.Atthattime,competitivedatabaseproductswereeitherextremelyimmatureorcostprohibitive.
KirkhasstoodbyhischoiceofPostgreSQLformanyyearsnow.Hisexpertiseisfoundedonkeepingupwithfeaturesandcapabilitiesastheybecomeavailable.
![Page 22: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/22.jpg)
Writingabookhasbeenauniqueexperienceforme.Manypeoplefantasizeaboutit,fewstartone,andevenfewergettopublication.Iamproudtobepartofateamthatactuallymadeittothebookshelf(whichitselfisadiminishingbreed).ThankstoSarahCullingtonfromPacktPublishingforgivingmeachancetoparticipateintheproject.IbelievethatthePostgreSQLcommunitywillbebetterservedbythisinformation,andIhopethattheyreceivethisasarewardforthetimethattheyhaveinvestedinmeovertheyears.
Abookonlyhasthevaluethatthereadersgiveit.ThankyoutothePostgreSQLcommunityforallthetechnical,personal,andprofessionaldevelopmenthelpyouhaveprovided.ThePostgreSQLcommunityisagreatbunchofpeople,andIhaveenjoyedthecompanyofmanyofthem.Ihopetocontributemoretothisprojectinthefuture,andIhopeyoufindmycontributionsasvaluableasIfindyours.
Thankyoutomyfamilyforgivingmeareasontosucceedandforlisteningtothegobbledygookandnoddingappreciatively.
Haveyoueverhadyourfamilyaskyouwhatyouweredoingandansweredthemwithafunction?Tryit.No,thenagain,don’ttryit.Theymayjusthaveyouinvoluntarilycheckedinsomewhere.
![Page 23: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/23.jpg)
![Page 24: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/24.jpg)
AbouttheReviewersStephenFrostisamajorcontributorandcommittertoPostgreSQL,whohasbeeninvolvedwithPostgreSQLsince2002,andhasdevelopedfeaturessuchastherolesystemandcolumn-levelprivileges.
HeisthechieftechnologyofficeratCrunchyDataSolutions,Inc.,thePostgreSQLcompanyforSecureEnterprises.HeisinvolvedintheadvancementofPostgreSQL’scapabilities,particularlyintheareaofsecurityinordertosupporttheneedsofgovernmentandfinancialinstitutionswhohavestrictsecurityandregulatoryrequirements.
RickvanHattemisanentrepreneurwithacomputersciencebackgroundandalong-timeopensourcedeveloperwithvastexperienceintheC,C++,Python,andJavalanguages.Additionally,hehasworkedwithmostlargedatabaseserverssuchasOracle,MSSQL,andMySQL,buthehasbeenfocusingonPostgreSQLsinceVersion7.4.
HeisoneofthefoundersoftheFashiolista.comsocialnetwork,anduntilrecently,hewastheCTO.Here,heusedPostgreSQLtoscalethefeedsformillionsofuserstoshowthatPostgreSQLcanholduptoNoSQLsolutions,givensometuningandadditionaltools.AfterFashiolista,heworkedasafreelanceconsultantforseveralcompanies,including2ndQuadrant.
HeiscurrentlythefounderofPGMon.com,amonitoringservicethatanalyzesyourdatabases,indexes,andqueriestokeepthemrunningatpeakperformance.Inadditiontoanalyzingyourdatabasesettings,thesystemactivelymonitorsyourqueriesandgivesyourecommendationstoenhanceperformance.
Heisalsothecreatorandmaintainerofalargenumberofopensourceprojects,suchaspg_query_analyser,pg_cascade_timestamp,QtQuery,Python-Statsd,andDjango-Statsd.
VibhorKumarisaprincipalsystemarchitectatEnterpriseDBwhospecializesinassistingFortune100companiestodeploy,manage,andoptimizePostgresdatabases.HejoinedEnterpriseDBin2008toworkwithPostgresafterseveralyearsofworkingwithOraclesystems.HehasworkedinteamleadershiprolesatIBMGlobalServicesandBMCSoftwareaswellasanOracledatabaseadministratoratCMCLtd.forseveralyears.HehasdevelopedexpertiseinOracle,DB2,andMongoDBandholdscertificationsinthem.HehasexperienceworkingwithMSSQLServer,MySQL,anddatawarehousing.Heholdsabachelor’sdegreeincomputersciencefromtheUniversityofLucknowandamaster’sdegreeincomputersciencefromtheArmyInstituteofManagement,Kolkata.HeisacertifiedPostgreSQLtrainerandholdsaprofessionalcertificationinPostgresPlusAdvancedServerfromEnterpriseDB.
JeffLawsonhasbeenafananduserofPostgreSQLsincethetimehediscovereditin2001.Overtheyears,hehasalsodevelopedanddeployedapplicationsforIBMDB2,Oracle,MySQL,MicrosoftSQLServer,Sybase,andothers,buthealwaysprefersPostgreSQLforitsbalanceoffeaturesandopenness.MuchofhisexperienceinvolvesdevelopingforInternet-facingwebsites/projectsthatrequirehighlyscalabledatabaseswithhighavailabilityorwithprovisionsfordisasterrecovery.
![Page 25: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/25.jpg)
HecurrentlyworksasthedirectorofsoftwaredevelopmentforFlightAware,whichisanairplane-trackingwebsitethatusesPostgreSQLandotheropensourcesoftwaretostoreandanalyzethepositionsofthethousandsofflightsthatareoperatedworldwideeveryday.Hehasextensiveexperienceinsoftwarearchitecture,datasecurity,andnetworkprotocoldesignfromthesoftwareengineeringpositionshehasheldatUniva/UnitedDevices,Microsoft,NASA’sJetPropulsionLaboratory,andWolfeTech.Heisafounderofdistributed.net,whichpioneereddistributedcomputinginthe1990s,andhecontinuestoserveasthechiefofoperationsandasamemberoftheboardthere.HeearnedaBScdegreeincomputersciencefromHarveyMuddCollege.
Heisfondofcattle,holdsanFAAprivatepilotcertificate,andownsanairplanebasedinHouston,Texas.
MarianoReingartlivesinBuenosAires,Argentina,andisaspecialistinthesoftwaredevelopmentofapplicationsandlibraries(webservices,PDF,GUI,replication,andsoon)withmorethan10yearsofexperience.Currently,heisthePostgreSQLregionalcontactforArgentinaandaPythonSoftwareFoundationmember.
Heisamajorcontributortotheweb2pyPythonwebframework,andnowhe’sworkingonthewxWidgetsmultiplatformGUItoolkit(specificallyintheQtportandAndroidmobileareas).Also,hehascontributedtomorethanadozenopensourceprojects,includinganinterfaceforFreeElectronicInvoicewebservices(PyAfipWs)andPythonicreplicationforPostgreSQL(PyReplica).
Hehasabachelor’sdegreeincomputersystemsanalysis,andcurrently,he’samaster’scandidatefortheMScinfreesoftwaredegreeattheOpenUniversityofCatalonia.
Heworksonhisownfundedentrepreneurialventureformedbyanopengroupofindependentprofessionals,dedicatedtosoftwaredevelopment,training,andtechnicalsupport,focusingonopensourcetools(GNU/Linux,Python,PostgreSQL,andweb2py/wxPython).
HehasworkedforlocalPython-basedcompaniesinlargebusinessapplications(ERP,SCM,andCRM)andmissioncriticalsystems(electioncounting,electronicvoting,and911emergencyeventssupport).Hehascontributedtobookssuchasweb2pyEnterpriseWebFramework,ThirdEdition,andweb2pyApplicationDevelopmentCookbook,PacktPublishing,andseveralSpanishtranslationsofthePostgreSQLofficialdocumentation.
Hisfullresumeisavailableathttp://reingart.blogspot.com/p/resume.html.
JulienTachoiresisaPostgreSQLspecialist,whoworksasconsultantfortheFrenchPostgreSQLcompanyDalibo.Heisthemaindeveloperofpg_activity,atop-endsoftwarededicatedtofollowthePostgreSQLincomingtrafficinrealtime,whichiswritteninPython.
IwanttothankmyemployerDalibo;mywife,Camille;andmyson,Arthur.
![Page 26: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/26.jpg)
![Page 27: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/27.jpg)
www.PacktPub.com
![Page 28: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/28.jpg)
Supportfiles,eBooks,discountoffers,andmoreForsupportfilesanddownloadsrelatedtoyourbook,pleasevisitwww.PacktPub.com.
DidyouknowthatPacktofferseBookversionsofeverybookpublished,withPDFandePubfilesavailable?YoucanupgradetotheeBookversionatwww.PacktPub.comandasaprintbookcustomer,youareentitledtoadiscountontheeBookcopy.Getintouchwithusat<[email protected]>formoredetails.
Atwww.PacktPub.com,youcanalsoreadacollectionoffreetechnicalarticles,signupforarangeoffreenewslettersandreceiveexclusivediscountsandoffersonPacktbooksandeBooks.
https://www2.packtpub.com/books/subscription/packtlib
DoyouneedinstantsolutionstoyourITquestions?PacktLibisPackt’sonlinedigitalbooklibrary.Here,youcansearch,access,andreadPackt’sentirelibraryofbooks.
![Page 29: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/29.jpg)
Whysubscribe?FullysearchableacrosseverybookpublishedbyPacktCopyandpaste,print,andbookmarkcontentOndemandandaccessibleviaawebbrowser
![Page 30: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/30.jpg)
FreeaccessforPacktaccountholdersIfyouhaveanaccountwithPacktatwww.PacktPub.com,youcanusethistoaccessPacktLibtodayandview9entirelyfreebooks.Simplyuseyourlogincredentialsforimmediateaccess.
![Page 31: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/31.jpg)
![Page 32: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/32.jpg)
PrefaceThisfascinatingguidetoserverprogrammingwilltakeyourskillsofPostgreSQLtoawholenewlevel.Astep-by-stepapproachwithilluminatingexampleswilleducateyouaboutthefullrangeofpossibilities.YouwillunderstandtheextensionframeworkofPostgreSQLandleverageitinwaysyouhaven’teveninventedyet.Youwilllearnhowtowritefunctionsandcreateyourowndatatypes,allinyourfavoriteprogramminglanguage.Itisastep-by-steptutorial,withplentyoftipsandtrickstokick-startserverprogramming.
![Page 33: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/33.jpg)
WhatthisbookcoversChapter1,WhatIsaPostgreSQLServer?,introducesyoutothePostgreSQLserverandwillsetthetonefortherestofthebook.ItintroducesyoutothewaysinwhichaPostgreSQLserverisextendible,andshowsyouthatitcanbetreatedasacompletesoftwaredevelopmentframeworkinsteadofjustadatabaseserver.
Chapter2,ServerProgrammingEnvironments,elaboratesthatPostgreSQLisbuilttohandleuserneeds,butmoreimportantly,itisbuiltnottochangeunderneathusersinthefuture.ItwilltouchupontheenvironmentsandwillhighlightsomeoftheimportantthingstobekeptinmindwhenprogrammingontheserverinPostgreSQL.
Chapter3,YourFirstPL/pgSQLFunction,buildsthefoundationsbydemonstratinghowtowritesimplePL/pgSQLfunctions.
Chapter4,ReturningStructuredData,buildsontheknowledgeofwritingPL/pgSQLfunctionsanddemonstrateshowtowritefunctionsthatreturnasetofvaluessuchasrows,arrays,andcursors.
Chapter5,PL/pgSQLTriggerFunctions,discusseshowtowritePL/pgSQLfunctionsthatareusedtowritetriggerlogic.ItalsodiscussesthevarioustypesoftriggersavailableinPostgreSQLandtheoptionsthatadatabasedeveloperhaswhenwritingsuchfunctions.
Chapter6,PostgreSQLEventTriggers,discussesPostgreSQL’seventtriggerfunctionality.EventtriggersarefiredwhenrunningaDDLoperationonatable.ThischapterdiscussesthevariouspossibilitiesandoptionsofcreatingeventtriggersandtheirlimitationsinPostgreSQL.
Chapter7,DebuggingPL/pgSQL,elaboratesonhowtodebugPL/pgSQL’sstoredproceduresandfunctionsinPostgreSQL.ThischapterexplainshowtoinstallthedebuggerpluginandusethepgAdmindebuggerconsole.
Chapter8,UsingUnrestrictedLanguages,explainsthedifferencesbetweenrestrictedandunrestrictedPostgreSQLlanguages.ThischapterusesPL/PythonasanexampleanddemonstratestheexamplesofbothrestrictedandunrestrictedfunctionsinPL/Python.
Chapter9,WritingAdvancedFunctionsinC,explainshowtoextendPostgreSQLbywritinguser-definedfunctions(UDFs)inC.
Chapter10,ScalingYourDatabasewithPL/Proxy,explainstheuseofaspecialprogramminglanguageinPostgreSQLcalledPL/Proxyandhowtouseitinordertopartitionandshardyourdatabase.
Chapter11,PL/Perl–PerlProceduralLanguage,discussesapopularPLlanguageinPostgreSQLcalledPL/Perl.ThischapterusessomesimpleexamplestodemonstratehowyoucanusePerltowritedatabasefunctions.
Chapter12,PL/Tcl–TclProceduralLanguage,discussesTclasalanguageofchoicewhenwritingdatabasefunctions.ItdiscussestheprosandconsofusingTclinthedatabase.
![Page 34: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/34.jpg)
Chapter13,PublishingYourCodeasPostgreSQLExtensions,discusseshowtopackageanddistributethePostgreSQLextensions.Well-packagedextensionscanbeeasilydistributedandinstalledbyotherusers.ThischapteralsointroducesyoutothePostgreSQLExtensionNetwork(PGXN)andshowsyouhowtouseittogettheextensionspublishedbyotherdevelopers.
Chapter14,PostgreSQLasanExtensibleRDBMS,discussesmoreextensibilityoptionsinPostgreSQL,suchascreatingnewdatatypes,operators,andindexmethods.
![Page 35: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/35.jpg)
![Page 36: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/36.jpg)
WhatyouneedforthisbookInordertofollowthisbook,youneedthefollowingsoftware:
PostgreSQLDatabaseServer9.4Linux/UnixOperatingSystemPython2,Perl,andTcl
![Page 37: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/37.jpg)
![Page 38: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/38.jpg)
WhothisbookisforThisbookisformoderatetoadvancedlevelPostgreSQLdatabaseprofessionals.Togetabetterunderstandingofthisbook,youshouldhaveageneralexperienceinwritingSQL,abasicideaofquerytuning,andsomecodingexperienceinalanguageofyourchoice.
![Page 39: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/39.jpg)
![Page 40: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/40.jpg)
ConventionsInthisbook,youwillfindanumberoftextstylesthatdistinguishbetweendifferentkindsofinformation.Herearesomeexamplesofthesestylesandanexplanationoftheirmeaning.
Codewordsintext,databasetablenames,foldernames,filenames,fileextensions,pathnames,dummyURLs,userinput,andTwitterhandlesareshownasfollows:“Ifanyofthechecksfail,youshoulddoROLLBACKinsteadofCOMMIT.”
Ablockofcodeissetasfollows:
CREATETABLEaccounts(ownertext,balancenumeric,amountnumeric);
INSERTINTOaccountsVALUES('Bob',100);
INSERTINTOaccountsVALUES('Mary',200);
Whenwewishtodrawyourattentiontoaparticularpartofacodeblock,therelevantlinesoritemsaresetinbold:
CREATEORREPLACEFUNCTIONfibonacci_seq(numinteger)
RETURNSSETOFintegerAS$$
DECLARE
aint:=0;
bint:=1;
BEGIN
IF(num<=0)
THENRETURN;
ENDIF;
RETURNNEXTa;
LOOP
EXITWHENnum<=1;
RETURNNEXTb;
num=num-1;
SELECTb,a+bINTOa,b;
ENDLOOP;
END;
$$LANGUAGEplpgsql;
Anycommand-lineinputoroutputiswrittenasfollows:
$psql-c"SELECT1AStest"
Newtermsandimportantwordsareshowninbold.Wordsthatyouseeonthescreen,forexample,inmenusordialogboxes,appearinthetextlikethis:“Entersomevaluesintothecolumns,asseenintheprecedingscreenshot,andclickontheDebugbutton.”
NoteWarningsorimportantnotesappearinaboxlikethis.
TipTipsandtricksappearlikethis.
![Page 41: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/41.jpg)
![Page 42: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/42.jpg)
![Page 43: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/43.jpg)
ReaderfeedbackFeedbackfromourreadersisalwayswelcome.Letusknowwhatyouthinkaboutthisbook—whatyoulikedordisliked.Readerfeedbackisimportantforusasithelpsusdeveloptitlesthatyouwillreallygetthemostoutof.
Tosendusgeneralfeedback,simplye-mail<[email protected]>,andmentionthebook’stitleinthesubjectofyourmessage.
Ifthereisatopicthatyouhaveexpertiseinandyouareinterestedineitherwritingorcontributingtoabook,seeourauthorguideatwww.packtpub.com/authors.
![Page 44: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/44.jpg)
![Page 45: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/45.jpg)
CustomersupportNowthatyouaretheproudownerofaPacktbook,wehaveanumberofthingstohelpyoutogetthemostfromyourpurchase.
![Page 46: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/46.jpg)
DownloadingtheexamplecodeYoucandownloadtheexamplecodefilesfromyouraccountathttp://www.packtpub.comforallthePacktPublishingbooksyouhavepurchased.Ifyoupurchasedthisbookelsewhere,youcanvisithttp://www.packtpub.com/supportandregistertohavethefilese-maileddirectlytoyou.
![Page 47: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/47.jpg)
ErrataAlthoughwehavetakeneverycaretoensuretheaccuracyofourcontent,mistakesdohappen.Ifyoufindamistakeinoneofourbooks—maybeamistakeinthetextorthecode—wewouldbegratefulifyoucouldreportthistous.Bydoingso,youcansaveotherreadersfromfrustrationandhelpusimprovesubsequentversionsofthisbook.Ifyoufindanyerrata,pleasereportthembyvisitinghttp://www.packtpub.com/submit-errata,selectingyourbook,clickingontheErrataSubmissionFormlink,andenteringthedetailsofyourerrata.Onceyourerrataareverified,yoursubmissionwillbeacceptedandtheerratawillbeuploadedtoourwebsiteoraddedtoanylistofexistingerrataundertheErratasectionofthattitle.
Toviewthepreviouslysubmittederrata,gotohttps://www.packtpub.com/books/content/supportandenterthenameofthebookinthesearchfield.TherequiredinformationwillappearundertheErratasection.
![Page 48: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/48.jpg)
PiracyPiracyofcopyrightedmaterialontheInternetisanongoingproblemacrossallmedia.AtPackt,wetaketheprotectionofourcopyrightandlicensesveryseriously.IfyoucomeacrossanyillegalcopiesofourworksinanyformontheInternet,pleaseprovideuswiththelocationaddressorwebsitenameimmediatelysothatwecanpursuearemedy.
Pleasecontactusat<[email protected]>withalinktothesuspectedpiratedmaterial.
Weappreciateyourhelpinprotectingourauthorsandourabilitytobringyouvaluablecontent.
![Page 49: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/49.jpg)
QuestionsIfyouhaveaproblemwithanyaspectofthisbook,youcancontactusat<[email protected]>,andwewilldoourbesttoaddresstheproblem.
![Page 50: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/50.jpg)
![Page 51: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/51.jpg)
Chapter1.WhatIsaPostgreSQLServer?IfyouthinkthataPostgreSQLServerisjustastoragesystemandtheonlywaytocommunicatewithitisbyexecutingSQLstatements,youarelimitingyourselftremendously.Thatis,youareusingjustatinypartofthedatabase’sfeatures.
APostgreSQLServerisapowerfulframeworkthatcanbeusedforallkindsofdataprocessing,andevensomenon-dataservertasks.Itisaserverplatformthatallowsyoutoeasilymixandmatchfunctionsandlibrariesfromseveralpopularlanguages.
Considerthiscomplicated,multilanguagesequenceofwork:
CallastringparsingfunctioninPerlConvertthestringtoXSLTandprocesstheresultusingJavaScriptAskforasecurestampfromanexternaltimestampingservice,suchashttp://guardtime.com/,usingtheirSDKforCWriteaPythonfunctiontodigitallysigntheresult
Thismultilanguagesequenceofworkcanbeimplementedasaseriesofsimplefunctioncallsusingseveraloftheavailableserverprogramminglanguages.ThedeveloperwhoneedstoaccomplishallthisworkcanjustcallasinglePostgreSQLfunctionwithouttheneedtobeawareofhowthedataisbeingpassedbetweenlanguagesandlibraries:
SELECTconvert_to_xslt_and_sign(raw_data_string);
Inthisbook,wewilldiscussseveralfacetsofPostgreSQLServerprogramming.PostgreSQLhasallofthenativeserver-sideprogrammingfeaturesavailableinmostlargerdatabasesystemssuchastriggers,whichareautomatedactionsinvokedautomaticallyeachtimedataischanged.However,ithasuniquelydeepabilitiestooverridethebuilt-inbehaviordowntoverybasicoperators.ThisuniquePostgreSQLabilitycomesfromitscatalog-drivendesign,whichstoresinformationaboutdatatypes,functions,andaccessmethods.TheabilityofPostgreSQLtoloaduser-definedfunctionsviadynamicloadingmakesitrapidlychangeablewithouthavingtorecompilethedatabaseitself.Thereareseveralthingsyoucandowiththisflexibilityofcustomization.Someexamplesofthiscustomizationincludethefollowing:
Writinguser-definedfunctions(UDF)tocarryoutcomplexcomputationsAddingcomplicatedconstraintstomakesurethatthedataintheservermeetsguidelinesCreatingtriggersinmanylanguagestomakerelatedchangestoothertables,auditchanges,forbidtheactionfromtakingplaceifitdoesnotmeetcertaincriteria,preventchangestothedatabase,enforceandexecutebusinessrules,orreplicatedataDefiningnewdatatypesandoperatorsinthedatabaseUsingthegeographytypesdefinedinthePostGISpackageAddingyourownindexaccessmethodsforeithertheexistingornewdatatypes,makingsomequeriesmuchmoreefficient
Whatsortofthingscanyoudowiththesefeatures?Therearelimitlesspossibilities,such
![Page 52: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/52.jpg)
astheoneslistedhere:
Writedataextractorfunctionstogetjusttheinterestingpartsfromstructureddata,suchasXMLorJSON,withoutneedingtoshipthewhole,possiblyhuge,documenttotheclientapplication.Processeventsasynchronously,suchassendingmailswithoutslowingdownthemainapplication.Youcancreateamailqueueforchangestouserinformation,populatedbyatrigger.Aseparatemail-sendingprocesscanconsumethisdatawheneveritisnotifiedbyanapplicationprocess.Implementanewdatatypetocustomhashthepasswords.Writefunctions,whichprovideinsideinformationabouttheserver,forexample,cachecontents,table-wiselockinformation,ortheSSLcertificateinformationofaclientconnectionforamonitoringdashboard.
Therestofthischapterispresentedasaseriesofdescriptionsofcommondatamanagementtasks,showinghowtheycanbesolvedinarobustandelegantwayviaserverprogramming.
NoteThesamplesinthischapterarealltestedtowork,buttheycomewithminimalcommentary.Theyareusedherejusttoshowyouvariousthingsthatserverprogrammingcanaccomplish.Thetechniquesthataredescribedwillbeexplainedthoroughlyinlaterchapters.
![Page 53: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/53.jpg)
Whyprogramintheserver?Developersprogramtheircodeinanumberofdifferentlanguages,anditcanbedesignedtorunjustaboutanywhere.Whenwritinganapplication,somepeoplefollowthephilosophythatasmuchofthelogicaspossiblefortheapplicationshouldbepushedtotheclient.WeseethisintheexplosionofapplicationsleveragingJavaScriptinsidebrowsers.Othersliketopushthelogicintothemiddletier,withanapplicationserverhandlingthebusinessrules.Theseareallvalidwaystodesignanapplication,sowhywillyouwanttoprograminthedatabaseserver?
Let’sstartwithasimpleexample.Manyapplicationsincludealistofcustomerswhohaveabalanceintheiraccount.We’llusethissampleschemaanddata:
CREATETABLEaccounts(ownertext,balancenumeric,amountnumeric);
INSERTINTOaccountsVALUES('Bob',100);
INSERTINTOaccountsVALUES('Mary',200);
TipDownloadingtheexamplecode
YoucandownloadtheexamplecodefilesforallthePacktbooksyouhavepurchasedfromyouraccountathttp://www.packtpub.com.Ifyoupurchasedthisbookelsewhere,youcanvisithttp://www.packtpub.com/supportandregistertohavethefilese-maileddirectlytoyou.
Whenusingadatabase,themostcommonwaytointeractwithit,istouseSQLqueries.Ifyouwanttomove14dollarsfromBob’saccounttoMary’saccountwithsimpleSQL,youcandosousingthefollowing:
UPDATEaccountsSETbalance=balance-14.00WHEREowner='Bob';
UPDATEaccountsSETbalance=balance+14.00WHEREowner='Mary';
However,youalsohavetomakesurethatBobactuallyhasenoughmoney(orcredit)inhisaccount.Notethatifanythingfails,thennoneofthetransactionswillhappen.Inanapplicationprogram,thisishowtheprecedingcodesnippetwillbemodified:
BEGIN;
SELECTamountFROMaccountsWHEREowner='Bob'FORUPDATE;—nowinthe
applicationcheckthattheamountisactuallybigger—than14
UPDATEaccountsSETamount=amount-14.00WHEREowner='Bob';
UPDATEaccountsSETamount=amount+14.00WHEREowner='Mary';
COMMIT;
DidMaryactuallyhaveanaccount?Ifshedidnot,thelastUPDATEcommandwillsucceedbyupdatingzerorows.Ifanyofthechecksfail,youshoulddoROLLBACKinsteadofCOMMIT.Onceyouhavedoneallthisforalltheclientsthattransfermoney,anewrequirementwillinvariablyarrive.Perhaps,theminimumamountthatcanbetransferredisnow5.00.Youwillneedtorevisitthecodeinallyourclientsagain.
So,whatcanyoudotomakeallofthismoremanageable,secure,androbust?Thisiswhereserverprogramming,executingcodeonthedatabaseserveritself,canhelp.Youcan
![Page 54: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/54.jpg)
movethecomputations,checks,anddatamanipulationsentirelyintoaUDFontheserver.Thisnotonlyensuresthatyouhaveonlyonecopyofoperationlogictomanage,butalsomakesthingsfasterbynotrequiringseveralroundtripsbetweentheclientandtheserver.Ifrequired,youcanalsomakesurethatonlytheessentialinformationisgivenoutfromthedatabase.Forexample,thereisnobusinessformostclientapplicationstoknowhowmuchmoneyBobhasinhisaccount.Mostly,theyonlyneedtoknowwhetherthereisenoughmoneytomakethetransfer,ortobemorespecific,whetherthetransactionsucceeded.
![Page 55: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/55.jpg)
UsingPL/pgSQLforintegritychecksPostgreSQLincludesitsownprogramminglanguagenamedPL/pgSQLthatisaimedtointegrateeasilywithSQLcommands.PLstandsforprocedurallanguage,andthisisjustoneofthemanylanguagesavailableforwritingservercode.pgSQListheshorthandforPostgreSQL.
UnlikebasicSQL,PL/pgSQLincludesproceduralelements,suchastheabilitytousetheif/then/elsestatementsandloops.YoucaneasilyexecuteSQLstatements,orevenloopovertheresultofaSQLstatementinthelanguage.
TheintegritychecksneededfortheapplicationcanbedoneinaPL/pgSQLfunctionthattakesthreearguments:namesofthepayerandtherecipientandtheamounttobepaid.Thissamplealsoreturnsthestatusofthepayment:
CREATEORREPLACEFUNCTIONtransfer(
i_payertext,
i_recipienttext,
i_amountnumeric(15,2))
RETURNStext
AS
$$
DECLARE
payer_balnumeric;
BEGIN
SELECTbalanceINTOpayer_bal
FROMaccounts
WHEREowner=i_payerFORUPDATE;
IFNOTFOUNDTHEN
RETURN'Payeraccountnotfound';
ENDIF;
IFpayer_bal<i_amountTHEN
RETURN'Notenoughfunds';
ENDIF;
UPDATEaccounts
SETbalance=balance+i_amount
WHEREowner=i_recipient;
IFNOTFOUNDTHEN
RETURN'Recipientdoesnotexist';
ENDIF;
UPDATEaccounts
SETbalance=balance-i_amount
WHEREowner=i_payer;
RETURN'OK';
END;
$$LANGUAGEplpgsql;
Hereareafewexamplesoftheusageofthisfunction,assumingthatyouhaven’texecutedthepreviouslyproposedUPDATEstatementsyet:
postgres=#SELECT*FROMaccounts;
owner|balance
![Page 56: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/56.jpg)
-------+---------
Bob|100
Mary|200
(2rows)
postgres=#SELECTtransfer('Bob','Mary',14.00);
transfer
----------
OK
(1row)
postgres=#SELECT*FROMaccounts;
owner|balance
-------+---------
Mary|214.00
Bob|86.00
(2rows)
Yourapplicationwillneedtocheckthereturncodeanddecidehowtohandletheseerrors.Aslongasitiswrittentorejectanyunexpectedvalue,youcanextendthisfunctiontodomorechecking,suchastheminimumtransferrableamount,andyoucanbesureitwillbeprevented.Thefollowingthreeerrorscanbereturned:
postgres=#SELECT*FROMtransfer('Fred','Mary',14.00);
transfer
-------------------------
Payeraccountnotfound
(1row)
postgres=#SELECT*FROMtransfer('Bob','Fred',14.00);
transfer
--------------------------
Recipientdoesnotexist
(1row)
postgres=#SELECT*FROMtransfer('Bob','Mary',500.00);
transfer
------------------
Notenoughfunds
(1row)
Forthesecheckstoalwayswork,youwillneedtomakeallthetransferoperationsgothroughthefunction,ratherthanmanuallychangingthevalueswithSQLstatements.Onewaytoachievethis,isbyrevokingupdateprivilegesfromusersandfromauserwithhigherprivilegesthatdefinethetransferfunctionwithSECURITYDEFINER.Thiswillallowtherestricteduserstorunthefunctionasiftheyhavehigherprivilegessimilartothefunction’screator.
![Page 57: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/57.jpg)
![Page 58: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/58.jpg)
Aboutthisbook’scodeexamplesThesampleoutputshownherehasbeencreatedwiththepsqlutilityofPostgreSQL,usuallyrunningonaLinuxsystem.MostofthecodewillworkthesamewayifyouareusingaGUIutilitysuchaspgAdmin3toaccesstheserverinstead.Takeanexampleofthefollowinglineofcode:
postgres=#SELECT1;
Thepostgres=#partisthepromptshownbythepsqlcommand.
TheexamplesinthisbookhavebeentestedusingPostgreSQL9.3.TheywillprobablyworkonPostgreSQLVersion8.3andlater.Therehaven’tbeenmanymajorchangestohowserverprogramminghappensinthelastfewversionsofPostgreSQL.Thesyntaxhasbecomestricterovertimetoreducethepossibilityofmistakesintheserverprogrammingcode.Duetothenatureofthesechanges,mostcodefromnewerversionswillstillrunontheolderones,unlessitusesverynewfeatures.However,theoldercodecaneasilyfailtorunduetooneofthenewlyenforcedrestrictions.
![Page 59: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/59.jpg)
SwitchingtotheexpandeddisplayWhenusingthepsqlutilitytoexecuteaquery,PostgreSQLnormallyoutputstheresultusingverticallyalignedcolumns:
$psql-c"SELECT1AStest"
test
------
1
(1row)
$psql
psql(9.3.2)
Type"help"forhelp.
postgres=#SELECT1AStest;
test
------
1
(1row)
Youcantellwhenyou’reseeingaregularoutputbecauseitwillendupshowingthenumberofrows.
Thistypeofoutputishardtofitintothetextofabooksuchasthis.It’seasiertoprinttheoutputfromwhattheprogramcallstheexpandeddisplay,whichbreakseachcolumnintoaseparateline.Youcanswitchtotheexpandeddisplayusingeitherthe-xcommand-lineswitchorbysending\xtothepsqlprogram.Here’sanexampleofusingeachofthese:
$psql-x-c"SELECT1AStest"
-[RECORD1]
test|1
$psql
psql(9.3.2)
Type"help"forhelp.
postgres=#\x
Expandeddisplayison.
postgres=#SELECT1AStest;
-[RECORD1]
test|1
Noticehowtheexpandedoutputdoesn’tshowtherowcountandnumberseachoutputrow.Tosavespace,notalloftheexamplesinthebookwillshowtheexpandedoutputbeingturnedon.Youcannormallytellwhichtypeyoucansee,bydifferencessuchaswhetheryou’reseeingrowsorRECORD.Theexpandedmodewillnormallybepreferredwhentheoutputofthequeryistoowidetofitintotheavailablewidthofthebook.Itisagoodideatosettheexpandedmodetoauto.Thiswillautomaticallyswitchtoexpandedmodefortableswithalotofcolumns.Youcanturnontheexpandedmodeusing\xauto:
postgres=#\xauto
Expandeddisplayisusedautomatically.
![Page 60: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/60.jpg)
![Page 61: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/61.jpg)
MovingbeyondsimplefunctionsServerprogrammingcanmeanalotofdifferentthings.Serverprogrammingisnotjustaboutwritingserverfunctions.Therearemanyotherthingsyoucandointheserver,whichcanbeconsideredasprogramming.
![Page 62: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/62.jpg)
DatacomparisonsusingoperatorsFormorecomplextasks,youcandefineyourowntypes,operators,andcastsfromonetypetoanother,lettingyouactuallycompareapplesandoranges.
Asshowninthenextexample,youcandefinethetypefruit_qtyforfruit-with-quantityandthenteachPostgreSQLtocompareapplesandoranges,saytomakeoneorangetobeworth1.5apples,inordertoconvertapplestooranges:
postgres=#CREATETYPEFRUIT_QTYas(nametext,qtyint);
postgres=#SELECT'("APPLE",3)'::FRUIT_QTY;
fruit_qty
----------------
(APPLE,3)
(1row)
CREATEFUNCTIONfruit_qty_larger_than(left_fruitFRUIT_QTY,right_fruit
FRUIT_QTY)
RETURNSBOOL
AS$$
BEGIN
IF(left_fruit.name='APPLE'ANDright_fruit.name='ORANGE')
THEN
RETURNleft_fruit.qty>(1.5*right_fruit.qty);
ENDIF;
IF(left_fruit.name='ORANGE'ANDright_fruit.name='APPLE')
THEN
RETURN(1.5*left_fruit.qty)>right_fruit.qty;
ENDIF;
RETURNleft_fruit.qty>right_fruit.qty;
END;
$$
LANGUAGEplpgsql;
postgres=#SELECTfruit_qty_larger_than('("APPLE",
3)'::FRUIT_QTY,'("ORANGE",2)'::FRUIT_QTY);
fruit_qty_larger_than
-----------------------
f
(1row)
postgres=#SELECTfruit_qty_larger_than('("APPLE",
4)'::FRUIT_QTY,'("ORANGE",2)'::FRUIT_QTY);
fruit_qty_larger_than
-----------------------
t
(1row)
CREATEOPERATOR>(
leftarg=FRUIT_QTY,
rightarg=FRUIT_QTY,
procedure=fruit_qty_larger_than,
commutator=>
);
![Page 63: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/63.jpg)
postgres=#SELECT'("ORANGE",2)'::FRUIT_QTY>'("APPLE",2)'::FRUIT_QTY;
?column?
----------
t
(1row)
postgres=#SELECT'("ORANGE",2)'::FRUIT_QTY>'("APPLE",3)'::FRUIT_QTY;
?column?
----------
f
(1row)
![Page 64: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/64.jpg)
![Page 65: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/65.jpg)
ManagingrelateddatawithtriggersServerprogrammingcanalsomeansettingupautomatedactions(triggers),sothatsomeoperationsinthedatabasecausesomeotherthingstohappenaswell.Forexample,youcansetupaprocesswheremakinganofferonsomeitemsisautomaticallyreservedtothembeinginthestocktable.
So,let’screateafruitstocktable,asshownhere:
CREATETABLEfruits_in_stock(
nametextPRIMARYKEY,
in_stockintegerNOTNULL,
reservedintegerNOTNULLDEFAULT0,
CHECK(in_stockbetween0and1000),
CHECK(reserved<=in_stock)
);
TheCHECKconstraintsmakesurethatsomebasicrulesarefollowed:youcan’thavemorethan1000fruitsinstock(they’llprobablygobad),youcan’thaveanegativestock,andyoucan’treservemorethanwhatyouhave.Thefruit_offertablewillcontainthefruitsfromstockwhichareonoffer.Whenweinsertarowinthefruit_offertable.Theofferedamountwillbereservedinthestocktableasshown:
CREATETABLEfruit_offer(
offer_idserialPRIMARYKEY,
recipient_nametext,
offer_datetimestampdefaultcurrent_timestamp,
fruit_nametextREFERENCESfruits_in_stock,
offered_amountinteger
);
TheoffertablehasanIDfortheoffer(soyoucandistinguishbetweenofferslater),recipient,date,offeredfruitname,andofferedamount.
Inordertoautomatethereservationmanagement,youfirstneedaTRIGGERfunction,whichimplementsthemanagementlogic:
CREATEORREPLACEFUNCTIONreserve_stock_on_offer()RETURNStriggerAS$$
BEGIN
IFTG_OP='INSERT'THEN
UPDATEfruits_in_stock
SETreserved=reserved+NEW.offered_amount
WHEREname=NEW.fruit_name;
ELSIFTG_OP='UPDATE'THEN
UPDATEfruits_in_stock
SETreserved=reserved-OLD.offered_amount
+NEW.offered_amount
WHEREname=NEW.fruit_name;
ELSIFTG_OP='DELETE'THEN
UPDATEfruits_in_stock
SETreserved=reserved-OLD.offered_amount
WHEREname=OLD.fruit_name;
ENDIF;
RETURNNEW;
![Page 66: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/66.jpg)
END;
$$LANGUAGEplpgsql;
YouhavetotellPostgreSQLtocallthisfunctioneachandeverytimetheofferrowischanged:
CREATETRIGGERmanage_reserve_stock_on_offer_change
AFTERINSERTORUPDATEORDELETEONfruit_offerFOREACHROWEXECUTE
PROCEDUREreserve_stock_on_offer();
Afterthis,wearereadytotestthefunctionality.First,wewilladdsomefruitstoourstock:
INSERTINTOfruits_in_stockVALUES('APPLE',500);
INSERTINTOfruits_in_stockVALUES('ORANGE',500);
Then,wewillcheckthestock(usingtheexpandeddisplay):
postgres=#\x
Expandeddisplayison.
postgres=#SELECT*FROMfruits_in_stock;
-[RECORD1]----
name|APPLE
in_stock|500
reserved|0
-[RECORD2]----
name|ORANGE
in_stock|500
reserved|0
Next,let’smakeanofferof100applestoBob:
postgres=#INSERTINTO
fruit_offer(recipient_name,fruit_name,offered_amount)
VALUES('Bob','APPLE',100);
INSERT01
postgres=#SELECT*FROMfruit_offer;
-[RECORD1]--+---------------------------
offer_id|1
recipient_name|Bob
offer_date|2013-01-2515:21:15.281579
fruit_name|APPLE
offered_amount|100
Oncheckingthestock,weseethatindeed100applesarereserved,asshowninthefollowingcodesnippet:
postgres=#SELECT*FROMfruits_in_stock;
-[RECORD1]----
name|ORANGE
in_stock|500
reserved|0
-[RECORD2]----
name|APPLE
in_stock|500
reserved|100
Ifwechangetheofferedamount,thereservedamountalsochanges:
![Page 67: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/67.jpg)
postgres=#UPDATEfruit_offerSEToffered_amount=115WHEREoffer_id=1;
UPDATE1
postgres=#SELECT*FROMfruits_in_stock;
-[RECORD1]----
name|ORANGE
in_stock|500
reserved|0
-[RECORD2]----
name|APPLE
in_stock|500
reserved|115
Wealsogetsomeextrabenefits.First,becauseoftheconstraintonthestocktable,youcan’tsellthereservedapples:
postgres=#UPDATEfruits_in_stockSETin_stock=100WHEREname='APPLE';
ERROR:newrowforrelation"fruits_in_stock"violatescheckconstraint
"fruits_in_stock_check"
DETAIL:Failingrowcontains(APPLE,100,115).
Moreinterestingly,youalsocan’treservemorethanyouhave,eventhoughtheconstraintsareonanothertable:
postgres=#UPDATEfruit_offerSEToffered_amount=1100WHEREoffer_id=1;
ERROR:newrowforrelation"fruits_in_stock"violatescheckconstraint
"fruits_in_stock_check"
DETAIL:Failingrowcontains(APPLE,500,1100).
CONTEXT:SQLstatement"UPDATEfruits_in_stock
SETreserved=reserved-OLD.offered_amount
+NEW.offered_amount
WHEREname=NEW.fruit_name"
PL/pgSQLfunctionreserve_stock_on_offer()line8atSQLstatement
Whenyoufinallydeletetheoffer,thereservationisreleased:
postgres=#DELETEFROMfruit_offerWHEREoffer_id=1;
DELETE1
postgres=#SELECT*FROMfruits_in_stock;
-[RECORD1]----
name|ORANGE
in_stock|500
reserved|0
-[RECORD2]----
name|APPLE
in_stock|500
reserved|0
Inarealsystem,youprobablywillarchivetheoldofferbeforedeletingit.
![Page 68: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/68.jpg)
![Page 69: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/69.jpg)
AuditingchangesIfyouneedtoknowwhodidwhattothedataandwhenitwasdone,onewaytofindoutistologeveryactionthatisperformedinanimportanttable.InPostgreSQL9.3,youcanalsoauditthedatadefinitionlanguage(DDL)changestothedatabaseusingeventtriggers.Wewilllearnmoreaboutthisinthelaterchapters.
Thereareatleasttwoequallyvalidwaystoperformdataauditing:
UsingauditingtriggersAllowingtablestobeaccessedonlythroughfunctionsandauditinginsidethesefunctions
Here,wewilltakealookataminimalnumberofexamplesforboththeapproaches.
First,let’screatethetables:
CREATETABLEsalaries(
emp_nametextPRIMARYKEY,
salaryintegerNOTNULL
);
CREATETABLEsalary_change_log(
changed_bytextDEFAULTCURRENT_USER,
changed_attimestampDEFAULTCURRENT_TIMESTAMP,
salary_optext,
emp_nametext,
old_salaryinteger,
new_salaryinteger
);
REVOKEALLONsalary_change_logFROMPUBLIC;
GRANTALLONsalary_change_logTOmanagers;
Youdon’tgenerallywantyouruserstobeabletochangeauditlogs,soonlygrantthemanagerstherighttoaccessthese.Ifyouplantoletusersaccessthesalarytabledirectly,youshouldputatriggeronitforauditing:
CREATEORREPLACEFUNCTIONlog_salary_change()RETURNStriggerAS$$
BEGIN
IFTG_OP='INSERT'THEN
INSERTINTOsalary_change_log(salary_op,emp_name,new_salary)
VALUES(TG_OP,NEW.emp_name,NEW.salary);
ELSIFTG_OP='UPDATE'THEN
INSERTINTOsalary_change_log(salary_op,emp_name,old_salary,new_salary)
VALUES(TG_OP,NEW.emp_name,OLD.salary,NEW.salary);
ELSIFTG_OP='DELETE'THEN
INSERTINTOsalary_change_log(salary_op,emp_name,old_salary)
VALUES(TG_OP,NEW.emp_name,OLD.salary);
ENDIF;
RETURNNEW;
END;
$$LANGUAGEplpgsqlSECURITYDEFINER;
CREATETRIGGERaudit_salary_change
![Page 70: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/70.jpg)
AFTERINSERTORUPDATEORDELETEONsalaries
FOREACHROWEXECUTEPROCEDURElog_salary_change();
Now,let’stestoutsomesalarymanagement:
postgres=#INSERTINTOsalariesvalues('Bob',1000);
INSERT01
postgres=#UPDATEsalariesSETsalary=1100WHEREemp_name='Bob';
UPDATE1
postgres=#INSERTINTOsalariesVALUES('Mary',1000);
INSERT01
postgres=#UPDATEsalariesSETsalary=salary+200;
UPDATE2
postgres=#SELECT*FROMsalaries;
-[RECORD1]--
emp_name|Bob
salary|1300
-[RECORD2]--
emp_name|Mary
salary|1200
Eachoneofthesechangesissavedintothesalarychangelogtableforauditingpurposes:
postgres=#SELECT*FROMsalary_change_log;
-[RECORD1]--------------------------
changed_by|frank
changed_at|2012-01-2515:44:43.311299
salary_op|INSERT
emp_name|Bob
old_salary|
new_salary|1000
-[RECORD2]--------------------------
changed_by|frank
changed_at|2012-01-2515:44:43.313405
salary_op|UPDATE
emp_name|Bob
old_salary|1000
new_salary|1100
-[RECORD3]--------------------------
changed_by|frank
changed_at|2012-01-2515:44:43.314208
salary_op|INSERT
emp_name|Mary
old_salary|
new_salary|1000
-[RECORD4]--------------------------
changed_by|frank
changed_at|2012-01-2515:44:43.314903
salary_op|UPDATE
emp_name|Bob
old_salary|1100
new_salary|1300
-[RECORD5]--------------------------
changed_by|frank
changed_at|2012-01-2515:44:43.314903
salary_op|UPDATE
emp_name|Mary
![Page 71: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/71.jpg)
old_salary|1000
new_salary|1200
Ontheotherhand,youmaynotwantanybodytohavedirectaccesstothesalarytable,inwhichcaseyoucanperformtheREVOKEcommand.ThefollowingcommandwillrevokeallprivilegesfromPUBLIC:
REVOKEALLONsalariesFROMPUBLIC;
Also,giveusersaccesstoonlytwofunctions:thefirstfunctionisforanyusertakingalookatsalariesandtheotherfunctioncanbeusedtochangesalaries,whichisavailableonlytomanagers.
ThefunctionswillhavealltheaccesstotheunderlyingtablesbecausetheyaredeclaredasSECURITYDEFINER,whichmeansthattheyrunwiththeprivilegesoftheuserwhocreatedthem.
Thisishowthesalarylookupfunctionwilllook:
CREATEORREPLACEFUNCTIONget_salary(text)
RETURNSinteger
AS$$
—ifyoulookatotherpeople'ssalaries,itgetslogged
INSERTINTOsalary_change_log(salary_op,emp_name,new_salary)
SELECT'SELECT',emp_name,salary
FROMsalaries
WHEREupper(emp_name)=upper($1)
ANDupper(emp_name)!=upper(CURRENT_USER);
—don'tlogselectofownsalary
—returntherequestedsalary
SELECTsalaryFROMsalariesWHEREupper(emp_name)=upper($1);
$$LANGUAGESQLSECURITYDEFINER;
Noticethatweimplementedasoft-securityapproach,whereyoucanlookupotherpeople’ssalaries,butyouhavetodoitresponsibly,thatis,onlywhenyouneedto,asyourmanagerwillknowthatyouhavechecked.
Theset_salary()functionabstractsawaytheneedtocheckwhethertheuserexists;iftheuserdoesnotexist,itiscreated.Settingsomeone’ssalaryto0willremovehimorherfromthesalarytable.Thus,theinterfaceissimplifiedtoalargeextent,andtheclientapplicationofthesefunctionsneedstoknow,anddo,less:
CREATEORREPLACEFUNCTIONset_salary(i_emp_nametext,i_salaryint)
RETURNSTEXTAS$$
DECLARE
old_salaryinteger;
BEGIN
SELECTsalaryINTOold_salary
FROMsalaries
WHEREupper(emp_name)=upper(i_emp_name);
IFNOTFOUNDTHEN
INSERTINTOsalariesVALUES(i_emp_name,i_salary);
INSERTINTOsalary_change_log(salary_op,emp_name,new_salary)
VALUES('INSERT',i_emp_name,i_salary);
RETURN'INSERTEDUSER'||i_emp_name;
![Page 72: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/72.jpg)
ELSIFi_salary>0THEN
UPDATEsalaries
SETsalary=i_salary
WHEREupper(emp_name)=upper(i_emp_name);
INSERTINTOsalary_change_log
(salary_op,emp_name,old_salary,new_salary)
VALUES('UPDATE',i_emp_name,old_salary,i_salary);
RETURN'UPDATEDUSER'||i_emp_name;
ELSE—salarysetto0
DELETEFROMsalariesWHEREupper(emp_name)=upper(i_emp_name);
INSERTINTOsalary_change_log(salary_op,emp_name,old_salary)
VALUES('DELETE',i_emp_name,old_salary);
RETURN'DELETEDUSER'||i_emp_name;
ENDIF;
END;
$$LANGUAGEplpgsqlSECURITYDEFINER;
Now,droptheaudittrigger(otherwisethechangeswillbeloggedtwice)andtestthenewfunctionality:
postgres=#DROPTRIGGERaudit_salary_changeONsalaries;
DROPTRIGGER
postgres=#
postgres=#SELECTset_salary('Fred',750);
-[RECORD1]------------------
set_salary|INSERTEDUSERFred
postgres=#SELECTset_salary('frank',100);
-[RECORD1]-------------------
set_salary|INSERTEDUSERfrank
postgres=#SELECT*FROMsalaries;
-[RECORD1]---
emp_name|Bob
salary|1300
-[RECORD2]---
emp_name|Mary
salary|1200
-[RECORD3]---
emp_name|Fred
salary|750
-[RECORD4]---
emp_name|frank
salary|100
postgres=#SELECTset_salary('mary',0);
-[RECORD1]-----------------
set_salary|DELETEDUSERmary
postgres=#SELECT*FROMsalaries;
-[RECORD1]---
emp_name|Bob
salary|1300
-[RECORD2]---
emp_name|Fred
salary|750
![Page 73: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/73.jpg)
-[RECORD3]---
emp_name|frank
salary|100
postgres=#SELECT*FROMsalary_change_log;
...
-[RECORD6]--------------------------
changed_by|gsmith
changed_at|2013-01-2515:57:49.057592
salary_op|INSERT
emp_name|Fred
old_salary|
new_salary|750
-[RECORD7]--------------------------
changed_by|gsmith
changed_at|2013-01-2515:57:49.062456
salary_op|INSERT
emp_name|frank
old_salary|
new_salary|100
-[RECORD8]--------------------------
changed_by|gsmith
changed_at|2013-01-2515:57:49.064337
salary_op|DELETE
emp_name|mary
old_salary|1200
new_salary|
![Page 74: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/74.jpg)
![Page 75: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/75.jpg)
DatacleaningIntheprecedingcode,wenoticethatemployeenamesdon’thaveconsistentcases.Itwillbeeasytoenforceconsistencybyaddingaconstraint,asshownhere:
CHECK(emp_name=upper(emp_name))
However,itisevenbettertojustmakesurethatthenameisstoredasuppercase,andthesimplestwaytodothisisbyusingtrigger:
CREATEORREPLACEFUNCTIONuppercase_name()
RETURNStriggerAS$$
BEGIN
NEW.emp_name=upper(NEW.emp_name);
RETURNNEW;
END;
$$LANGUAGEplpgsql;
CREATETRIGGERuppercase_emp_name
BEFOREINSERTORUPDATEORDELETEONsalaries
FOREACHROWEXECUTEPROCEDUREuppercase_name();
Thenextset_salary()callforanewemployeewillnowinsertemp_nameinuppercase:
postgres=#SELECTset_salary('arnold',80);
-[RECORD1]-------------------
set_salary|INSERTEDUSERarnold
Astheuppercasinghappensinsideatrigger,thefunction’sresponsestillshowsalowercasename,butinthedatabase,itisuppercased:
postgres=#SELECT*FROMsalaries;
-[RECORD1]---
emp_name|Bob
salary|1300
-[RECORD2]---
emp_name|Fred
salary|750
-[RECORD3]---
emp_name|Frank
salary|100
-[RECORD4]---
emp_name|ARNOLD
salary|80
Afterfixingtheexistingmixed-caseemployeenames,wecanmakesurethatallemployeenameswillbeuppercasedinthefuturebyaddingaconstraint:
postgres=#updatesalariessetemp_name=upper(emp_name)wherenot
emp_name=upper(emp_name);
UPDATE3
postgres=#altertablesalariesaddconstraint
emp_name_must_be_uppercasepostgresCHECK(emp_name=upper(emp_name));
ALTERTABLE
![Page 76: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/76.jpg)
Ifthisbehaviorisneededinmoreplaces,itwillmakesensetodefineanewtype–sayu_text,whichisalwaysstoredasuppercase.YouwilllearnmoreaboutthisapproachinChapter14,PostgreSQLasExtensibleRDBMS.
![Page 77: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/77.jpg)
![Page 78: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/78.jpg)
CustomsortordersThelastexampleinthischapter,isaboutusingfunctionsfordifferentwaysofsorting.
Saywearegivenatasktosortwordsbytheirvowelsonly,andinadditiontothis,tomakethelastvowelthemostsignificantonewhensorting.Whilethistaskmayseemreallycomplicatedatfirst,itcanbeeasilysolvedwithfunctions:
CREATEORREPLACEFUNCTIONreversed_vowels(wordtext)
RETURNStextAS$$
vowels=[cforcinword.lower()ifcin'aeiou']
vowels.reverse()
return''.join(vowels)
$$LANGUAGEplpythonuIMMUTABLE;
postgres=#selectword,reversed_vowels(word)fromwordsorderby
reversed_vowels(word);
word|reversed_vowels
-------------+-----------------
Abracadabra|aaaaa
Great|ae
Barter|ea
Revolver|eoe
(4rows)
NoteBeforeperformingthiscode,pleasemakesureyouhavePython2.xinstalled.WewilldiscussPL/Pythoninmuchdetailinthelaterchaptersofthisbook.
Thebestpartisthatyoucanuseyournewfunctioninanindexdefinition:
postgres=#CREATEINDEXreversed_vowels_indexONwords
(reversed_vowels(word));
CREATEINDEX
Thesystemwillautomaticallyusethisindexwheneverthereversed_vowels(word)functionisusedintheWHEREorORDERBYclause.
![Page 79: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/79.jpg)
![Page 80: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/80.jpg)
ProgrammingbestpracticesDevelopingapplicationsoftwareiscomplicated.Someoftheapproachesthathelpmanagethiscomplexityaresopopularthattheyhavebeengivensimpleacronymsthatcanberemembered.Next,we’llintroducesomeoftheseprinciplesandshowyouhowserverprogramminghelpsmakethemeasiertofollow.
![Page 81: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/81.jpg)
KISS–keepitsimplestupidOneofthemaintechniquestosuccessfulprogrammingiswritingsimplecode.Thatis,writingcodethatyoucaneasilyunderstand3yearsfromnowandthatotherscanunderstandaswell.Itisnotalwaysachievable,butitalmostalwaysmakessensetowriteyourcodeinthesimplestwaypossible.Youcanrewritepartsofitlaterforvariousreasonssuchasspeed,codecompactness,toshowoffhowcleveryouare,andsoon.However,alwayswritethecodeinasimplewayfirst,sothatyoucanbeabsolutelysurethatitdoeswhatyouwant.Notonlydoyougetworkingonthecodequickly,butyoualsohavesomethingtocomparetowhenyoutrymoreadvancedwaystodothesamething.
Remember,debuggingisharderthanwritingcode;so,ifyouwritethecodeinthemostcomplexwayyoucan,youwillhaveareallyhardtimedebuggingit.
Itisofteneasiertowriteasetreturningfunctioninsteadofacomplexquery.Yes,itwillprobablyrunslowerthanthesamethingimplementedasasinglecomplexquery,duetothefactthattheoptimizercandoverylittletothecodewrittenasfunctions,butthespeedmaybesufficientforyourneeds.Ifmorespeedisrequired,it’sverylikelytorefactorthecodepiecebypiece,joiningpartsofthefunctionintolargerquerieswheretheoptimizerhasabetterchanceofdiscoveringbetterqueryplansuntiltheperformanceisacceptableagain.
Rememberthatmostofthetime,youdon’tneedtheabsolutelyfastestcode.Foryourclientsorbosses,thebestcodeistheonethatdoesthejobwellandarrivesontime.
![Page 82: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/82.jpg)
DRY–don’trepeatyourselfThisprinciplemeansyoushouldimplementanypieceofbusinesslogicjustonceandputthecodefordoingitintherightplace.
Thismaybehardsometimes;forexample,youwanttodosomechecksonyourwebformsinthebrowser,butstilldothefinalchecksinthedatabase.However,asageneralguideline,itisverymuchvalid.
Serverprogramminghelpsalothere.Ifyourdatamanipulationcodeisinthedatabasenearthedata,allthedatausershaveeasyaccesstoit,andyouwillnotneedtomanageasimilarcodeinaC++Windowsprogram,twoPHPwebsites,andabunchofPythonscriptsdoingnightlymanagementtasks.Ifanyofthemneedtodothisthingtoacustomer’stable,theyjustcall:
SELECT*FROMdo_this_thing_to_customers(arg1,arg2,arg3);
That’sit!
Ifthelogicbehindthefunctionneedstobechanged,youjustchangethefunctionwithnodowntimeandnocomplicatedorchestrationofpushingdatabasequeryupdatestoseveralclients.Oncethefunctionischangedinthedatabase,itischangedforalltheusers.
![Page 83: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/83.jpg)
YAGNI–youain’tgonnaneeditInotherwords,don’tdomorethanyouabsolutelyneedto.
Ifyouhaveacreepyfeelingthatyourclientisnotyetwellawareofhowthefinaldatabasewilllookorwhatitwilldo,it’shelpfultoresisttheurgetodesigneverythingintothedatabase.Amuchbetterwayistodoaminimalimplementationthatsatisfiesthecurrentspecifications,butdoitwithextensibilityinmind.Itisveryeasyto“paintyourselfintoacorner”whenimplementingabigspecificationwithlargeimaginaryparts.
Ifyouorganizeyouraccesstothedatabasethroughfunctions,itisoftenpossibletodoevenlargerewritesofbusinesslogicwithouttouchingthefrontendapplicationcode.YourapplicationstillperformsSELECT*FROMdo_this_thing_to_customers(arg1,arg2,arg3),evenafteryouhaverewrittenthefunctionfivetimesandchangedthewholetablestructuretwice.
![Page 84: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/84.jpg)
SOA–service-orientedarchitectureUsually,whenyouheartheacronymSOA,itwillbefromenterprisesoftwarepeopletryingtosellyouacomplexsetofSOAPservices.ButtheessenceofSOAistoorganizeyoursoftwareplatformasasetofservicesthatclients,andotherservices,callinordertoperformcertainwell-definedatomictasks,asfollows:
Checkingauser’spasswordandcredentialsPresentinghim/herwithalistofhis/herfavoritewebsitesSellinghim/heranewreddogcollarwithacomplementarymembershipinthered-collareddogclub
TheseservicescanbeimplementedasSOAPcallswithcorrespondingWSDLdefinitionsandJavaserverswithservletcontainers,aswellasacomplexmanagementinfrastructure.TheycanalsobeasetofPostgreSQLfunctions,takingasetofargumentsandreturningasetofvalues.Iftheargumentsorreturnvaluesarecomplex,theycanbepassedasXMLorJSON,butasimplesetofstandardPostgreSQLdatatypesisoftenenough.InChapter10,ScalingYourDatabasewithPL/Proxy,youwilllearnhowtomakesuchaPostgreSQL-basedSOAserviceinfinitelyscalable.
![Page 85: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/85.jpg)
TypeextensibilitySomeoftheprecedingtechniquesareavailableinotherdatabases,butPostgreSQL’sextensibilitydoesnotstophere.InPostgreSQL,youcanjustwriteUDFsinanyofthemostpopularscriptinglanguages.Youcanalsodefineyourowntypes,notjustdomains,whicharestandardtypeswithsomeextraconstraintsattached,andnewfull-fledgedtypestoo.
Forexample,aDutchcompany,MGRID,hasdevelopedavaluewithunitsetofdatatypes,sothatyoucandivide10kmby0.2hoursandgettheresultin50km/h.Ofcourse,youcanalsocastthesameresulttometerspersecondoranyotherunitofspeed.Andyes,youcangetthisasafractionofc—thespeedoflight.
Thiskindoffunctionalityneedsboththetypesandoverloadedoperands,whichknowthatifyoudividedistancebytime,thentheresultisspeed.Youwillalsoneeduser-definedcasts,whichareautomaticallyormanually-invokedconversionfunctionsbetweentypes.
MGRIDdevelopedthisforuseinmedicalapplications,wherethecostofanerrorcanbehigh—thedifferencebetween10mland10cccanbevital.However,usingasimilarsystemmightalsohaveavertedmanyotherdisasters,wherewrongunitsendedupproducingbadcomputationresults.Iftheamountisalwaysaccompaniedbytheunit,thepossibilityforthesekindsoferrorsisdiminished.Youcanalsoaddyourownindexmethodifyouhavesomeprogrammingskillsandyourproblemdomainisnotwellservedbytheexistingindexes.ThereisalreadyarespectablesetofindextypesincludedinthecorePostgreSQL,aswellasseveralothersthataredevelopedoutsidethecore.
ThelatestindexmethodthatbecameofficiallyincludedinPostgreSQLisknearestneighbor(KNN)—acleverindex,whichcanreturnKrowsorderedbytheirdistancefromthedesiredsearchtarget.OneuseofKNNisinfuzzytextsearch,wherethiscanbeusedtorankfull-textsearchresultsbyhowwelltheymatchthesearchterms.BeforeKNN,thiskindofthingwasdonebyqueryingalltherowswhichmatchedevenslightly,thensortingallthesebythedistancefunction,andreturningKtoprowsasthefinalstep.
IfdoneusingtheKNNindex,theindexaccesscanstartreturningtherowsinthedesiredorder;so,asimpleLIMITKfunctionwillreturntheKtopmatches.
TheKNNindexcanalsobeusedforrealdistances,forexample,answeringtherequest“Givemethe10nearestpizzaplacestoCentralStation.”
Asyousaw,indextypesaredifferentfromthedatatypestheyindex.Anotherexample,isthesameGeneralInvertedIndex(GIN)canbeusedforfull-textsearches(togetherwithstemmers,thesauri,andothertext-processingstuff),aswellasforindexingelementsofintegerarrays.
![Page 86: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/86.jpg)
![Page 87: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/87.jpg)
CachingYetanotherplacewhereserver-sideprogrammingcanbeusedistocachevalues,whichareexpensivetocompute.Thefollowingisthebasicpatternhere:
1. Checkwhetherthevalueiscached.2. Ifitisn’t,orthevalueistooold,computeandcacheit.3. Returnthecachedvalue.
Forexample,calculatingthesalesforacompanyistheperfectitemtocache.Perhaps,alargeretailcompanyhas1,000storeswithpotentiallymillionsofindividualsales’transactionsperday.Ifthecorporateheadquartersislookingforsales’trends,itismuchmoreefficientifthedailysalesnumbersareprecalculatedatthestorelevelinsteadofsummingupmillionsofdailytransactions.
Ifthevalueissimple,suchaslookingupauser’sinformationfromasingletablebasedontheuserID,youdon’tneedtodoanything.ThevaluegetscachedinPostgreSQL’sinternalpagecache,andalllookupstoitaresofastthatevenonaveryfastnetwork,mostofthetimeisspentdoingthelookupsinthenetworkandnotintheactuallookup.Insuchacase,gettingdatafromaPostgreSQLdatabaseisasfastasgettingitfromanyotherin-memorycache(suchasmemcached)butwithoutanyextraoverheadinmanagingthecache.
Anotherusecaseofcachingistoimplementmaterializedviews.Theseareviewsthatareprecomputedonlywhenrequired,noteverytimeoneselectsdatafromtheview.SomeSQLdatabaseshavematerializedviewsasseparatedatabaseobjects,butinthePostgreSQLversionspriorto9.3,youhavetodoityourselfusingotherdatabasefeaturestoautomatethewholeprocess.
![Page 88: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/88.jpg)
![Page 89: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/89.jpg)
Wrappingup–whyprogramintheserver?Themainadvantagesofdoingmostdatamanipulationcodeontheserver-sidearestatedinthefollowingsections.
![Page 90: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/90.jpg)
PerformanceDoingthecomputationnearthedataisalmostalwaysaperformancewin,asthelatenciestogetthedataareminimal.Inatypicaldata-intensivecomputation,mostofthetimeisspentingettingthedata.Therefore,makingdataaccessinsidethecomputationfasteristhebestwaytomakethewholethingfast.Onmylaptop,ittakes2.2mstoqueryonerandomrowfroma1,000,000-rowdatabaseintotheclient,butittakesonly0.12mstogetthedatainsidethedatabase.Thisis20timesfasterandinsidethesamemachineoverUnixsockets.Thedifferencecanbebiggerifthereisanetworkconnectionbetweentheclientandtheserver.
Asmallreal-wordstory:
Afriendofminewascalledtohelpalargecompany(I’msureallofyouknowit,butIcan’ttellyouwhichone)inordertomakeitse-mailsendingapplicationfaster.Theyhadimplementedtheire-mailgenerationsystemwithallthelatestJavaEEtechnologies:first,gettingthedatafromthedatabase,passingthedataaroundbetweenservices,andserializinganddeserializingitseveraltimesbeforefinallydoingXSLTtransformationonthedatatoproducethee-mailtext.Theendresultbeingthatitproducedonlyafewhundrede-mailspersecond,andtheywerefallingbehindwiththeirresponses.
WhenherewrotetheprocesstouseaPL/Perlfunctioninsidethedatabasetoformatthedataandthequeryreturnedalreadyfully-formattede-mails,itsuddenlystartedspewingouttensofthousandsofe-mailspersecondandtheyhadtoaddasecondcopyofthesentmailtoactuallybeabletosendthemout.
![Page 91: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/91.jpg)
EaseofmaintenanceIfallthedatamanipulationcodeisinadatabase,eitherasdatabasefunctionsorviews,theactualupgradeprocessbecomesveryeasy.AllthatisneededistorunaDDLscriptthatredefinesthefunctions;alltheclientsautomaticallyusethenewcodewithnodowntimeandnocomplicatedcoordinationbetweenseveralfrontendsystemsandteams.
![Page 92: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/92.jpg)
ImprovedproductivityServer-sidefunctionsareperhapsthebestwaytoachievecodereuse.Anyclientapplicationwritteninanylanguageorframeworkcanmakeuseoftheserver-sidefunctions,ensuringmaximumreuseinallenvironments.
![Page 93: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/93.jpg)
SimplewaystotightensecurityIfalltheaccessforsomepossiblyinsecureserversgoesthroughfunctions,thedatabaseuseroftheseserverscanonlybegrantedaccesstotheneededfunctionsandnothingelse.Theycan’tseethetabledataoreventhefactthatthesetablesexist.So,eveniftheserveriscompromised,allitcandoiscontinuetocallthesamefunctions.Also,thereisnopossibilityofstealingpasswords,e-mails,orothersensitiveinformationbyissuingitsownqueriessuchasSELECT*FROMusers;andgettingallthedatathereisinthedatabase.
Also,themostimportantthingisthatprogramminginaserverisfun!
![Page 94: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/94.jpg)
![Page 95: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/95.jpg)
SummaryProgramminginsidethedatabaseserverisnotalwaysthefirstthingthatcomestomindtomanydevelopers,butitsuniqueplacementinsidetheapplicationstackgivesitsomepowerfuladvantages.Yourapplicationcanbefaster,moresecure,andmoremaintainablebypushinglogicintothedatabase.Withserver-sideprogramminginPostgreSQL,youcansecureyourdatausingfunctions,auditaccesstoyourdataandstructuralchangesusingtriggers,andimproveproductivitybyachievingcodereuse.Also,youcanenrichyourdatausingcustomdatatypes,analyzeyourdatausingcustomoperators,andextendthecapabilitiesofthedatabasebydynamicallyloadingnewfunctions.
ThisisjustthestartofwhatyoucandoinsidePostgreSQL.Throughouttherestofthisbook,youwilllearnmanyotherwaystowritepowerfulapplicationsbyprogramminginsidePostgreSQL.
![Page 96: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/96.jpg)
![Page 97: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/97.jpg)
Chapter2.ServerProgrammingEnvironmentsYou’vehadachancetogetacquaintedwiththegeneralideaofusingPostgreSQL,butnowwearegoingtoanswerthequestionofwhyanyonewillchoosePostgreSQLasadevelopmentplatform.AsmuchasI’dliketobelievethatit’saneasydecisionforeveryone,it’snot.
Forstarters,let’sgetridoftheoptimisticideathatyouchooseadatabaseplatformfortechnicalreasons.Sure,weallliketothinkthatweareobjective,andwebaseourdecisionsonapreponderanceofthetechnicalevidence.Thispreponderanceofevidencethenindicateswhichfeaturesareavailableandrelevanttoourapplication.Wewillthenproceedtomakeaweightedchoiceinfavorofthemostadvantageousplatform,anduseabalanceoftheevidencestocreateworkaroundsandalternativeswhereourchoicefallsshort.Thefactisthatwedon’treallyunderstandalltherequirementsoftheapplicationuntilwearehalfwaythroughthedevelopmentcycle.Herearesomereasonswhy:
Wedon’tknowhowtheapplicationwillevolveovertime.Manystart-upspivotfromtheirinitialideaasthemarkettellsthemtochange.Wedon’tknowhowmanyuserstherewillreallybeuntilwehavesomeregistrationsandcanbegintomeasurethecurve.Wedon’trealizehowimportantaparticularfeaturecanbeuntilwegetuserfeedback.Thetruthis,thatwedon’treallyknowmuchaboutthelong-termneedsoftheapplicationuntilwe’rewritingversion2ormaybeevenversion3.
Thatis,unlessyou’reoneofthefortunatefewwhohasaResearchandDevelopmentdepartmentthatwritesthealphaversion,throwsitoutthewindow,andthenasksyoutowritethenextversionbasedonthelessonslearned.Eventhen,youreallydon’tknowwhattheusagepatternsaregoingtobeoncetheapplicationisdeployed.
WhatwegenerallyseeinthePostgreSQLcommunity—whennewusersstartaskingquestions—ispeoplenotlookingtomakeadecision,butratherpeoplewhohavealreadymadeadecision.Inmostcases,theyarelookingfortechnicaljustificationforanexistingplanofaction.Thedecisionhasalreadybeenpassed.WhatIamgoingtowriteaboutinthischapterisnotaTPCbenchmark,norisitabouttherelativemeritsofPostgreSQLfunctionsversusstoredprocedures.Frankly,nobodyreallycaresaboutthesethingsuntiltheyhavealreadymadeachoiceandwanttojustifyit.
ThischaptercontainstheguidethatIwishsomeonehadwrittenformewhenIchosetousePostgreSQLbackin1998.
![Page 98: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/98.jpg)
CostofacquisitionOneofbiggestthefactorsthatdecideswhichtechnologyisusedintheapplicationstackisthecostofacquisition.I’veseenmanyapplicationarchitecturesdrawnonawhiteboardwherethetechnicalteamwasembarrassedtoshowthem,buttheyjustifiedthedesignbytryingtokeepsoftwarelicensingcostsdown.Whenitcomestothedatabaseenvironment,theusualsuspectsareOracle,SQLServer,MySQL,andPostgreSQL.Oracle,thedominantplayerinthedatabasespace,isalsothemostcostly.Atthelowend,OracledoeshavereasonablypricedofferingsandevenafreeExpressEdition,buttheyarelimited.Mostpeoplehaveneedsbeyondthelow-pricedofferingsandfallintotheenterprisesalesmachineofOracle.Thisusuallyresultsinahigh-pricequotethatmakesyourCFOfalloutofhis/herchair,andyou’rebacktodesigningyoursolutioninordertokeepyourlicensingcostsdown.
ThencomesMicrosoftSQLServer.Thisisyourfirstreasonablyviableoption.ThepricingislistedontheMicrosoftwebsite.Iwillnotreproduceitherebecausethepricingscheduleistoovolatileforabookthatwillremaininprintforalongertime.Nonetheless,anexperiencedthumbvalueofthepurchasecostforSQLServerwillgetyourunningwithaweb-capablemodelforabout$5,000.Thisdoesnotincludeaservicecontract.Inthegrandschemeofdevelopmentcosts,thisisreasonableandnottoohighofabarriertoenter.
Then,wehavetheopensourceofferingssuchasMySQLandPostgreSQL.Theycostnothingandtheservicecontractscost—waitforit—nothing.Thisisaveryhardcostofacquisitiontobeat.
Remember,inthebeginningofthechapter,whenIwastalkingaboutallthethingsthatyoudon’tknowwhentheprojectstarts?Here’swheretherealwincomesin.Youcanaffordtofail.
There,Isaidit!
Lowcostofacquisitionisasynonymforlowcostoffailure.Whenweaddupalloftheunknownsfortheproject,wefindoutthatwehaveafairlygoodchancethatthefirstiterationwillnotmeetthemarketneeds,andweneedtofindawaytojettisonitquicklywithoutlong-termcontractsandtheadditionalcostsofspinningupanewproject.
Thisallowstheprojectmanagertomoveontothenextversionusinglessonslearnedfromtheconsumerafterthefirstversion.Hopefully,thislessoninuseracceptancewillcomeataverylowcostandtheprojectwillthenbegintothriveinthefollowingversions.Don’tletthesuccessoftheprojecthangongettingthefirstversionperfect.Youwon’t!
![Page 99: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/99.jpg)
![Page 100: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/100.jpg)
AvailabilityofdevelopersThishasbeenoneofthemosthilariouspartsofmydevelopmentlife.IrecentlyrecommendedalocalcompanytousePostgreSQLforareportingsystem.ThecompanyinquestionwantedtoknowthatiftheychosePostgreSQL,wouldanyoneonstaffbeabletomaintainit.So,IbegantointerviewthedeveloperstofindoutabouttheirexperienceswithPostgreSQL.
Me:DoyouhaveanyexperiencewithPostgreSQL?
Developer1:Yes,Iuseditatthelastjobforaproductfulfillmentproject,butIdon’tthinkmanypeoplehavethatexperience.WeshouldprobablysticktousingMySQL.
Me:DoyouhaveanyexperiencewithPostgreSQL?
Developer2:Yes,Iuseditatthelastjobforareportingproject,butIdon’tthinkmanypeoplehavethatexperience.WeshouldprobablysticktousingMySQL.
Afterinterviewingallsevendevelopersthatwereinfluentialontheproject,Ifoundthattheonlypersonwithouthands-onexperiencewithPostgreSQLwastheprojectmanager.Sincetheprojectmanagerdidn’texpecttohaveanytechnicalinvolvementintheproject,heapprovedtheselectionofPostgreSQL.
PostgreSQLisoneofthedirtylittlesecretsofwebdevelopers.Theyhaveaboutthesameleveloffamiliaritywithitastheydowithencryptionandsecurity.Becauseonlyadvanceduserswilluseit,theyhaveageneralgeekrequirementtolookintoitandpresumethateveryoneelseistooinexperiencedtodothesame.Everyoneistryingto“dumbitdown”fortheotherguy.Theyconsidertheirownuseofthetoolsathand(MySQL)asacrificethattheyarewillingtomakeinordertohelpthelessexperiencedpersondownthehall.Comically,thepersondownthehallthinksthathe’s/she’smakingthesamesacrificeforeveryoneelse.
TipLessonlearned
Quitmakingchoicesfortheotherguy.He/sheisjustasexperienced(andintelligent)asyouare,orhe/shemightjustwanttheopportunitytoadvancehis/herskills.
![Page 101: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/101.jpg)
![Page 102: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/102.jpg)
LicensingAbout2monthsafterOracleboughtMySQL,theyannouncedaplanthatdividedthedevelopmentintotwocamps:aMySQLcommunityeditionandaprofessionalversion.Thecommunityeditionwouldnolongergainanynewfeatures,andtheprofessionalversionwouldbecomeacommercialproduct.
Therewasavastandthunderoussuckingsoundintheopensourcecommunity,astheythrashedwildlyabouttofindanewplatformforFreeandOpenSourceSoftware(FOSS)development.
Oracleimmediately(inabout2weeks)countermandedtheorderanddeclaredthatthingswillstayastheywerefortheindefinitefuture.Thosewithshortmemories,forgivinghearts,orwhojustweren’tpayingattentionwentonabouttheirbusiness.ManyotheropensourceprojectseitherswitchedtoPostgreSQLorsuddenlygrewPostgreSQLdatabasesupport.
Today,wehaveMySQLandMySQLEnterpriseEdition.Ifyouwantbackup,highavailability,enterprisescalability,andtheMySQLEnterpriseMonitor,younowhavetoponyupsomedough.Capitalismisfine,andcorporationshavearighttochargemoneyfortheirservicesandproductsinordertoexist.Butwhyshouldyou,asaprojectmanagerordeveloper,havetopayforsomethingthatyoucangetforfree?
Licensingisallaboutcontinuedproductavailabilityanddistribution.ThePostgreSQLlicensingmodelspecificallystatesthatyoucanhavethesourcecode,doanythingwithit,redistributeithoweveryoujollywellplease,andtheserightsextendindefinitely.Trytogetthisdealwithacommercialvendor.
Asacorporatedeveloper,PostgreSQLwinsthelegalbattleforriskmanagementhandsdown.Ihaveheardtheargument“IwanttogowithacommercialvendorifIneedsomeonetosue.”Iwillencourageanyonewhoconsidersitagoodargumenttodoalittleresearchabouthowoftenthesevendorshavebeensued,howoftenthosesuitsweresuccessful,andwhatthecostofcourtwasforthatsuccess.Ithinkyou’llfindthattheonlyviableoptionisnottohavethebattle.
![Page 103: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/103.jpg)
![Page 104: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/104.jpg)
PredictabilityThissectioncouldjustaswellhavebeentitledstandardscompliance,butIdecidedagainstitbecausethebenefitsofstandardscomplianceincorporateprojectsarenotobvious.Thelimitationsofthecommondatabasesarewell-documented,andIwillshowyouafewwebsitesinamomentwhereyoucanmakeacomparisonofwhohasthemostunintendedbehavior.Iwillencourageyoutoreadthefollowingmaterialwhilethinkingaboutthequestion,“Whichmethodoffeaturedevelopmentismostlikelytomakemyapplicationbreakinthefuture?”:
http://www.sql-info.de/postgresql/postgres-gotchas.htmlhttp://www.sql-info.de/mysql/gotchas.html
NoteSpoileralert:
Astricteradherencetostandardscomesatthecostofnotallowingambiguousbehavior.Notallowingambiguousbehaviormakesthedeveloper’slifemoredifficult.Makingthedeveloper’slifemoredifficultensuresthattheinterpretationofthecommandsthatthedevelopergiveswillnotchangelater,breakingtheapplication.
Justhowlazycanyouaffordtobe?I’mnotsurehowtomeasurethis.PostgreSQLisavailableforno-costfuturepredictability,soIdon’thavetoanswerthequestion.
Sure,PostgreSQLalsohassomebugslisted.However,changestothedatabasecorehaveatendencytomaketheengineworklikethedocumentationsaysitdoes,notlikethedocumentationshouldhavesaid.PostgreSQLdevelopersdon’thavetosay,“Oops,Ididn’tthinkofthat,”veryoften.Whentheydo,PostgreSQLjustbecomesmorestandardscompliant.
![Page 105: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/105.jpg)
![Page 106: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/106.jpg)
CommunityOracleandSQLServerdon’thaveacommunity.PleaseunderstandwhenIsaythat,Imeanthatthechancethatyouwillgettotalktoadeveloperofthecoredatabaseisaboutthesameasyourchanceofwinningthelottery.Bythetimeyoudo,it’sprobablybecauseyoufoundabugsoheinousthatitcouldn’tbeignoredandtheonlypersonwhocanunderstandyourreportistheguywhowrotethecodeinquestion.Theyhavepaidtechnicalsupportandthissupporthasproveninmyexperiencetobegenerallycompetent,butnotstellar.IhavehadtoworkaroundtheproblemthatIoriginallyrequestedhelpwithabout40percentofthetime.
ComparethistoMySQLandPostgreSQL,wherejustaboutanybodycanspeaktojustaboutanybodyelsealldaylong.ManyofthecoredevelopersofboththeplatformscanbefoundonIRC,metatconventions,contactedforcontractdevelopmentwork,andforthemostpart,bribedremarkablyeasilywithbeer(hint,hint,wink,wink,nudge,nudge).
Theyareactivelyconcernedaboutthehealthoftheoverallcommunityandwillanswerjustaboutanykindofquestionyouask,evenifthequestionhasaverytenuousrelationshiptodatabasedevelopment.Mypersonalexperience,isthatthePostgreSQLteamhasmorecoredevelopersreadilyavailablethanMySQL.Theyarealsomorepersonallyavailableatconventionsandmeetings.
DidImentiontheylikebeer?
![Page 107: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/107.jpg)
![Page 108: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/108.jpg)
ProcedurallanguagesSQLServerallowsyoutocreateadynamiclinklibrary(DLL)inanylanguagethatproducestheCommonLanguageRuntime(CLR).TheseDLLsmustbeloadedintotheserveratboottime.Tocreateaprocedureatruntimeandhaveitimmediatelyavailable,theonlychoiceisthebuilt-inSQLdialect,TransactSQL(TSQL).
MySQLhasafeaturecalledplugins.Oneofthelegalplugintypesisaprocedurallanguage.SeverallanguageshavebeentooledtoworkwithMySQLviathepluginsystem,includingmostofthepopularonessuchasPHPandPython.Thesefunctionscannotbeusedforstoredproceduresortriggers,buttheycanbeinvokedfromthecommonSQLstatements.Fortherest,youarestuckwiththebuilt-inSQL.
PostgreSQLhasfullsupportforadditionalprocedurallanguages,whichcanbeusedtocreateanylegalentityinthedatabasethatcanbecreatedwithPL/pgSQL.Thelanguagecanbeadded(orremoved)fromarunningversionofPostgreSQLandanyfunctiondefinedusingthislanguagecanalsobecreatedordroppedwhilesupportforadditionalprocedurallanguages,whichcanbeusedtocreateanylegalentityinthedatabasethatcanbecreatedwithPL/pgSQL.Thelanguagecanbeadded(orremoved)fromarunningversionofPostgreSQLandanyfunctiondefinedusingthislanguagecanalsobecreatedordroppedwhilePostgreSQLisrunning.
TheselanguageshavefullaccesstoPostgreSQL’sinternalfunctionsandtoallthedataentitiesthatthecallinguserhaspermissionfor.InadditiontohavingaccesstointernalPostgreSQLfunctions,entities,anddatastructures,somefunctions(inuntrustedlanguages)canalsoaccessexternalservices,createordeletefilesanddirectories,orsende-mailsandinvokeexternalprocesses.Wewilldiscusstrustedanduntrustedlanguagesinlaterchapters.
ManyofthesepluginlanguageextensionsareavailableforPostgreSQL.IhaveusedtheextensionsforPHP,Python,Bash,andPL/pgSQL.Yes,thismeansthatthestandardlanguageforPostgreSQLisalsoinstalledandmanagedusingthesameextensionsystemasanyotherlanguage.
ThisbringsustothepointthatwehavemoredevelopersavailableforPostgreSQLthanyoumighthaveoriginallythought.Softwaredevelopersarenotrequiredtolearnanewdevelopmentlanguageinordertowritestoredprocedures.TheycanextendPostgreSQLwithalanguageoftheirchoiceandcontinuetocodeinthemannerandworkflowthattheychoose.
TipLessonlearned
Therearenosecond-classcitizensinthePostgreSQLdevelopmentcommunity.Anyonecancodein(almost)anylanguagetheychoose.
![Page 109: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/109.jpg)
Third-partytoolsAfrequentpointofcomparisonamongthedatabaseplatformsisthenumberofthird-partyapplicationsavailable.I’mnotsosurethatthetotalnumbermatters,asmuchastheexistenceoftheapplicationsyouactuallyneed.
Tothisend,thefollowingisalistoftheproductsthatIhaveusedextensivelywithPostgreSQL:
Pentahodataintegration(kettle):ThisisanoutstandingExtract,TransformandLoad(ETL)toolPentahoReportServer:ThisisagreatreportingenginepgAdmin3:Thisisanawesomedatabaseadministrationtoolphp5-pgsql:ThisisapackagethatallowsnativeaccesstoPostgreSQLfromPHPQCubed:ThisisthePHPdevelopmentframeworkwithPostgreSQLsupportYii:ThisisanothergreatPHPdevelopmentframeworkTalend:ThisisanotherETLtoolthatworks,butthisisnotmyfavoriteBIRT:ThisisagreatJAVAreportingtoolwithaneasyreportcreationenvironmentpsycopg2:ThisisthePythonbindingsforPostgreSQL
ThesetoolshavemadethePostgreSQLdevelopmentexperienceabreeze,andthisisnowherenearacompletelist.WecanfillthisbookwithjustalistofapplicationsthatsupportPostgreSQL,andthankstoitsliberallicense,PostgreSQLisembeddedinmanycommercialapplicationsthatyouneverreallyknow.
TipLessonlearned
Don’tworrytoomuchabouthowmanytoolsareouttherefortheproduct.Theonesthatmatterareavailable.
![Page 110: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/110.jpg)
PlatformcompatibilitySQLServerisaMicrosoftproduct.Assuch,itwas,andwillalwaysbe,aMicrosoftplatformtool.ItisaccessibletosomelimiteddegreeviaODBC,butitisnotaseriouschoiceforcross-platformdevelopment.
MySQLandPostgreSQLsupporteveryoperatingsystemcurrentlyavailabletoday.Thisability(orthelackoflimitation)isastrongargumentforlong-termstability.Ifanyparticularoperatingsystemisnolongeravailable,ornolongersupportsopensourcesoftware,itisfairlysimpletomovethedatabaseservertoanotherplatform.
TipLessonlearned
Inthecommercialoperatingsystemwars,justsayno.
![Page 111: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/111.jpg)
Applicationdesign “Thethingthathathbeen,itisthatwhichshallbe;andthatwhichisdoneisthatwhichshallbedone:andthereisnonewthingunderthesun.”
—Ecclesiastes1:9(KJV)
“…oldthingsarepassedaway;behold,allthingsarebecomenew.”
—2Corinthians5:16-18(KJV)
Insoftwaredevelopment,wearealwaysrunningintothesituationwherewhatisoldisnewagain,anddeveloperswhoembraceaphilosophyswearbyitlikeareligion.Weswingbackandforthbetweenthinserversandthinclients,flatandhierarchicalstorage,desktopapplicationsandwebapplicationsand,mostappropriatelyforthischapter,betweenclientandserverprogramming.
Thereasonforthisswingbetweenprogrammingimplementationshasgotnothingtodowiththefeaturesthattheclientortheserveroffers.Developerexperienceisamuchmorelikelyinfluence,andthisinfluencecangoineitherdirection,dependingonwhatthedeveloperencounteredfirst.
Iencourageboththeserver-centricdeveloperandtheclient-centricdevelopertolaydowntheirpitchforkswhilereadingtherestofthischapter.
Wewilldiscuss,induetime,mostofthenewfeaturesofserverprogramming.Ifyou’restillnotconvinced,wewilltakealookathowyoucanharnessthebenefitsofmostofthosefeatureswithoutleavingyourapplication-centeredpointofview.
DatabasesareconsideredharmfulThesimplestandleastpowerfulwayoflookingatserverprogramming,istoviewthedatabaseasadatabucket.UsingonlythemostbasicSQLstatementssuchasINSERT,SELECT,UPDATE,andDELETE,youcanmanipulatedata,asinglerowatatime,andcreateapplicationlibrariesformultipledatabaseseasily.
Thisapproachhassomemajordrawbacks.Movingdatabackandforthtothedatabaseserveronerowatatimeisextremelyinefficient,andyouwillfindthatthismethodissimplynotviableinaweb-scaleapplication.
Thisideaisusuallyassociatedwiththeconceptofadatabaseabstractionlayer,aclientlibrarythatallowsthedevelopertoswitchthedatabaseoutfromundertheapplicationwithlittleeffort.Thisabstractionlayerisveryusefulintheopensourcedevelopmentcommunity,whichallowstheuseofmanydatabases,buttheyhavenofinancialincentivetogetthebestpossibleperformance.
SQL,beingbasedonrelationalalgebraandtuplerelationalcalculus,hastheabilitytoquicklyandefficientlyperformset-basedprocessingonlargeamountsofdata;theapplication-sideprocessingusuallyinvolvesiterativelooping,whichisgenerallymuchslower.
Inmy27-yearcareer,Ihaveneveractuallychangedthedatabaseofaninstalled
![Page 112: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/112.jpg)
applicationwithoutthrowingawaytheapplication.OneoftheprinciplesofagilesoftwaredevelopmentisYAGNI(youain’tgonnaneedit).Thisisoneofthosecases.
TipLessonlearned
Dataabstractionisvaluableforprojectsthatneedtoselectadatabaseplatformatinstallationtime.Foranythingelse,justsayno.
EncapsulationAnothertechniqueusedinmoreclient-centricdevelopmentphilosophies,istoisolatethedatabase-specificcallsintoalibraryofprocedures.Thisdesignisusuallyaimedatleavingtheapplicationincontrolofallthebusinesslogic.Theapplicationisstilltheking,andthedatabaseisstilljustanecessaryevil.
Thisviewofdatabasearchitecturesellstheapplicationdevelopershortbyignoringatoolboxfulloftoolsandchoosingonlythehammer.Everythingintheapplicationisthenpaintedtolooklikeanailandissmackedwiththehammer.
TipLessonlearned
Don’tgiveuponthepowerofthedatabasejustbecauseitisnotfamiliar.Useprocedurallanguagesandcheckoutextensiontoolkits.Therearesomeawesomepiecesofworkinthere.
WhatdoesPostgreSQLoffer?Sofar,we’vementionedprocedurallanguages,functions,triggers,customdatatypes,andoperators.ThesethingscanbecreateddirectlyinthedatabaseviatheCREATEcommandsoraddedaslibrariesusingextensions.
Now,wewillshowyousomethingsthatyouneedtokeepinmindwhenprogrammingontheserverinPostgreSQL.
DatalocalityIfpossible,keepthedataontheserver.Believeme,it’shappierthere,andperformanceismuchbetterwhenmodifyingdata.Ifeverythingwasdoneintheapplicationlayer,thedatawillneedtobereturnedfromthedatabasewiththemodificationsandthenfinallysentbacktothedatabaseforacommit.Ifyouarebuildingaweb-scalableapplication,thisshouldbeyourlastresort.
Let’swalkthroughasmallsnippetthatusestwomethodsinordertomakeanupdatetoasinglerecord:
<?php
$db=pg_connect("hostportuserpassworddbnameschema");
$sql="SELECT*FROMcustomerWHEREid=23";
$row=pg_fetch_array($db,$sql);
if($row['account_balance']>6000){
![Page 113: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/113.jpg)
$sql="UPDATEcustomerSETvalued_customer=trueWHEREid=23;";;";
pg_query($db,$sql);
}
pg_close($db);
?>
Thiscodesnippetpullsarowofdatafromthedatabaseservertotheclient,makesanevaluation,andchangesacustomeraccountbasedontheevaluation.Theresultofthechangeisthensentbacktotheserverforprocessing.
Thereareseveralthingsthatarewrongwiththisscenario.First,thescalabilityisterrible.Imagineifthisoperationneededtobeperformedforthousands,orevenmillionsofcustomers.Thiswillbereallyslowbecausethecodewillprocesstherecordsonebyone,andeachrecordwillbesentoverthenetworkandthenupdated,whichinvolvesgoingoverthenetworkagainforeachrecord.
Thesecondproblemistransactionalintegrity.Whathappensiftheuser’saccountbalancechangesfromsomeothertransactionbetweenthequeryandtheupdate?Isthecustomerstillvalued?Thiswilldependonthebusinessreasonfortheevaluation.
Tryoutthefollowingexample:
<?php
$db=pg_connect('...');
pg_query('UPDATEcustomerSETvalued_customer=trueWHEREbalance>
6000;',$db);
pg_close($db);
?>
Thisexampleissimple,hastransactionalintegrity,andworksforanincrediblylargenumberofcustomers.Whypointoutsuchasimpleandobviousexample?Theanswerisbecausemanydevelopmentframeworksworkincorrectlybydefault.Thecodegeneratorwillproducesomeequivalentformofthisexampleintheinterestofbeingcross-platform,predictable,andeasytointegrateintoasimpledesignmodel.
Thismethodpromotesterriblepractices.Forsystemsthathaveaverylownumberofconcurrenttransactions,youwillprobablyseewhatyouexpect,butasconcurrencyincreases,thenumberofunintendedbehaviorsalsoincrease.
Thesecondexampleexposesabetterphilosophy:operateoncolumns(notonrows),leavethedataontheserver,andletthedatabasedothetransactionalworkforyou.That’swhatthedatabaseismadefor.
![Page 114: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/114.jpg)
MorebasicsIthelpstohavesomebasicbackgroundinformationbeforeyoustartprogrammingfortheserver.Inthenextfewsections,wewillexplorethegeneraltechnicalenvironmentinwhichyouwillbeworking.Wewillcoveralotofinformation,butdon’tworrytoomuchaboutrememberingitallrightnow.Justtrytopickupthegeneralidea.
TransactionsThedefaulttransactionisolationlevelinPostgreSQLiscalledReadCommitted.Thismeansthatifmultipletransactionsattempttomodifythesamedata,theymustwaitforeachothertofinishbeforeactingontheresultingdata.Theywaitinafirst-come-first-serveorder.Thefinalresultofthedataiswhatmostpeoplewillnaturallyexpect:thelastchronologicalchangebeingreflected.
PostgreSQLdoesnotprovideanywaytodoadirtyread.Adirtyreadistheabilitytoviewthedatathewayitappearsinsomeoneelse’stransactionandtouseitasifitwerecommitted.ThisabilityisnotavailableinPostgreSQLbecauseofthewayinwhichthemultiversionconcurrencycontrolworks.
Thereareothertransactionisolationmethodsavailable;youcanreadaboutthemindetailathttp://www.postgresql.org/docs/current/static/transaction-iso.html.
Itisimportanttonote,thatwhennotransactionblocksarespecified(BEGIN..END),PostgreSQLwilltreateachindividualstatementlikeaprivatetransactionandcommitimmediatelywhenthestatementisfinished.Thisgivesothertransactionsachancetosettlebetweenyourstatements.Someprogramminglanguagesprovideatransactionblockaroundyourstatements,whilesomedonot.Pleasecheckyourlanguagedocumentationtofindoutwhetheryouarerunninginatransactedsession.
NoteWhenusingthetwomainclientstointeractwithPostgreSQL,thetransactionbehaviorisdifferent.Thepsqlcommand-lineclientdoesnotprovidetransactionblocks.Youareexpectedtoknowwhentostart/stopatransactiononyourown.ThepgAdmin3querywindow,ontheotherhand,wrapsanystatementthatyousubmitintoatransactionblockforyou.Thiswayitprovidesacanceloption.Ifthetransactionisinterrupted,ROLLBACKwillbeperformedandthedatabasewillgobacktoitsformerstate.
Someoperationsareexemptfromtransactions.Forexample,asequenceobjectwillcontinuetoincrementevenifthetransactionfailsandisrolledback.CREATEINDEXCONCURRENTLYrequiresthemanagementofitsowntransactionsandshouldnotbecalledfromwithinatransactionblock.ThesameistrueforVACUUM,aswellasCLUSTER.
GeneralerrorreportinganderrorhandlingIfyouwanttoprovideastatustotheuserduringexecution,youshouldbefamiliarwiththecommandsRAISE,NOTICE,andNOTIFY.Fromatransactionalperspective,thedifferenceisthatRAISEandNOTICEwillsendthemessageimmediately,evenwhenwrappedinatransaction,whileNOTIFYwillwaitforthetransactiontosettlebefore
![Page 115: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/115.jpg)
sendingamessage.NOTIFYwill,therefore,actuallynotnotifyyouofanythingifthetransactionfailsandisrolledback.
User-definedfunctionsTheabilitytowriteuser-definedfunctionsisthepowerhousefeatureofPostgreSQL.Functionscanbewritteninmanydifferentprogramminglanguages,canuseanykindofcontrolstructuresthatthelanguageprovides,andinthecaseof“untrusted”languages,canperformanyoperationthatisavailableinPostgreSQL.
FunctionscanprovidefeaturesthatarenotevendirectlyrelatedtoSQL.Someoftheupcomingexampleswillshowyouhowtogetnetworkaddressinformation,querythesystem,movefilesaround,anddojustaboutanythingthatyourheartdesires.
So,howdoweaccessthesugarygoodnessofPostgreSQL?Westartbydeclaringthatwewantafunction:
CREATEORREPLACEFUNCTIONaddition(integer,integer)RETURNSinteger
AS$$
DECLAREretvalinteger;
BEGIN
SELECT$1+$2INTOretval;
RETURNretval;
END;
$$LANGUAGEplpgsql;
Whatifwewanttoaddthreeintegerstogether?Usingthefollowingcodewecanaddthreeintegerstogether:
CREATEORREPLACEFUNCTIONaddition(integer,integer,integer)RETURNS
integer
AS$$
DECLAREretvalinteger;
BEGIN
SELECT$1+$2+$3INTOretval;
RETURNretval;
END;
$$LANGUAGEplpgsql;
Wejustinvokedaconceptcalledfunctionoverloading.Thisfeatureallowsyoutodeclareafunctionofthesamename,butwithdifferentparametersthatpotentiallybehavedifferently.Thisdifferencecanbejustassubtleaschangingthedatatypeofoneoftheargumentstothefunction.ThefunctionthatPostgreSQLinvokesdependsontheclosestmatchtothefunctionargumentsandexpectedreturntype.
Supposewewanttoaddtogetheranynumberofintegers?Well,PostgreSQLhasawaytodothisalso,asfollows:
CREATEORREPLACEFUNCTIONaddition(VARIADICarrinteger[])RETURNS
integer
AS$$
DECLAREretvalinteger;
BEGIN
SELECTsum($1[i])INTOretvalFROMgenerate_subscripts($1,1)g(i);
![Page 116: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/116.jpg)
RETURNretval;
END;
$$
LANGUAGEplpgsql;
Thiswillallowyoutopassinanynumberofintegersandgetanappropriateresponse.Thesefunctions,ofcourse,donothandlerealornumericdatatypes.Tohandleotherdatatypes,simplydeclarethefunctionagainwiththosetypesandcallthemwiththeappropriateparameters.
Formoreinformationaboutvariableparameters,checkouthttp://www.postgresql.org/docs/9.3/static/xfunc-sql.html#XFUNC-SQL-VARIADIC-FUNCTIONS.
OtherparametersThereismorethanonewaytogetdataintoafunctionandoutofit.WecanalsodeclareIN/OUTparameters,returnatable,returnasetofrecords,andusecursorsforboththeinputandoutput.
ThisbringsustoapseudotypecalledANY.Itallowstheparametertypetobeundefined,anditallowsanybasicdatatypetobepassedtothefunction.Then,itisuptothefunctiontodecidewhattodowiththedata.ThereareseveralotherpseudotypesavailableinPostgreSQL,alsocalledthepolymorphictypes.Theseareanyelement,anyarray,anynonarray,anyenum,andanyrange.Youcanreadmoreaboutthesepseudotypesathttp://www.postgresql.org/docs/9.3/static/datatype-pseudo.html.
Hereisanexampleofthepseudotypeanyarray.Thefollowingsimplefunctiontakesanarrayofanytypeasanargumentandreturnsanarraybyremovingalltheduplicates:
CREATEORREPLACEFUNCTIONremove_duplicates(anyarray)
RETURNSanyarrayAS
$$
SELECTARRAY(SELECTDISTINCTunnest($1));
$$
LANGUAGE'sql';
postgres=#SELECTremove_duplicates(ARRAY[1,1,2,2,3,3]);
remove_duplicates
-------------------
{1,2,3}
(1row)
postgres=#SELECTremove_duplicates(ARRAY['a','a','b','c']);
remove_duplicates
-------------------
{b,a,c}
(1row)
MorecontrolOnceyouhaveyourfunctionwrittenthewayyouneed,PostgreSQLgivesyouadditionalcontroloverhowthefunctionexecutes.Youcancontrolwhatdatathefunctioncanaccess
![Page 117: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/117.jpg)
andhowPostgreSQLwillinterprettheexpenseofrunningthefunction.
Therearetwostatementsthatprovideasecuritycontextforyourfunctions.ThefirstoneisSECURITYINVOKER,whichisthedefaultsecuritycontext.Inthedefaultcontext,theprivilegesofthecallinguserarerespectedbythefunction.
TheothercontextisSECURITYDEFINER.Inthiscontext,theuserprivilegesofthecreatorofthefunctionarerespectedduringtheexecutionofthefunction.Generally,thisisusedtotemporarilyescalateuserrightsforaspecificpurpose.
Thisisveryusefulifyouwanttohaveastrictercontroloveryourdata.Inanenvironmentwheresecurityoftheunderlyingdataisimportant,andyoudon’twantuserstodirectlySELECTthedataorchangeitusingINSERT,UPDATE,orDELETE,youcancreateasetoffunctionswiththesecurity-definerattributeasAPIsforthetables.ThisapproachgivesyoucompletecontroloveryourAPIbehaviorandhowuserscanaccesstheunderlyingobjects.
Costcanalsobedefinedforthefunction.Thiscostwillhelpthequeryplannerestimatehowexpensiveitistocallthefunction.Higherordersofcostwillcausethequeryplannertochangetheaccesspath,soyourfunctionwillbecalledasfewtimesaspossible.ThePostgreSQLdocumentationshowsthesenumberstobeafactorofcpu_operator_cost.That’smorethanalittlemisleading.ThesenumbershavenodirectcorrelationtoCPUcycles.Theyareonlyrelevantincomparisonwithoneanother.It’smorelikehowsomenationalmoneycompareswiththerestoftheEuropeanUnion.SomeEurosaremoreequalthanothers.
Toestimateyourownfunction’scomplexity,startwiththelanguageyouareimplementingitin.ForC,thedefaultwillbe1*numberofrecordsreturned,anditwillbe100forallotherlanguages,accordingtothePostgreSQLdocumentationathttp://www.postgresql.org/docs/current/static/sql-createfunction.html.Forplsh,youmaywanttouse150ormore,dependingonhowmanyexternaltoolcallsareinvolvedingettingananswer.Thedefaultis100andthisseemstoworkreasonablywellforPL/pgSQL.
![Page 118: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/118.jpg)
![Page 119: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/119.jpg)
SummaryNowyouknowafewthingsaboutthePostgreSQLenvironment,aswellassomethingsthatwillhelpyouintheunforeseeablefuture.PostgreSQLisbuilttohandleyourneeds,butmoreimportantly,itisbuiltnottochangeunderneathyouinthefuture.
WetouchedupontheenvironmentandcalledoutsomeofthemoreimportantthingstobekeptinmindwhenprogrammingontheserverinPostgreSQL.Don’tworrytoomuchifyoudon’trememberallofit.Itisfinetogoontothenextchapter,wherewewillactuallystartmakingsomeusefulfunctionsandlearnaboutwritingourfirstPL/pgSQLfunctions.Youwillalsolearnhowtowriteconditionalstatements,loops,anddifferentwaystoreturndata.Then,comebackandreviewthischapterwhenyouhaveaclearerunderstandingofthefeaturesavailabletothefunctionwriter.
![Page 120: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/120.jpg)
![Page 121: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/121.jpg)
Chapter3.YourFirstPL/pgSQLFunctionAfunctionisthebasicbuildingblockforextendingPostgreSQL.Afunctionacceptsinputintheformofparameters,anditcancreateoutputintheformofoutputparametersorreturnvalues.ManyfunctionsareprovidedbyPostgreSQLitself,thatis,commonmathematicalfunctionssuchassquarerootsandabsolutevalues.Foracomprehensivelistofthefunctionsthatarealreadyavailable,gotohttp://www.postgresql.org/docs/current/static/functions.html.
Thefunctionsthatyoucreatehavethesameprivilegesandabilitythatthebuilt-infunctionspossess.ThedevelopersofPostgreSQLusethesamelibrariestoextendthedatabasethatyouuse,asadeveloper,towriteyourbusinesslogic.
Thismeans,thatyouhavethetoolsavailabletobeafirst-classcitizenofthePostgreSQLdevelopmentcommunity.Infact,therearenosecond-classseatsonthisbus.
AfunctionacceptsparametersthatcanbeofanydatatypeavailableinPostgreSQL,anditreturnsresultstothecallerusingthesametype.Whatyoudowithinthefunctionisentirelyuptoyou.YouhavebeenempoweredtodoanythingthatPostgreSQLiscapableofdoing.YouareherewithalsowarnedthatyouarecapableofdoinganythingthatPostgreSQLiscapableofdoing.Thetrainingwheelsareoff.
Inthischapter,youwilllearnthefollowingtopics:
ThebasicbuildingblocksofaPostgreSQLfunctionPassingparametersintoafunctionThebasiccontrolstructuresinsideafunctionReturningresultsoutofafunction
![Page 122: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/122.jpg)
WhyPL/pgSQL?PL/pgSQLisapowerfulSQLscriptinglanguage,thatisheavilyinfluencedbyPL/SQL,thestoredprocedurelanguagedistributedwithOracle.ItisincludedinthevastmajorityofPostgreSQLinstallationsasastandardpartoftheproduct,soitusuallyrequiresnosetupatalltobegin.
PL/pgSQLalsohasadirtylittlesecret.ThePostgreSQLdevelopersdon’twantyoutoknowthatitisafull-fledgedSQLdevelopmentlanguage,capableofdoingprettymuchanythingwithinthePostgreSQLdatabase.
Whyisthisasecret?Foryears,PostgreSQLdidnotclaimtohavestoredprocedures.PL/pgSQLfunctionswereoriginallydesignedtoreturnscalarvaluesandwereintendedforsimplemathematicaltasksandtrivialstringmanipulations.
Overtheyears,PL/pgSQLdevelopedarichsetofcontrolstructuresandgainedtheabilitytobeusedbytriggers,operators,andindexes.Intheend,developersweregrudginglyforcedtoadmitthattheyhadacomplete,storedproceduredevelopmentsystemontheirhands.
Alongtheway,thegoalofPL/pgSQLchangedfromsimplescalarfunctions,toprovidingaccesstoallofthePostgreSQLsysteminternals,withfullcontrolstructure.Thefulllistofwhatisavailableinthecurrentversionisprovidedathttp://www.postgresql.org/docs/current/static/plpgsql-overview.html.
Today,thefollowingaresomeofthebenefitsofusingPL/pgSQL:
ItiseasytouseItisavailablebydefaultonmostdeploymentsofPostgreSQLItisoptimizedfortheperformanceofdata-intensivetasks
InadditiontoPL/pgSQL,PostgreSQLalsoallowsmanyotherlanguagessuchasPL/Perl,PL/Python,PL/Proxy,andPL/Tcltobepluggedintothedatabase,someofwhichwillbecoveredinthisbook.YoumayalsochoosetowriteyourfunctionsinPerl,Python,PHP,bash,andahostofotherlanguages,buttheywilllikelyneedtobeaddedtoyourinstanceofPostgreSQL.
![Page 123: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/123.jpg)
![Page 124: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/124.jpg)
ThestructureofaPL/pgSQLfunctionItdoesn’ttakemuchtogetaPL/pgSQLfunctionworking.Here’sabasicexample:
CREATEFUNCTIONmid(varchar,integer,integer)RETURNSvarchar
AS$$
BEGIN
RETURNsubstring($1,$2,$3);
END;
$$
LANGUAGEplpgsql;
TheprecedingfunctionshowsthebasicelementsofaPL/pgSQLfunction.Itcreatesanaliasforthesubstringbuilt-infunctioncalledmid.ThisisahandyaliastohavearoundfordevelopersthatcomefromMicrosoftSQLServerorMySQLandarewonderingwhathappenedtothemidfunction.Italsoillustratesthemostbasicparameter-passingstrategy:parametersarenotnamedandareaccessedinthefunctionbytheirrelativelocationfromlefttoright.The$$characterinthisexamplerepresentsthestartandendofthecodeblock.Thischaractersequencecanbearbitraryandyoucanusesomethingelseofyourchoice,butthisbookuses$$inalltheexamples.
ThebasicelementsofaPL/pgSQLfunctionarename,parameters,returntype,body,andlanguage.Itcanbearguedthatparametersarenotmandatoryforafunctionandneitheristhereturnvalue.Thismightbeusefulforaprocedurethatoperatesondatawithoutprovidingaresponse,butitwillbeprudenttoreturnthevalueTRUEtoindicatethattheproceduresucceeded.
![Page 125: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/125.jpg)
AccessingfunctionargumentsFunctionargumentscanalsobepassedandaccessedbyname,insteadofjustbytheordinalorder.Byaccessingtheparametersbyname,itmakestheresultingfunctioncodealittlemorereadable.Thefollowingisanexampleofafunctionthatusesnamedparameters:
CREATEFUNCTIONmid(keyfieldvarchar,starting_pointinteger)RETURNS
varchar
AS
$$
BEGIN
RETURNsubstring(keyfield,starting_point);
END
$$
LANGUAGEplpgsql;
Theprecedingfunctionalsodemonstratestheoverloadingofthemidfunction.OverloadingisanotherfeatureofPostgreSQLfunctions,whichallowsmultipleprocedurestousethesamename,butadifferentnumberortypesofparameters.Inthiscase,wefirstdeclaredthemidfunctionwiththreeparameters.However,inthisexample,overloadingisusedtoimplementanalternativeformofthemidfunction,wherethereareonlytwoparameters.Whenthethirdparameterisomitted,theresultwillbeastringstartingfromstarting_pointandcontinuingtotheendoftheinputstring,asshownhere:
SELECTmid('KirkL.Roybal',9);
Theprecedinglineofcodeyieldsthefollowingresult:
mid
--------
Roybal
(1row)
Inordertoaccessthefunctionparametersbyname,PostgreSQLmakesafeweducatedguessesdependingonthestatement.Consider,foramoment,thefollowingfunction:
CREATEORREPLACEFUNCTIONambiguous(parametervarchar)RETURNSintegerAS
$$
DECLAREretvalinteger;
BEGIN
INSERTINTOparameter(parameter)VALUES(parameter)RETURNINGidINTO
retval;
RETURNretval;
END;
$$
LANGUAGEplpgsql;
SELECTambiguous('parameter');
Thisisanexampleofpositivelyatrociousprogrammingsincetheargument,table,andits
![Page 126: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/126.jpg)
columnareallcalledparameter.Thisshouldneveroccuroutsideanexampleofhownottowritefunctions.However,PostgreSQLisintelligentenoughtocorrectlydeducethatthecontentsofthefunctionparameterareonlylegalintheVALUESlist.AllotheroccurrencesofparameterareactuallyphysicalPostgreSQLentities.
Wealsointroducedanoptionalsectiontothefunction.WedeclareavariablebeforetheBEGINstatement.Variablesthatappearinthissectionarevalidduringtheexecutionofthefunction.
Alsonote,theRETURNINGidINTOretvalstatementinthisfunction.Thisfeatureallowsthedevelopertospecifytheidentityfieldoftherecordandreturnsthevalueofthisfieldaftertherecordhasbeeninserted.Ourfunctionthenreturnsthisvaluetothecallerasanindicatorthatthefunctionsucceeded,andasawaytofindtherecordthathasbeeninserted.Thisisagoodwaytoreturnvaluesinsertedbydefault,suchastheserialsequencenumbers.Youcanuseanyexpressionwithtablecolumnnames,andthesyntaxwillbesimilartothecolumnlistinaSELECTstatement.
![Page 127: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/127.jpg)
![Page 128: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/128.jpg)
ConditionalexpressionsConditionalexpressionsallowdeveloperstocontroltheactionofthefunction,basedonadefinedcriteria.PostgreSQLprovidestheCASEandIFstatementstoexecutedifferentcommandsbasedonconditions.ThefollowingisanexampleoftheusageofaCASEstatementtocontrolhowastringistreatedbasedonitsvalue.Ifthevalueisnullorcontainsazero-lengthstring,itistreatedthesameasnull:
CREATEORREPLACEFUNCTIONformat_us_full_name(
prefixtext,firstnametext,
mitext,lastnametext,
suffixtext)
RETURNStextAS
$$
DECLARE
fname_mitext;
fmi_lnametext;
prefix_fmiltext;
pfmil_suffixtext;
BEGIN
fname_mi:=CONCAT_WS('',
CASEtrim(firstname)
WHEN''
THENNULL
ELSEfirstname
END,
CASEtrim(mi)
WHEN''
THENNULL
ELSEmi
END||'.');
fmi_lname:=CONCAT_WS('',
CASEfname_mi
WHEN''
THENNULL
ELSEfname_mi
END,
CASEtrim(lastname)
WHEN''
THENNULL
ELSElastname
END);
prefix_fmil:=CONCAT_WS('.',
CASEtrim(prefix)
WHEN''
THENNULL
ELSEprefix
END,
CASEfmi_lname
WHEN''
THENNULL
ELSEfmi_lname
END);
pfmil_suffix:=CONCAT_WS(',',
![Page 129: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/129.jpg)
CASEprefix_fmil
WHEN''
THENNULL
ELSEprefix_fmil
END,
CASEtrim(suffix)
WHEN''
THENNULL
ELSEsuffix||'.'
END);
RETURNpfmil_suffix;
END;
$$
LANGUAGEplpgsql;
Theideahere,isthatwhenanyelementofafullnameismissing,thesurroundingpunctuationandwhitespacesshouldalsobemissing.Thisfunctionreturnsawell-formattedfullnameofapersonintheUSA,withasmuchofthenamefilledinaspossible.Whenrunningthisfunction,youwillseethefollowing:
postgres=#SELECTformat_us_full_name('Mr','Martin','L','King','Jr');
format_us_full_name
-------------------------
Mr.MartinL.King,Jr.
(1row)
Now,let’strywithanamemissing:
postgres=#SELECTformat_us_full_name('','Martin','L','King','Jr');
format_us_full_name
---------------------
MartinL.King,Jr.
(1row)
Anotherwaytouseconditionalexpressions,isusingtheIF/THEN/ELSEblocks.Thefollowingisthesamefunctionagain,writtenusingIFstatements,ratherthanCASEstatements:
CREATEORREPLACEFUNCTIONformat_us_full_name(
prefixtext,firstnametext,
mitext,lastnametext,
suffixtext)
RETURNStextAS
$$
DECLARE
fname_mitext;
fmi_lnametext;
prefix_fmiltext;
pfmil_suffixtext;
BEGIN
fname_mi:=CONCAT_WS('',
IF(trim(firstname)='',NULL,firstname),
![Page 130: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/130.jpg)
IF(trim(mi)='',NULL,mi||'.')
);
fmi_lname:=CONCAT_WS('',
IF(fname_mi='',NULL,fname_mi),
IF(trim(lastname)='',NULL,lastname)
);
prefix_fmil:=CONCAT_WS('.',
IF(trim(prefix)='',NULL,prefix),
IF(fmi_lname='',NULL,fmi_lname)
);
pfmil_suffix:=CONCAT_WS(',',
IF(prefix_fmil='',NULL,prefix_fmil),
IF(trim(suffix)='',NULL,suffix||'.')
);
RETURNpfmil_suffix;
END;
$$
LANGUAGEplpgsql;
PostgreSQL’sPL/pgSQLprovidesseveralothersyntacticalvariantsoftheseconditionalexpressions.Thisintroductionfocusesonthemostcommonlyusedones.Foramorecompletediscussionofthetopic,visithttp://www.postgresql.org/docs/current/static/functions-conditional.html.
![Page 131: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/131.jpg)
LoopswithcountersThePL/pgSQLlanguageprovidesasimplewaytoloopthroughsomeelements.ThefollowingisafunctionthatreturnsthenthFibonaccisequencenumber:
CREATEORREPLACEFUNCTIONfib(ninteger)
RETURNSINTEGERAS$$
DECLARE
counterinteger:=0;
ainteger:=0;
binteger:=1;
BEGIN
IF(n<1)THEN
RETURN0;
ENDIF;
LOOP
EXITWHENcounter=n;
counter:=counter+1;
SELECTb,a+bINTOa,b;
ENDLOOP;
RETURNa;
END;
$$
LANGUAGEplpgsql;
SELECTfib(4);
Theprecedingcodegives3astheoutput.
Justfortherecord,eachelementintheFibonaccisequenceisthesumoftheprevioustwoelements.Thus,thefirstfewelementsofthesequenceshouldbe0,1,1,2,3,5,8,13,21,34,andsoon.ThereareafewPostgreSQLFibonaccisequencefunctionsoutthereontheinterwebs,buttheyusethedreadedrecursivemethod.Inthiscase,recursionisabadthing.Ourexampleusestheiterativemethodthatavoidstheuseofstacksforrecursion,asthismightresultinthelackofstackspaceforlargenumbers.
Inthisfunction,wealsointroduceddefaultvaluestothevariablesinthedeclarationssection.Whenthefunctionisinvoked,thevariableswillbeinitiallysettothesevalues.
Also,takeaquickganderatthestatementSELECTb,a+bINTOa,b.Thisstatementmakestwovariableassignmentsatthesametime.Itavoidstheuseofathirdvariablewhileactingonbothaandb.
AnotherslightvariationofthefunctionusingaFORloop,isasfollows:
CREATEORREPLACEFUNCTIONfib(ninteger)
RETURNSINTEGER
AS$$
DECLARE
counterinteger:=0;
ainteger:=0;
binteger:=1;
BEGIN
![Page 132: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/132.jpg)
IF(n<1)THEN
RETURN0;
ENDIF;
FORcounterIN1..n
LOOP
SELECTb,a+bINTOa,b;
ENDLOOP;
RETURNa;
END;
$$
LANGUAGEplpgsql;
Forsomeadditionalloopingsyntax,takealookatthePostgreSQLdocumentationpageathttp://www.postgresql.org/docs/current/static/plpgsql-control-structures.html.
StatementterminationInPL/pgSQL,allblocksandthestatementswithintheblocks,mustendwithasemicolon.TheexceptionsarethestatementsthatstartablockwithIForBEGIN.Block-startingstatementsarenotcompletestatements;therefore,thesemicolonisalwaysaftertheblock-endingstatement,suchasEND;orENDIF;.
![Page 133: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/133.jpg)
LoopingthroughqueryresultsBeforeweembarkonthisjourneyofqueryresultloops,IthinkIshouldwarnyou,thatifyouareusingthismethod,youareprobablydoingitwrong.Thisisoneofthemostprocessor-andmemory-intensiveoperationsthatPostgreSQLoffers.Thereareexceedinglyfewreasonstoiteratethrougharesultsetonthedatabaseserverthatoffsetthiscost.IwouldencourageyoutothinkhardabouthowtoimplementthesameideausingaVALUESlistinaquery,temporarytable,andpermanenttable,ortoprecomputethevaluesinanywaypossible,inordertoavoidthisoperation.So,doyoustillthinkyouhaveanoverwhelmingreasontousethistechnique?Okay,thenreadon.Thefollowingisthesimpleversion:
FORrowIN
EXECUTE'SELECT*FROMjob_queueqWHERENOTprocessedLIMIT100'
LOOP
CASErow.process_type
WHEN'archive_point_of_sale'
THENINSERTINTOhist_orders(...)
SELECT…FROMorders
INNERJOINorder_detail…
INNERJOINitem…;
WHEN'prune_archived_orders'
THENDELETEFROMorder_detail
WHEREorder_idin(SELECTorder_idFROMhist_orders);
DELETEFROMorders
WHEREorder_idIN(SELECTorder_idFROMhist_orders);
ELSE
RAISENOTICE'Unknownprocess_type:%',row.process_type;
END;
UPDATEjob_queueSETprocessed=TRUEWHEREid=q.id;
ENDLOOP;
Theprecedingexampleshowsabasicstrategypatternofprocessingmessagesinajobqueue.Usingthistechnique,therowsinatablecontainalistofjobsthatneedtobeprocessed.
WeintroducetheEXECUTEstatementhereaswell.TheSELECTstatementisastringvalue.UsingEXECUTE,wecandynamicallybuildPL/pgSQLcommandsasstringsandtheninvokethemasstatementsagainstthedatabase.Thistechniquecomesinhandy,whenwewanttochangethetablenameorotherSQLkeywordsthatmakeupourstatement.ThesepartsoftheSQLstatementcannotbestoredinvariablesandarenotgenerallychangeable.WithEXECUTE,wecanchangeanypartofthestatementwejollywellplease.WemustmentionthatEXECUTEhasacostassociatedwithit:thequeriesarepreparedeachtimebeforerunning.
ThefollowingisanexamplefromthePostgreSQLdocumentationthatshowsdynamiccommandsrunninginsidealoop:
CREATEFUNCTIONcs_refresh_mviews()RETURNSintegerAS$$
DECLARE
mviewsRECORD;
![Page 134: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/134.jpg)
BEGIN
PERFORMcs_log('Refreshingmaterializedviews…');
FORmviewsINSELECT*FROMcs_materialized_viewsORDERBYsort_key
LOOP
—Now"mviews"hasonerecordfromcs_materialized_views
PERFORMcs_log('Refreshingmaterializedview'||
quote_ident(mviews.mv_name)||'...');
EXECUTE'TRUNCATETABLE'||quote_ident(mviews.mv_name);
EXECUTE'INSERTINTO'||quote_ident(mviews.mv_name)||''||
mviews.mv_query;
ENDLOOP;
PERFORMcs_log('Donerefreshingmaterializedviews.');
RETURN1;
END;
$$LANGUAGEplpgsql;
Theprecedingloopingexample,showsamorecomplexfunctionthatrefreshesthedatainsomestagingtables.Thesestagingtablesaredesignatedmaterializedviewsbecausethedataisactuallyphysicallytransferredtothestagingtables.Thismethodwasacommonwaytoreducequeryexecutionoverheadformanypresentationsofthesamedata,beforematerializedviewswereofficiallysupportedinPostgreSQL9.3.Inthiscase,theinefficiencyofloopingistrivialcomparedtothecontinuedcostofrepeatedqueriestothesamedata.
![Page 135: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/135.jpg)
PERFORMversusSELECTYoumayhavenoticedastatementinthepreviousexamplethatwehaven’tcoveredyet.UsethePERFORMcommandwhenyouwanttojustdiscardtheresultsofastatement.Changethepreviousexampletothefollowingline:
SELECTcs_log("Donerefreshingmaterializedviews");
ThequeryenginewillreturnNodestinationforresultdata.
Wecanretrievetheresultsintovariables,andthenproceedtoignorethevariables,butthat’sjustalittletoosloppyformytaste.ByusingthePERFORMstatement,wehaveindicatedthatignoringtheresultswasnotaccidental.Wewerehappywiththefactthatthelogwasappendedtoblindly,andifitwasn’t,ohwell,wedidn’tfailtocontinuetheexecutionbecauseofalogentryissue.
![Page 136: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/136.jpg)
LoopingThroughArraysThereisaveryconvenientloopconstructcalledFOREACH,whichallowsyoutoloopthroughtheelementsofanarray.Let’sdiveintoanexample:
CREATEFUNCTIONfindmax(int[])RETURNSint8AS$$
DECLARE
maxint8:=0;
xint;
BEGIN
FOREACHxINARRAY$1
LOOP
IFx>maxTHEN
max:=x;
ENDIF;
ENDLOOP;
RETURNmax;
END;
$$LANGUAGEplpgsql;
Thisfunctionisquiteself-explanatory.Itfindsthemaximumvaluesfromagivenintegerarray.ThepointtobenotedhereisthatunlikeanormalFORloop,aFOREACHloopcanonlyuseacountervariablethatisalreadydeclared.Youcanseethatwehavedeclaredxbeforeweuseditasacounterintheloop.Youcanrunthisfunctiontoseeifitworks:
postgres=#selectfindmax(ARRAY[1,2,3,4,5,-1]);
findmax
---------
5
(1row)
![Page 137: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/137.jpg)
![Page 138: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/138.jpg)
ReturningarecordSofar,allofourfunctionexampleshavefeaturedasimplescalarvalueintheRETURNclause.InPL/pgSQL,youcanalsodefineset-returningfunctions(SRF).Thesefunctionscanreturneitheratypedefinedbyanexistingtableoragenericrecordtype.Let’stakealookatasimpleexample:
CREATETABLEnames(idserial,namevarchar);
INSERTINTOnames(name)VALUES('John');
INSERTINTOnames(name)VALUES('Martin');
INSERTINTOnames(name)VALUES('Peter');
CREATEORREPLACEFUNCTIONGetNames()RETURNSSETOFnamesAS'SELECT*FROM
names;'LANGUAGE'sql';
Wejustdefinedaverysimplefunction,GetNames(),whichwillsimplyreturnalltherowsfromournewlydefinednamestable.
IfyouruntheGetNames()functionnow,youwillgetthefollowingoutput:
postgres=#selectGetNames();
getnames
------------
(1,John)
(2,Martin)
(3,Peter)
(3rows)
YoucanuseanSRFinplaceofatableorasasubqueryintheFROMclauseofaquery.Here’sanexample:
postgres=#select*fromGetNames()whereid>2;
id|name
----+-------
3|Peter
(1row)
Inadditiontothetabletypes,wecanalsoreturngenerictypesfromanSRF.Wecanchangeourexamplealittletodemonstratethis.Let’sdefineanewreturntypeandanewfunction:
CREATETYPEnametypeAS(idint,namevarchar);
CREATEFUNCTIONPlpgGetNames()RETURNSSETOFnametypeAS
$$
DECLARE
rnametype%rowtype;
BEGIN
FORrINSELECTid,nameFROMnamesLOOP
RETURNNEXTr;
ENDLOOP;
RETURN;
END;
$$
![Page 139: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/139.jpg)
LANGUAGE'plpgsql';
ThePlpgGetNames()functiondeclaresavariablertobeofrowtypenametype.Thisvariableisusedtostoretherowsqueriedintheloop.Thefunctiondoesaloopoverthenamestableandsetsrtoeachrowintheresultset.TheRETURNNEXTcommandmeansthatanoutputrowisqueuedintothereturnsetofthefunction.Thisdoesnotcausethefunctiontoreturn.Finally,theRETURNstatementaftertheloopreturnsalltherows,whichwerequeuedearlierusingRETURNNEXT.
Let’srunournewfunction,asshownhere:
postgres=#SELECTPlpgGetNames();
plpggetnames
--------------
(1,John)
(2,Martin)
(3,Peter)
(3rows)
Forthesakeofasecondexample,wewillassumethatyouareinthemiddleofabigsoftwaredevelopmentupgradeprocedurethatusesaname/valuepairtablestructuretostoresettings.Youhavebeenaskedtochangethetablestructurefromthekeyandvaluecolumnstoaseriesofcolumns,wherethecolumnnameisnowthenameofthekey.ThisissimilartothepivottablesinExcel.Bytheway,youalsoneedtopreservethesettingsforeveryversionofthesoftwareyouhaveeverdeployed.
IfyoutakealookattheexistingCREATETABLEstatementforthetableyouhavetoworkwith,youwillfindthefollowing:
CREATETABLEapplication_settings_old(
versionvarchar(200),
keyvarchar(200),
valuevarchar(2000));
WhenyourunaSELECTstatementagainstthetable,youwillfindoutthattherearen’tmanysettings,buttherehavebeenquiteafewversionsofthesettings.So,let’smakeanewtablethatisalittlemoreexplicit:
CREATETABLEapplication_settings_new(
versionvarchar(200),
full_namevarchar(2000),
descriptionvarchar(2000),
print_certificatevarchar(2000),
show_advertisementsvarchar(2000),
show_splash_screenvarchar(2000));
TransformingthesettingsdataintothisnewformatcanbeaccomplishedwithanINSERTstatementandafunctionthatconvenientlyreturnsourdatainthenewtableformat.
Let’saddsometestdata,asfollows:
INSERTINTOapplication_settings_old
VALUES('3456','full_name','test_name');
INSERTINTOapplication_settings_old
![Page 140: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/140.jpg)
VALUES('3456','description','test_description');
INSERTINTOapplication_settings_old
VALUES('3456','print_certificate','yes');
INSERTINTOapplication_settings_old
VALUES('3456','show_advertisements','yes');
INSERTINTOapplication_settings_old
VALUES('3456','show_splash_screen','no');
Let’sgoaheadanddefinethefunction:
CREATEORREPLACEFUNCTION
flatten_application_settings(app_versionvarchar(200))
RETURNSsetofapplication_settings_new
AS$$
BEGIN
—Createatemporarytabletoholdasinglerowofdata
IFEXISTS(SELECTrelnameFROMpg_classWHERErelname='tmp_settings')
THEN
TRUNCATETABLEtmp_settings;
ELSE
CREATETEMPTABLEtmp_settings(LIKEapplication_settings_new);
ENDIF;
--therowwillcontainallofthedataforthisversion
INSERTINTOtmp_settings(version)VALUES(app_version);
—addthedetailstotherecordforthisapplicationversion
UPDATEtmp_settings
SETfull_name=(SELECTvalue
FROMapplication_settings_old
WHEREversion=app_version
ANDkey='full_name'),
description=(SELECTvalue
FROMapplication_settings_old
WHEREversion=app_version
ANDkey='description'),
print_certificate=(SELECTvalue
FROMapplication_settings_old
WHEREversion=app_version
ANDkey='print_certificate'),
show_advertisements=(SELECTvalue
FROMapplication_settings_old
WHEREversion=app_version
ANDkey='show_advertisements'),
show_splash_screen=(SELECTvalue
FROMapplication_settings_old
WHEREversion=app_version
ANDkey='show_splash_screen');
--handbacktheresultstothecaller
RETURNQUERYSELECT*FROMtmp_settings;
END;
$$LANGUAGEplpgsql;
Theprecedingfunctionreturnsasinglerowofdatatothecallingquery.Therowcontainsallthesettingsthatwerepreviouslydefinedaskey/valuepairs,butareexplicitlydefinedfieldsnow.Thefunctionandthefinaltablecanalsobeenhancedtotransformthedatatypesofthesettingstosomethingmoreexplicit.However,I’llleavethatoneuptoyou.
![Page 141: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/141.jpg)
Wethenproceedtousethefunctioninordertodothetransformation:
INSERTINTOapplication_settings_new
SELECT(flatten_application_settings(version)).*
FROM(
SELECTversion
FROMapplication_settings_old
GROUPBYversion)ASver;
Voilá!Thedataisnowavailableinatabularforminthenewtablestructure.
![Page 142: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/142.jpg)
![Page 143: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/143.jpg)
Actingonthefunction’sresultsThepreviousexampleshowedonewaytoretrieve,andfurtherprocess,functionresults.Thefollowingareafewmoreusefulwaystocallafunction:
SELECTfib(25);
SELECT(flatten_application_settings('9.08.97')).*;
SELECT*FROMflatten_application_settings('9.08.97');
AnyoftheprecedingmethodswillcreatealegalfieldlistinPostgreSQL,which,inturn,canbeusedinanywaythefieldsinasimpleSELECTstatementonatableareused.
Theexampleintheprevioussectionusedtheresultsoftheflatten_application_settings()function,asourceofdataforanINSERTstatement.ThefollowingisanexampleofhowtousethesamefunctionasadatasourceforUPDATE:
UPDATEapplication_settings_new
SETfull_name=flat.full_name,
description=flat.description,
print_certificate=flat.print_certificate,
show_advertisements=flat.show_advertisements,
show_splash_screen=flat.show_splash_screen
FROMflatten_application_settings('9.08.97')flat;
Usingtheapplicationversionasakey,wecanupdatetherecordsinthenewtable.Isn’tthisareallyhandywaytokeepupwiththechangestotheapplicationsettings,whileboththeoldandnewapplicationsarestillactive?I’lltakeanycomplimentsintheformofcash(orbeer),please.
![Page 144: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/144.jpg)
![Page 145: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/145.jpg)
SummaryWritingfunctionsinPostgreSQLisanextremelypowerfultool.PostgreSQLfunctionsprovidetheabilitytoaddfunctionalitytothedatabasecore,inordertoincreaseperformance,security,andmaintainability.
Thesefunctionscanbewritteninjustaboutanylanguagethatisavailabletotheopensourcecommunityandseveralthatareproprietary.Ifthelanguagethatyouwanttowritetheminisnotavailable,itcanbemadeavailablequicklyandeasilythroughaveryrobustandcompletecompatibilitylayer.Inthischapter,weonlylookedatPL/pgSQLfunctions.
Inthenextchapter,wewillfocusmoreonPL/pgSQLfunctions,andtakealookatthedifferentwaysinwhichdatacanbereturnedusingOUTparametersandreturnvalues.
![Page 146: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/146.jpg)
![Page 147: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/147.jpg)
Chapter4.ReturningStructuredDataInthepreviouschapter,wesawfunctionsthatreturnsinglevalues.Thesefunctionsreturneithera“scalar,”simpletypesuchasaninteger,text,ordata;oramorecomplextype,similartoarowinthedatabasetable.Inthischapter,wewillexpandtheseconceptsandshowyouhowtoreturnyourdatatotheclientinmorepowerfulways.
Wewillalsoexaminethefollowingtopics:
DifferencesbetweenSETOFscalars,rows,andarraysReturningCURSORs,whicharekindof“lazy”tables,thatis,somethingthatcanbeusedtogetasetofrows,butwhichmaynothaveactuallyevaluatedorfetchedtherowsyet,asthemodernworldisnotaboutrigidtable-structureddataWaystodealwithmorecomplexdatastructures,bothpredefinedanddynamicallycreated
Let’sstartwithasimpleexampleandthenaddmorefeaturesandvariantsaswego.
![Page 148: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/148.jpg)
SetsandarraysRowsetsaresimilartoarraysinmanyways,buttheymainlydifferintheirusage.Formostdatamanipulations,youwillwanttouserowsets,astheSQLlanguageisdesignedtodealwiththem.Arrays,however,aremostusefulforstaticstorage.Theyaremorecomplicatedforclientapplicationstousethanrowsets,withusabilityfeaturesmissing,suchasnosimpleandstraightforwardbuilt-inwaystoiterateoverthem.
![Page 149: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/149.jpg)
![Page 150: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/150.jpg)
ReturningsetsWhenyouwriteasetreturningfunction,therearesomedifferencesfromanormalscalarfunction.First,let’stakealookathowtoreturnasetofintegers.
![Page 151: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/151.jpg)
ReturningasetofintegersWewillrevisitourFibonaccinumbergeneratingfunction;however,thistimewewillnotjustreturnthenthnumber,butthewholesequenceofnumbersuptothenthnumber,asshownhere:
CREATEORREPLACEFUNCTIONfibonacci_seq(numinteger)
RETURNSSETOFintegerAS$$
DECLARE
aint:=0;
bint:=1;
BEGIN
IF(num<=0)
THENRETURN;
ENDIF;
RETURNNEXTa;
LOOP
EXITWHENnum<=1;
RETURNNEXTb;
num=num-1;
SELECTb,a+bINTOa,b;
ENDLOOP;
END;
$$LANGUAGEplpgsql;
Thefirstdifferencewesee,isthatinsteadofreturningasingleintegervalue,thisfunctionisdefinedtoreturnaSETOFinteger.
Then,ifyouexaminethecodecarefully,youwillseethattherearetwodifferenttypesofRETURNstatements.ThefirstistheordinaryRETURNfunctioninthefollowingcodesnippet:
IF(num<=0)
THENRETURN;
Inthiscase,theIFfunctionisusedtoterminatethefibonacci_seqfunctionearly,ifthelengthofthedesiredsequenceofFibonaccinumbersiszeroorless.
ThesecondkindofRETURNstatementisusedtoreturnvaluesandcontinueexecution:
RETURNNEXTa;
RETURNNEXTappendsrowstotheresultsetofthefunction,andtheexecutioncontinuesuntilanormalRETURNstatementisencounteredoruntilthecontrolreachestheendofthefunction.YoumayhavenoticedthatthereareafewotherthingswediddifferentlyinthisFibonacciexample,thanwedidearlier.First,wedeclaredandinitializedthevariablesaandbinsidetheDECLAREsection,insteadoffirstdeclaringandtheninitializingthem.Wealsousedtheargumentasadowncounterinsteadofusingaseparatevariabletocountfromzeroandthencomparingitwiththeargument.
Let’stestourfunctionnow.Inthenextsection,wewilldiscusshowtousethesetreturningfunctionsinmoredetail:
![Page 152: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/152.jpg)
postgres=#SELECTfibonacci_seq(5);
fibonacci_seq
---------------
0
1
1
2
3
(5rows)
Bothofthesetechniquessaveafewlinesofcodeandcanmakethecodemorereadable,dependingonyourpreferences.However,thelongerversionsmightbeeasiertofollowandunderstand,sowedon’tparticularlyendorseeitherway.
![Page 153: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/153.jpg)
![Page 154: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/154.jpg)
UsingasetreturningfunctionAsetreturningfunction(alsoknownasatablefunction)canbeusedinmostplaceswhereatable,view,orsubquerycanbeused.Theyareapowerfulandflexiblewaytoreturndata.
YoucancallthefunctionintheSELECTclause,asyoudowithascalarfunction:
postgres=#SELECTfibonacci_seq(3);
fibonacci_seq
---------------
0
1
1
(3rows)
YoucanalsocallthefunctionaspartoftheFROMclause:
postgres=#SELECT*FROMfibonacci_seq(3);
fibonacci_seq
---------------
0
1
1
(3rows)
YoucanevencallthefunctionintheWHEREclause:
postgres=#SELECT*FROMfibonacci_seq(3)WHERE1=ANY(SELECT
fibonacci_seq(3));
fibonacci_seq
---------------
0
1
1
(3rows)
Youcanlimittheresultset,justasinthecaseofqueryingatable:
postgres=#SELECT*FROMfibonacci_seq(10)asfibWHEREfib>3;
fibonacci_seq
---------------
5
8
13
21
34
(5rows)
Usingdatabase-sidefunctionsforallthedataaccessisagreatwaytosecureyourapplication;italsohelpswithperformanceandallowseasymaintenance.Tablefunctionsallowyoutousefunctionsinallcaseswhereyouwouldhavebeenforcedtousemorecomplexqueriesfromtheclientifonlyscalarfunctionswereavailable.
Returningrowsfromafunctionwilloftenbehelpfultoreturnbacktotheclientmore
![Page 155: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/155.jpg)
informationthanjustasetofintegers.Youmayneedallthecolumnsfromanexistingtable,andthesimplestwaytodeclareareturntypeforafunctionistojustusethetableaspartofthereturndefinition,asshownhere:
CREATEORREPLACEFUNCTIONinstalled_languages()
RETURNSSETOFpg_languageAS$$
BEGIN
RETURNQUERYSELECT*FROMpg_language;
END;
$$LANGUAGEplpgsql;
NoticethatyoustillneedtheSETOFpart,butinsteadofdefiningitasasetofintegers,weusepg_language,whichisatable.
YoucanuseTYPE,definedusingtheCREATETYPEcommandorevenVIEW:
hannu=#SELECT*FROMinstalled_languages();
-[RECORD1]-+----------
lanname|internal
lanowner|10
lanispl|f
lanpltrusted|f
lanplcallfoid|0
laninline|0
lanvalidator|2246
lanacl|
-[RECORD2]-+----------
lanname|c
lanowner|10
lanispl|f
lanpltrusted|f
lanplcallfoid|0
laninline|0
lanvalidator|2247
lanacl|
-[RECORD3]-+----------
lanname|sql
lanowner|10
lanispl|f
lanpltrusted|t
lanplcallfoid|0
laninline|0
lanvalidator|2248
lanacl|
-[RECORD4]-+----------
lanname|plpgsql
lanowner|10
lanispl|t
lanpltrusted|t
lanplcallfoid|12596
laninline|12597
lanvalidator|12598
lanacl|
-[RECORD5]-+----------
lanname|plpythonu
![Page 156: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/156.jpg)
lanowner|10
lanispl|t
lanpltrusted|f
lanplcallfoid|17563
laninline|17564
lanvalidator|17565
lanacl|
![Page 157: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/157.jpg)
![Page 158: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/158.jpg)
FunctionsbasedonviewsCreatingafunctionbasedonaviewdefinitionisaverypowerfulandflexiblewayofprovidinginformationtousers.Asanexampleofthis,IwilltellyouastoryofhowIstartedasimpleutilityviewtoanswerthequestion,“Whatqueriesarerunningnow,andwhichquerieshavebeenrunningforthelongesttime?”Thisevolvedintoafunctionbasedonthisview,plusafewmoreviewsbasedonthefunction.
ThewaytogetallthedatatoanswerthisquestioninPostgreSQLisbyusingthefollowingquery.Pleasenotethattheoutputisusinganexpandedmodeofpsql.Youcanturnitonusingthe\xmeta-command:
hannu=#SELECT*FROMpg_stat_activityWHEREstate='active';
-[RECORD1]----+--------------------------------
datid|17557
datname|hannu
pid|8933
usesysid|10
usename|postgres
application_name|psql
client_addr|
client_hostname|
client_port|-1
backend_start|2013-03-1913:47:45.920902-04
xact_start|2013-03-1914:05:47.91225-04
query_start|2013-03-1914:05:47.91225-04
state_change|2013-03-1914:05:47.912253-04
waiting|f
state|active
query|select*frompg_stat_activity|wherestate='active';
Theusualprocessistouseavariantofthefollowingquery,whichisalreadywrappedintoaviewhere:
CREATEVIEWrunning_queriesAS
SELECT
(CURRENT_TIMESTAMP-query_start)asruntime,
pid,
usename,
waiting,
query
FROMpg_stat_activity
WHEREstate='active'
ORDERBY1DESC
LIMIT10;
Soon,youwillnoticethatputtingthisqueryintoaviewisnotenough.Sometimes,youmaywanttovarythenumberoflowestqueries,whilesometimesyoumaynotwanttohavethefullquerytext,butjustthebeginning,andsoon.
Ifyouwanttovarysomeparameters,thelogicalthingtodoistouseafunctioninsteadofaview,asotherwiseyouwillneedtocreatedifferentviewsofeachnewrequirement:
![Page 159: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/159.jpg)
CREATEORREPLACEFUNCTIONrunning_queries(rowsint,qlenint)
RETURNSSETOFrunning_queriesAS
$$
BEGIN
RETURNQUERYSELECT
runtime,
pid,
usename,
waiting,
substring(query,1,qlen)asquery
FROMrunning_queries
ORDERBY1DESC
LIMITrows;
END;
$$LANGUAGEplpgsql;
Asasecurityprecaution,thedefaultbehaviorofthepg_stat_activityviewisthatonlysuperuserscanseewhatotherusersarerunning.Sometimes,itmaybenecessarytoallowthenon-superuserstoatleastseethetypeofquery(SELECT,INSERT,DELETE,orUPDATE)thatotherusersarerunning,buthidetheexactcontents.Todothis,youhavetomaketwochangestothepreviousfunction.
First,replacetherowtogetcurrent_querywiththefollowingcodesnippet:
(CASEWHEN(usename=session_user)
OR(SELECTusesuper
FROMpg_user
WHEREusename=session_user)
THEN
substring(query,1,qlen)
ELSE
substring(ltrim(query),1,6)||'***'
END)asquery
Thiscodesnippetcheckseachrowtoseewhethertheuserrunningthefunctionhaspermissiontoseethefullquery.Iftheuserisasuperuser,thenheshehaspermissiontoseethefullquery.Iftheuserisaregularuser,he/shewillonlyseethefullqueryforhis/herqueries.Allotherrowswillonlyshowthefirstsixcharactersfollowedby***tomarkitasashortenedquerystring.
Theotherkeypointtoallowingordinaryuserstorunthefunction,istograntthemtheappropriaterightstodoso.Whenafunctioniscreated,thedefaultbehavioristorunwiththeSECURITYINVOKERrights,whichmeansthatthefunctionwillbecalledwiththerightsoftheuserwhocalledit.Toeasilygrantthecorrectrightstocallthefunction,thefunctionneedstobecreatedwiththeSECURITYDEFINERattribute.Thiscausesthefunctiontoexecutewiththeprivilegesoftheuserwhocreatedthefunction;therefore,creatingthefunctionasasuperuserwillallowittoexecuteasasuperuser,regardlessoftherightsoftheuserwhocalledit.This,however,shouldbedonewithcautionbecauseasuperusercanbedangerous,andifyouendupexecutingastringthatispassedin,youwillhavealltheissuesofSQLinjectionattacks.
Now,youhaveafunction,whichyoucanusetogetthestartofthefivelongest-running
![Page 160: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/160.jpg)
queriesusingthefollowingquery:
SELECT*FROMrunning_queries(5,25);
Inordertogetacompletequery,youcanusethefollowing:
SELECT*FROMrunning_queries(1000,1024);
Youmaywanttodefineafewconvenienceviewsforthevariantsyouusemost,asfollows:
CREATEORREPLACEVIEWrunning_queries_tinyAS
SELECT*FROMrunning_queries(5,25);
CREATEVIEWrunning_queries_fullAS
SELECT*FROMrunning_queries(1000,1024);
Youcanevenredefinetheoriginalviewtousethefirstversionofthefunction:
CREATEORREPLACEVIEWrunning_queriesAS
SELECT*FROMrunning_queries(5,25);
Thisisusuallynotrecommended,butitdemonstratesthefollowingthreeimportantthings:
ViewsandfunctionscanhaveexactlythesamenameYoucangetacircularreferencebybasingafunctiononaviewandthenbasingaviewonthatfunctionIfyougetacircularreferenceinthisway,youcan’teasilychangeeitherdefinition
Toresolvethis,simplyavoidcircularreferences.
Evenwithoutcircularreferences,thereisstilladependencyontheviewcalledfromthefunction.If,forinstance,youneedtoaddacolumntoshowtheapplicationnametotherunning_queriesview,thefunctionneedstochangeaswell:
CREATEORREPLACEVIEWrunning_queriesAS
SELECT
CURRENT_TIMESTAMP-query_startasruntime,
pid,
usename,
waiting,
query,
application_nameasappname
FROMpg_stat_activity
ORDERBY1DESC
LIMIT10;
Theviewdefinitioncanbechangedwithoutanerror,butthenexttimeyoutrytoruntherunning_queries(int,int)function,youwillgetanerror:
hannu=#SELECT*FROMrunning_queries(5,25);
ERROR:structureofquerydoesnotmatchfunctionresulttype
DETAIL:Numberofreturnedcolumns(5)doesnotmatchexpectedcolumn
count(6).
CONTEXT:PL/pgSQLfunction"running_queries"line3atRETURNQUERY
Tofixthis,youneedtoaddanadditionalcolumntothefunction.Thisisoneofthe
![Page 161: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/161.jpg)
dangersofreusingtypesinthisway:youmightendupbreakingfunctionsunintentionally.PostgreSQLwon’ttellyou,whenyouchangeatypeinthisway,whetheranyfunctionswereusingthistypeandwillonlyfailwhenyoutrytorunthequery:
CREATEORREPLACEFUNCTIONrunning_queries(rowsint,qlenint)
RETURNSSETOFrunning_queriesAS
$$
BEGIN
RETURNQUERYSELECT
runtime,
pid,
usename,
waiting,
(CASEWHEN(usename=session_user)
OR(selectusesuper
frompg_user
whereusename=session_user)
THEN
substring(query,1,qlen)
ELSE
substring(ltrim(query),1,6)||'***'
END)asquery,
appname
FROMrunning_queries
ORDERBY1DESC
LIMITrows;
END;
$$
LANGUAGEplpgsql
SECURITYDEFINER;
![Page 162: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/162.jpg)
![Page 163: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/163.jpg)
OUTparametersandrecordsUsingapre-existingtype,table,orviewforcompoundreturntypesisasimplemechanismforreturningmorecomplexstructures.However,thereisoftenaneedtodefinethereturntypeofthefunctionwiththefunctionitselfandnotdependonotherobjects.Thisisespeciallytruewhenmanagingchangestoarunningapplication;so,overaperiodoftime,twobetterwaystohandlethishavebeenaddedtoPostgreSQL.
![Page 164: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/164.jpg)
OUTparametersUntilnow,allthefunctionswecreatedusedparametersthataredefinedasINparameters.TheINparametersaremeanttojustpassinformationintothefunctionthatcanbeused,butnotreturned.ParameterscanalsobedefinedasOUTorINOUTparametersifyouwantthefunctiontoreturnsomeinformationaswell:
CREATEORREPLACEFUNCTIONpositives(
INOUTaint,
INOUTbint,
INOUTcint)
AS$$
BEGIN
IFa<0THENa=null;ENDIF;
IFb<0THENb=null;ENDIF;
IFc<0THENc=null;ENDIF;
END;
$$LANGUAGEplpgsql;
Whenwerunthepreviousfunction,itonlyreturnsasinglerowofdatawiththreecolumns,asshownhere:
hannu=#SELECT*FROMpositives(-1,1,2);
-[RECORD1]
a|
b|1
c|2
![Page 165: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/165.jpg)
ReturningrecordsIfmultiplerowsofdataneedtobereturned,asimilarfunctionthatreturnsasetisachievedbyaddingRETURNSSETOFRECORD.ThistechniquecanonlybeusedwithfunctionsusingtheINOUTorOUTarguments:
CREATEFUNCTIONpermutations(INOUTaint,
INOUTbint,
INOUTcint)
RETURNSSETOFRECORD
AS$$
BEGIN
RETURNNEXT;
SELECTb,cINTOc,b;RETURNNEXT;
SELECTa,bINTOb,a;RETURNNEXT;
SELECTb,cINTOc,b;RETURNNEXT;
SELECTa,bINTOb,a;RETURNNEXT;
SELECTb,cINTOc,b;RETURNNEXT;
END;
$$LANGUAGEplpgsql;
Runningthepermutationsfunctionreturnssixrows,asexpected:
hannu=#SELECT*FROMpermutations(1,2,3);
-[RECORD1]
a|1
b|2
c|3
-[RECORD2]
a|1
b|3
c|2
-[RECORD3]
a|3
b|1
c|2
-[RECORD4]
a|3
b|2
c|1
-[RECORD5]
a|2
b|3
c|1
-[RECORD6]
a|2
b|1
c|3
Thisworkswell,butitseemsabitverboseforwhatisaprettysimpleoperation.ThisisbecausewecannotdirectlycallRETURNNEXTa,b,c,butweneedtofirstassignvaluestovariablesdeclaredbytheINOUTincantations.Wealsowanttoavoidtheevenclumsiersyntaxoftmp=a;a=b;b=tmp;.
DuetodesigndecisionsinthePL/pgSQLlanguage,thereiscurrentlynogoodwayto
![Page 166: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/166.jpg)
constructthereturnstructureatruntime,thatis,noRETURNa,b,c.
However,let’strytodoitanywayandseewhathappens.
![Page 167: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/167.jpg)
UsingRETURNSTABLEYoumaythinkthatiftherearenovisibleOUTparametersinafunctiondeclaredasRETURNSTABLE(...),thefollowingcodemightwork:
CREATEFUNCTIONpermutations2(aint,bint,cint)RETURNSTABLE(aint,b
int,cint)
AS$$
BEGIN
RETURNNEXTa,b,c;
END;
$$LANGUAGEplpgsql;
However,whenwetrytodoitthisway,wegetanerror:
ERROR:parametername"a"usedmorethanonce
CONTEXT:compilationofPL/pgSQLfunction"permutations2"nearline1
ThiserrorhintsthatthefieldsinthereturntabledefinitionarealsoactuallyjustOUTparametersandthewholeRETURNSTABLEsyntaxisjustanotherwaytospellCREATEFUNCTIONf(OUT…,OUT…)RETURNSRECORD….
Thiscanbeverifiedfurtherbychangingtheinputparameters,sothatthedefinitioncanbefedintoPostgreSQL:
CREATEFUNCTIONpermutations2(iaint,ibint,icint)
RETURNSTABLE(aint,bint,cint)
AS$$
BEGIN
RETURNNEXTa,b,c;
END;
$$LANGUAGEplpgsql;
Whenwetrytocreatethefunction,wegetthefollowingoutput:
ERROR:RETURNNEXTcannothaveaparameterinfunctionwithOUTparameters
LINE5:RETURNNEXTa,b,c;
^
Soyes,thefieldsofthetableintheRETURNSdefinitionareactuallyjustOUTparameters.
![Page 168: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/168.jpg)
ReturningwithnopredefinedstructureSometimes,youreallyneedtowriteafunctionwherethereturnstructureisunknown.OnegoodthingaboutPostgreSQLfunctiondeclarations,isthatyoucanusethereturntypeRECORD,whichcanbeleftundefineduntilthefunctioniscalled:
CREATEORREPLACEFUNCTIONrun_a_query(queryTEXT)
RETURNSSETOFRECORD
AS$$
DECLARE
retvalRECORD;
BEGIN
FORretvalINEXECUTEqueryLOOP
RETURNNEXTretval;
ENDLOOP;
END;
$$LANGUAGEplpgsql;
Thisisafunctionthatletsauserexecuteaquery;itisquiteuselessassuch,butitcanbeusedasthebasisformoreusefulfunctionsthat,forexample,letusersrunqueriesonlyatacertaintime,orcanbeusedtoperformsomechecksonqueriesbeforerunningthem.
Simplyrunthefollowingquery:
SELECT*FROMrun_a_query('SELECTusename,usesysidFROMpg_user');
Youwillgetthefollowingerror:
ERROR:acolumndefinitionlistisrequiredforfunctionsreturning
"record"
LINE1:select*fromrun_a_query('selectusename,usesysidfrompg_…
Tousethiskindofafunction,youneedtotellPostgreSQLwhatthereturnvalueswillbe,byaddingacolumndefinitionlistatthetimeofcallingafunctioninthefollowingway:
SELECT*FROMrun_a_query('SELECTusename,usesysidFROMpg_user')AS
("user"text,uidint);
So,willthiswork?No,youwillgetthefollowingerror:
ERROR:wrongrecordtypesuppliedinRETURNNEXT
DETAIL:Returnedtypenamedoesnotmatchexpectedtypetextincolumn1.
CONTEXT:PL/pgSQLfunctionrun_a_query(text)line6atRETURNNEXT
Bychangingthingsslightly,wefinallyarriveatsomethingthatworks,asfollows:
hannu=#SELECT*FROMrun_a_query('SELECTusename::text,usesysid::intFROM
pg_user')AS("user"text,uidint);
-[RECORD1]--
user|postgres
uid|10
-[RECORD2]--
user|hannu
uid|17573
Whatdowelearnfromthis?PostgreSQLwillletyoureturnanarbitraryrecordfroma
![Page 169: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/169.jpg)
function,butitisveryparticularinhowitdoesthis.Whenyoucallthefunction,youwillneedtobeverydeliberateaboutthings,especiallydatatypes.PostgreSQLwillusedefaultcaststoconvertdatatodifferentdatatypesifithasenoughinformation.However,inafunctionsuchasthis,muchofthatinformationisnotknown.
![Page 170: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/170.jpg)
ReturningSETOFANYThereisanotherwaytodefinefunctionsthatcanoperateon,andreturn,incompletetypedefinitions:usingtheANY*pseudotypes.
Let’sdefineafunction,whichturnsasimpleone-dimensionalPostgreSQLarrayofanytypeintoasetofrowswithoneelementofthesametype:
CREATEORREPLACEFUNCTIONarray_to_rows(array_inANYARRAY)
RETURNSTABLE(row_outANYELEMENT)
AS$$
BEGIN
FORiIN1..array_upper(array_in,1)LOOP
row_out=array_in[i];
RETURNNEXT;
ENDLOOP;
END;
$$LANGUAGEplpgsql;
Thisworkswellonanarrayofintegers:
hannu=#SELECTarray_to_rows('{1,2,3}'::int[]);
-[RECORD1]-+--
array_to_rows|1
-[RECORD2]-+--
array_to_rows|2
-[RECORD3]-+--
array_to_rows|3
Italsoworkswellonanarrayofdates,asshownhere:
hannu=#SELECTarray_to_rows('{"1970-1-1","2012-12-12"}'::date[]);
-[RECORD1]-+-----------
array_to_rows|1970-01-01
-[RECORD2]-+-----------
array_to_rows|2012-12-12
Thefunctionevenworksonarraysofrecordsfromuser-definedtables:
hannu=#CREATETABLEmydata(idserialprimarykey,datatext);
CREATETABLE
hannu=#INSERTINTOmydataVALUES(1,'one'),(2,'two');
INSERT02
hannu=#SELECTarray_to_rows(array(SELECTmFROMmydatam));
-[RECORD1]-+--------
array_to_rows|(1,one)
-[RECORD2]-+--------
array_to_rows|(2,two)
hannu=#SELECT*FROMarray_to_rows(array(SELECTmFROMmydatam));
-[RECORD1]
id|1
data|one
-[RECORD2]
id|2
![Page 171: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/171.jpg)
data|two
ThelasttwoSELECTstatementsreturnaone-columntableofthetypemydataandatwo-columntableofthesametypeexpandedintoitscomponentcolumns.Thissinglefunctionisflexibleenoughtohandleseveraldifferenttypesofdatawithoutanychanges.
NoteThereisamorepotentversionofarray_to_rowsbuiltintoPostgreSQLcalledunnest().Thebuilt-infunctionisfasterthanoursamplefunctionandcanalsodealwitharrayswithmorethanonedimension:
hannu=#SELECTunnest('{{1,2,3},{4,5,6}}'::int[]);
-[RECORD1]
unnest|1
-[RECORD2]
unnest|2
-[RECORD3]
unnest|3
-[RECORD4]
unnest|4
-[RECORD5]
unnest|5
-[RECORD6]
unnest|6
PostgreSQLhasaweirdarraytype,whichcanholdthearraysofanynumberofdimensions.Itisevenweirderthanthis,asthearrayslicesinanydimensioncanalsostartwithanypositiveindex(andtheyare,bydefault,1-based).Forexample,anarraywithindicesrangingfrom-2to2isproducedbythefollowingincantation:
hannu=#SELECT'[-2:2]={1,2,3,4,5}'::int[];
-[RECORD1]------------
int4|[-2:2]={1,2,3,4,5}
Tocheckwhetherthisreallyisthecase,usethefollowingcodesnippet:
hannu=#SELECTarray_dims('[-2:2]={1,2,3,4,5}'::int[]);
-[RECORD1]------
array_dims|[-2:2]
Thethirdelementofthearrayis3,andthisisthemiddleelement.
![Page 172: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/172.jpg)
VariadicargumentlistsPostgreSQLallowsyoutowriteafunctionwithavariablenumberofarguments.ThisisaccomplishedusingVARIADIC.Let’stakealookatapracticalexample.Supposeyouwanttolimittheresultsofaqueryinyourfunction,basedontheVARIADIClistofarguments;here’sonewaytodothis:
CREATEORREPLACEFUNCTIONget_nspc_tbls(VARIADICarrname[])
RETURNSTABLE(table_namename,idoid,nspnamename)
AS$$
BEGIN
RETURNQUERYSELECTc.relname,c.oid,n.nspnamefrompg_classc,
pg_namespacenwherec.relnamespace=n.oidandn.nspname=any(arr);
END;
$$LANGUAGEplpgsql;
Theprecedingfunctionletsyoulistthetables,whichareinspecifiednamespaces.Thevariablelistallowsyoutoprovideoneormorenamespacenames.Thistrickcanbequitehandyinvarioussituations.Noticetheuseoftheanyfunction;youcan’tsubstituteitwithanINclause,asthiswilltrytocompareanametypewithname[]:
postgres=#SELECT*FROMget_nspc_tbls('public','pg_temp');
-[RECORD1]------------------------
table_name|a
id|16434
nspname|public
-[RECORD2]------------------------
table_name|parameter
id|24682
nspname|public
-[RECORD3]------------------------
table_name|application_settings_old
id|24690
nspname|public
-[RECORD4]------------------------
table_name|foo
id|16455
nspname|pg_temp
![Page 173: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/173.jpg)
![Page 174: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/174.jpg)
AsummaryoftheRETURNSETOFvariantsYoulearnedthatyoucanreturntable-likedatasetsfromafunctionusingoneofthefollowing:
RETURNS RECORDstructure INSIDEfunction
SETOF<type> Thisisobtainedfromthetypedefinition
DECLARErowvariableoftheROWorRECORDtype
ASSIGNtorowvariable
RETURNNEXTvar;
SETOF
<table/view>Thisisthesameasthetableorviewstructure
SETOFRECORD DynamicusingAS(nametype,…)atcallsite
SETOFRECORD ThisusestheOUTandINOUTfunctionarguments.AssignedtotheOUTvariables RETURNNEXT;
TABLE(...)
Thisisdeclaredinline,inparentheses,aftertheTABLEkeywordandisconvertedtotheOUTvariableforuseinfunctions.ItisassignedtotheOUTvariablesfromtheTABLE(...)partofthedeclaration.
RETURNNEXT;
![Page 175: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/175.jpg)
![Page 176: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/176.jpg)
ReturningcursorsAnothermethodthatcanbeusedtogettabulardataoutofafunction,isusingCURSOR.
CURSOR,oraportal,asitissometimesreferredtoinPostgreSQLdocumentation,isaninternalstructurethatcontainsapreparedqueryplan,readytoreturnrowsfromthequery.Sometimes,thecursorneedstoretrieveallthedataforthequeryatonce,butformanyqueriesitdoeslazyfetching.Forexample,queriesthatneedtoscanallofthedatainatable,suchasSELECT*FROMxtable,onlyreadtheamountofdatathatisneededforeachFETCHfromthecursor.
InplainSQL,CURSORisdefinedasfollows:
DECLAREmycursorCURSORFOR<query>;
Later,therowsarefetchedusingthefollowingstatement:
FETCHNEXTFROMmycursor;
Whileyoucanuseacursortohandlethedatafromasetreturningfunctiontheusualway,bysimplydeclaringthecursorasDECLAREmycursorCURSORFORSELECT*FROMmysetfunc();,manytimesitismorebeneficialtohavethefunctionitselfjustreturnacursor.
Youwillwanttodothisifyouneeddifferentcursorsbasedonargumentvalues,orifyouneedtoreturndynamicallystructureddataoutofafunction,withoutdefiningthestructurewhencallingthefunction.
ThecursorinPL/pgSQLisrepresentedbyavariableofthetyperefcursorandmustbedeclaredinoneofthefollowingthreeways:
DECLARE
curs1refcursor;
curs2CURSORFORSELECT*FROMtenk1;
curs3CURSOR(keyinteger)ISSELECT*FROMtenk1WHEREunique1=key;
ThefirstvariantdeclaresanunboundcursorthatneedstobeboundtoaqueryatOPENtime.Thetworemainingvariantsdeclareacursorboundtoaquery.
NoteYoucanreadagoodtechnicaloverviewonhowtousecursorsinPL/pgSQLfunctionsfromtheofficialPostgreSQLdocumentationathttp://www.postgresql.org/docs/current/static/plpgsql-cursors.html.
Onethingtonoteaboutthedocumentationisthatyoudon’treallyneedto“return”thecursor,atleastnotnowbecausecursorscanalsobepassedbacktothecallerinOUTparameters.
ThePostgreSQLdocumentationstates:
“Thefollowingexampleshowsonewaytoreturnmultiplecursorsfromasingle
![Page 177: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/177.jpg)
function:
CREATEFUNCTIONmyfunc(refcursor,refcursor)RETURNSSETOFrefcursorAS$$
BEGIN
OPEN$1FORSELECT*FROMtable_1;
RETURNNEXT$1;
OPEN$2FORSELECT*FROMtable_2;
RETURNNEXT$2;
END;
$$LANGUAGEplpgsql;
—needtobeinatransactiontousecursors.
BEGIN;
SELECT*FROMmyfunc('a','b');
FETCHALLFROMa;
FETCHALLFROMb;
COMMIT;"
YoucanalsowritethemyfuncfunctionusingtheOUTparameters:
CREATEFUNCTIONmyfunc2(cur1refcursor,cur2refcursor)
RETURNSVOIDAS$$
BEGIN
OPENcur1FORSELECT*FROMtable_1;
OPENcur2FORSELECT*FROMtable_2;
END;
$$LANGUAGEplpgsql;
Youwillstillrunthefunctioninexactlythesamewayasthefunctionreturningthecursorvariable.
![Page 178: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/178.jpg)
IteratingovercursorsreturnedfromanotherfunctionTowrapupourcursors’discussion,let’sgothroughanexampleofreturningacursorandtheniteratingoverthereturnedcursorinanotherPL/pgSQLfunction:
1. First,let’screateafive-rowtableandfillitwithdata:
CREATETABLEfiverows(idserialPRIMARYKEY,datatext);
INSERTINTOfiverows(data)VALUES('one'),('two'),
('three'),('four'),('five');
2. Next,let’sdefineourcursorreturningfunction.Thisfunctionwillopenacursorforaquery,basedonitsargumentandthenreturnthatcursor:
CREATEFUNCTIONcurtest1(currefcursor,tagtext)
RETURNSrefcursor
AS$$
BEGIN
OPENcurFORSELECTid,data||'+'||tagFROMfiverows;
RETURNcur;
END;
$$LANGUAGEplpgsql;
3. Next,wedefineafunction,whichusesthefunctionwejustcreatedtoopentwoadditionalcursors,andthenprocessthequeryresults.Toshowthatwearenotcheatingandthatthefunctionreallycreatesthecursors,weusethefunctiontwiceanditerateovertheresultsinparallel:
CREATEFUNCTIONcurtest2(tag1text,tag2text)
RETURNSSETOFfiverows
AS$$
DECLARE
cur1refcursor;
cur2refcursor;
rowrecord;
BEGIN
cur1=curtest1(NULL,tag1);
cur2=curtest1(NULL,tag2);
LOOP
FETCHcur1INTOrow;
EXITWHENNOTFOUND;
RETURNNEXTrow;
FETCHcur2INTOrow;
EXITWHENNOTFOUND;
RETURNNEXTrow;
ENDLOOP;
END;
$$LANGUAGEplpgsql;
Pleasenote,thatoncearecordvariableinsideaplpgsqlfunctionisdefinedbybeingused,itcan’tbechangedfromrecordtypeforthedurationofthatsessionbecause
![Page 179: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/179.jpg)
PL/pgSQLstoresandreusestheplanbuiltwiththerecordtype.
BypassinginNULLtothefirstparametersofcurtest1,PostgreSQLautomaticallygeneratesthecursornamessothatmultipleinvocationsofthisfunctionwillnotgetnameconflictswithanyotherfunctions,whichalsocreatecursors.
![Page 180: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/180.jpg)
WrappingupoffunctionsreturningcursorsTheprosofusingcursorsareasfollows:
Cursorsareausefultoolifyoudon’twanttoalwaysexecutethequeryandwaitforthefullresultsetbeforereturningfromafunctionCurrently,theyarealsotheonlywaytoreturnmultipleresultsetsoutofauser-definedfunction
Theconsofusingcursorsareasfollows:
Theymainlyworktopassdatabetweenfunctionsontheserver,andyouarestilllimitedtoonerecordsetpercallreturnedtothedatabaseclientTheyaresometimesconfusingtouse,andboundandunboundcursorsarenotalwaysinterchangeable
NoteYoucanreadmoreaboutcursorsathttp://www.postgresql.org/docs/current/static/plpgsql-cursors.html.
![Page 181: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/181.jpg)
![Page 182: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/182.jpg)
OtherwaystoworkwithstructureddataWenowhavecoveredthetraditionalwaysofreturningsetsofstructureddatafromfunctions.Wewillnowstartwiththemoreinterestingpart.Othermethodstopassaroundcomplexdatastructureshaveevolvedintheworld.
![Page 183: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/183.jpg)
Complexdatatypesforthemodernworld–XMLandJSONIntherealworld,mostofthedataisnotinasingletableandthedatabaseisnotthemainthingthatmostprogrammersfocuson.Often,theydon’teventhinkaboutitatall,oratleasttheywouldrathernotthinkaboutit.
Ifyouareadatabasedeveloperwhoworksonthedatabasesideofthings,itisoftendesirabletotalktotheclients(beitweborapplicationdevelopersasyourclient,orprogramsasdatabaseclients)inthelanguagetheyspeak.Currently,thetwomostwidelyspokendatalanguagesbythewebapplicationsandtheirdevelopersareXMLandJSON.
BothXMLandJSONaretext-baseddataformats,andassuch,theycanbeeasilysavedintofieldsofthetypetext.PostgreSQL,beingaDBMS,builtforbeinguser-extendable,alsohasextensivesupportforboththeseformats.
![Page 184: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/184.jpg)
XMLdatatypeandreturningdataasXMLfromfunctionsOneoftheextensionsaddedtoPostgreSQL,inordertosupportXMLdata,isanativeXMLdatatype.WhiletheXMLdatatypeislargelyjustatextfield,itdiffersfromtextinthefollowingways:
TheXMLstoredinanXMLfieldischeckedoninsertsandupdatestobewell-formedTherearesupportfunctionstoproduceandworkwithknownwell-formedXML
AnXMLvaluecanbeproducedinacoupleofways,includingthestandardSQLmethod:
XMLPARSE({DOCUMENT|CONTENT}value)
PostgreSQLalsohasaspecificsyntaxthatwillproduceanXMLvalue:
xml'<foo>bar</foo>'
'<foo>bar</foo>'::xml
AnXMLvaluecanbeeasilyconvertedtoatextrepresentationusingtheXMLSERIALIZEfunction,asfollows:
XMLSERIALIZE({DOCUMENT|CONTENT}valueAStype)
Additionally,PostgreSQLallowsyoutosimplycasttheXMLvalueastext.
NoteThefulldescriptionoftheXMLdatatypeanditsassociatedfunctionsisavailableathttp://www.postgresql.org/docs/current/static/datatype-xml.html.AseachversionofPostgreSQLhasimproved,thesupportforXMLhasalsoimproved.
Thereareseveral*_to_xmlfunctionsinPostgreSQL,whichtakeeitheraSQLquery,oratable,orviewasinputandreturnitscorrespondingXMLrepresentation.
Let’stakealookatthisusingthefiverowstablewedefinedpreviouslyintheReturningcursorssection.
First,let’sgetthetabledataasanXML:
hannu=#SELECTtable_to_xml('fiverows',true,false,'')ASs;
-[RECORD1]-------------------------------------------------------
s|<fiverowsxmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
|<row>
|<id>1</id>
|<data>one</data>
|</row>
|
|<row>
|<id>2</id>
|<data>two</data>
|</row>
![Page 185: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/185.jpg)
|
|<row>
|<id>3</id>
|<data>three</data>
|</row>
|
|<row>
|<id>4</id>
|<data>four</data>
|</row>
|
|<row>
|<id>5</id>
|<data>five</data>
|</row>
|
|</fiverows>
|
IfyouhaveaclientthatcanhandleXML,thenthe*_to_xmlfunctionscanbethebestwaytoreturncomplexdata.
Anothergoodthingaboutthe*_to_xmlfunctionsisthatyoucancreateafunctionwhichreturnsseveraldifferentXMLdocumentsinonegoand,thus,returnsdatarowswithdifferentstructures.Agoodexample,willbeapaymentorderandrows,wherethefirstrecordreturnedbythefunctionistheXMLfortheorderheaderfollowedbyoneormorerecordsofXMLfortheorderrows,allreturnedbythesamefunctioninonecall.
Thereare,atthetimeofwritingthisbook,fivevariantsofthe*_to_xmlfunctions:
cursor_to_xml(cursorrefcursor,countinteger,nullsbool,tableforestbool,
targetnstext)
query_to_xml(querytext,nullsbool,tableforestbool,targetnstext)
table_to_xml(tblregclass,nullsboolean,tableforestboolean,targetns
text)
schema_to_xml(schemaname,nullsboolean,tableforestboolean,targetns
text)
database_to_xml(nullsboolean,tableforestbool,targetnstext)
Thecursor_to_xml(...)function,whichiteratesoveranopencursor,isrecommendedforlargedatasets,asitcanconvertthedataintochunksofrowswithoutfirstaccumulatingallthedatainmemory.
ThenextthreefunctionsreturnastringthatrepresentsaSQLquery,atablename,oraschemaname,andreturnallthedatafromthenamedobject.Thetable_to_xml()functionalsoworksonviews.Then,thereisthedatabase_to_xml(...)function,whichconvertsthecurrentdatabasetoanXMLdocument.However,acommonresultofrunningitonaproductiondatabaseisanout-of-memoryerroriftheoutputistoobig:
hannu=#SELECTdatabase_to_xml(true,true,'n');
ERROR:outofmemory
DETAIL:Failedonrequestofsize1024.
![Page 186: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/186.jpg)
ReturningdataintheJSONformatInPostgreSQL9.2,thereisanewnativedatatypeforJSONvalues.ThisnewsupportforJSONfollowedthesamegrowthpatternasXML.ItinitiallystartedwithtwofunctionstoconvertarraysandrecordstotheJSONformat,butinPostgreSQL9.3,therearemanynewfunctionsintroduced.ThefollowingisasummaryofimprovementsinthePostgreSQL9.3JSONsupport:
TherearededicatedJSONoperatorssuchas->,->>,and#>TherearetennewJSONfunctions
TheJSONparserisexposedasanAPI.TheAPIprovideshooksforthesignificantparserevent,suchasthebeginningandendofobjectsandarrays,andprovidingfunctionstohandlethesehooksallowsawidevarietyofJSONprocessingfunctionstobecreated.
ThehstoreextensionhastwonewJSON-relatedfunctions,hstore_to_json(hstore)andhstore_to_json_loose(hstore).
NoteYoucanreadaboutthenewJSONoperatorsandthefunctionsintheofficialdocumentationathttp://www.postgresql.org/docs/current/static/functions-json.html.
Therow_to_json(record,bool)functionisusedtoconvertanyrecordtoJSON,andarray_to_json(anyarray,bool)isusedtoconvertanyarraytoJSON.
Thefollowingaresomesimpleexamplesoftheusageofthesefunctions:
hannu=#SELECTarray_to_json(array[1,2,3]);
-[RECORD1]-+--------
array_to_json|[1,2,3]
hannu=#SELECT*FROMtest;
-[RECORD1]--------------------
id|1
data|0.26281
tstampt|2012-04-0513:21:03.235
-[RECORD2]--------------------
id|2
data|0.1574
tstampt|2012-04-0513:21:05.201
hannu=#SELECTrow_to_json(t)FROMtestt;
-[RECORD1]-----------------------------------------------------
row_to_json|{"id":1,"data":0.26281,"tstampt":"2012-04-0513:21:03.235"}
-[RECORD2]-----------------------------------------------------
row_to_json|{"id":2,"data":0.1574,"tstampt":"2012-04-0513:21:05.201"}
ThesefunctionsareveryusefulastheyenableustowritefunctionsreturningmuchmorecomplexdatathanwaspossibleusingthestandardRETURNSTABLEsyntax,buttherealpowerofthesefunctionscomesfrombeingabletoconvertarbitrarilycomplexrows.
Let’sfirstcreateasimpletablewithsomedata:
![Page 187: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/187.jpg)
CREATETABLEtest(
idserialPRIMARYKEY,
datatext,
tstamptimestampDEFAULTcurrent_timestamp
);
INSERTINTOtest(data)VALUES(random()),(random());
Now,let’screateanothertable,whichhasonecolumnwiththedatatypeoftheprevioustable,andinsertrowsfromthistableinthenewtable:
hannu=#CREATETABLEtest2(
hannu(#idserialPRIMARYKEY,
hannu(#data2test,
hannu(#tstamptimestampDEFAULTcurrent_timestamp
hannu(#);
hannu=#INSERTINTOtest2(data2)SELECTtestFROMtest;
INSERT02
hannu=#SELECT*FROMtest2;
-[RECORD1]------------------------------------
id|5
data2|(1,0.26281,"2012-04-0513:21:03.235204")
tstamp|2012-04-3015:42:11.757535
-[RECORD2]------------------------------------
id|6
data2|(2,0.15740,"2012-04-0513:21:05.2033")
tstamp|2012-04-3015:42:11.757535
Now,let’sseehowrow_to_json()handlesthistable:
hannu=#SELECTrow_to_json(t2,true)FROMtest2t2;
row_to_json
-----------------------------------------------------------
{"id":5,
"data2":{"id":1,"data":"0.26281",
"tstamp":"2012-04-0513:21:03.235204"},
"tstamp":"2012-04-3015:42:11.757535"}
{"id":6,
"data2":{"id":2,"data":"0.15740",
"tstamp":"2012-04-0513:21:05.2033"},
"tstamp":"2012-04-3015:42:11.757535"}
(2rows)
TheresultwasconvertedtoJSONwithoutanyproblems.
Justtobesure,let’spushthecomplexityupabitmoreandcreateatest3table,whichhasanarrayofthetable2rowsasitsdatavalue:
CREATETABLEtest3(
idserialPRIMARYKEY,
data3test2[],
tstamptimestampDEFAULTcurrent_timestamp
);
INSERTINTOtest3(data3)
SELECTarray(SELECTtest2FROMtest2);
Let’sseewhetherrow_to_jsonstillworks,asshownhere:
![Page 188: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/188.jpg)
SELECTrow_to_json(t3,true)FROMtest3t3;
------------------------------------------
{"id":1,
"data3":[{"id":1,
"data2":{"id":1,
"data":"0.262814193032682",
"tstamp":"2012-04-0513:21:03.235204"},
"tstamp":"2012-04-0513:25:03.644497"
},
{"id":2,
"data2":{"id":2,
"data":"0.157406373415142",
"tstamp":"2012-04-0513:21:05.2033"},
"tstamp":"2012-04-0513:25:03.644497"
}
],
"tstamp":"2012-04-1614:40:15.795947"}
(1row)
Yes,itdoes!
Well,actuallyIhadtomanuallyformatitalittle,astheprettyprintflagtorow_to_json()onlyforksforthetoplevel,andthesecondrowoftheresult(theonethatfollows"data3")wasallinoneline.However,JSONitselfwascompletelyfunctional!
![Page 189: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/189.jpg)
![Page 190: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/190.jpg)
SummaryThemainpointsyoulearnedinthischapterarethatyoucanreturnmultiplerowsandreturndatausingOUTparameters,aswellasreturnmultiplerowsofcomplexdata,similartoaSELECTquery.Youalsolearnedthatseveralsetsoftablescanbereturned,andyoucanpossiblyhavethemevaluatedinalazymannerusingrefcursors.Moreover,youcanreturndataascomplexasyouwantusingeitherXMLorJSON.
So,therereallyareveryfewreasonsfornotusingdatabasefunctionsasyourmaininteractionmechanismwiththedatabase.Inthenextchapter,wewilllearnhowtocallfunctionswhendifferenttypesofeventsoccurinthedatabase.
![Page 191: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/191.jpg)
![Page 192: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/192.jpg)
Chapter5.PL/pgSQLTriggerFunctionsWhileitisgenerallyagoodpracticetokeeprelatedcodetogetherandavoidhiddenactionsaspartofthemainapplicationcodeworkflows,therearevalidcaseswhereitisagoodpracticetoaddsomekindofgeneralorcross-applicationfunctionalitytothedatabaseusingautomatedactions,whichhappeneachandeverytimeatableismodified.Thatis,actionsarepartofyourdatamodelandnotyourapplicationcodeandyouwanttobesurethatitisnotpossibletoforgetorbypassthem,whichissimilartohowconstraintsmakeitimpossibletoinsertinvaliddata.
Themethodusedtoaddautomatedfunctioncallstoatablemodifyingeventiscalledatrigger.Triggersareespeciallyusefulforthecaseswheretherearemultipledifferentclientapplications—possiblyfromdifferentsourcesandusingdifferentprogrammingstyles—accessingthesamedatausingmultipledifferentfunctionsorsimpleSQL.
Fromastandard’sperspective,triggersarestandardizedinSQL3(SQL1999).Triggersaregenerallydefinedusinganevent-condition-action(ECA)model.Eventsoccurinthedatabase,whichtriggertheinvocationofacertainfunctioniftheconditionsaresatisfied.Alldataactionsperformedbythetriggerexecutewithinthesametransactioninwhichthetriggerisexecuting.TriggerscannotcontaintransactioncontrolstatementssuchasCOMMITandROLLBACK.Triggerscanbestatementlevelorrowlevel(moreonthislaterinthechapter).
InPostgreSQL,atriggerisdefinedintwosteps:
1. DefineatriggerfunctionusingCREATEFUNCTION.2. BindthistriggerfunctiontoatableusingCREATETRIGGER.
Inthischapter,wewillcoverthefollowingtopics:
CreatingatriggerandatriggerfunctionTakingalookatsomeoftheusecasesoftriggers,suchasanaudittrigger,anddisallowingcertainoperationsusingtriggersDiscussingconditionaltriggersandtriggersonspecificfieldchangesDescribingthelistofvariablespassedontoatriggerinbrief,whichcanbeusedinthetriggerfunctionforconditionallookups
![Page 193: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/193.jpg)
CreatingthetriggerfunctionThetriggerfunction’sdefinitionlooksmostlylikeanordinaryfunctiondefinition,exceptthatithasareturnvaluetype,trigger,anditdoesnottakeanyarguments:
CREATEFUNCTIONmytriggerfunc()RETURNStriggerAS$$…
TriggerfunctionsarepassedinformationabouttheircallingenvironmentthroughaspecialTriggerDatastructure,whichinthecaseofPL/pgSQLisaccessiblethroughasetoflocalvariables.Thelocalvariables,OLDandNEW,representtherowinwhichthetriggerisinbeforeandaftertriggeringtheevent.Additionally,thereareseveralotherlocalvariablesthatstartwiththeprefixTG_,suchasTG_WHENorTG_TABLE_NAMEforgeneralcontext.Onceyourtriggerfunctionisdefined,youcanbindittoaspecificsetofactionsonatable.
![Page 194: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/194.jpg)
CreatingthetriggerThesimplifiedsyntaxtocreateauser-definedTRIGGERstatementisgivenasfollows:
CREATETRIGGERname
{BEFORE|AFTER|INSTEADOF}{event[OR…]}
ONtable_name
[FOR[EACH]{ROW|STATEMENT}]
EXECUTEPROCEDUREfunction_name(arguments)
Intheprecedingcode,theeventiseitherINSERT,UPDATE,DELETE,orTRUNCATE.Thereareafewmoreoptionswhichwewillcomebacktoinalatersection.
Theargumentsvariableseeminglypassedtothetriggerfunctioninthetriggerdefinitionarenotusedasargumentswhencallingthetrigger.Instead,theyareavailabletothetriggerfunctionasatextarray(text[])intheTG_ARGVvariable(thelengthofthisarrayisinTG_NARGS).Let’sslowlystartinvestigatinghowtriggersandtriggerfunctionswork.
StartingfromPostgreSQL9.3,thereissupportforDDLtriggers.WewilllearnmoreaboutDDLtriggers,alsocalledeventtriggers,inthenextchapter.
First,wewilluseasimpletriggerexampleandmoveontomorecomplexexamplesstepbystep.
![Page 195: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/195.jpg)
![Page 196: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/196.jpg)
Workingonasimple“Hey,I’mcalled”triggerThefirsttriggerwewillworkonsimplysendsanoticebacktothedatabaseclienteachtimethetriggerisfiredandprovidessomefeedbackonitsfiringconditions:
CREATEORREPLACEFUNCTIONnotify_trigger()
RETURNSTRIGGERAS$$
BEGIN
RAISENOTICE'Hi,Igot%invokedFOR%%%on%',
TG_NAME,
TG_LEVEL,
TG_WHEN,
TG_OP,
TG_TABLE_NAME;
END;
$$LANGUAGEplpgsql;
Next,weneedatabletobindthisfunctiontothefollowinglineofcode:
CREATETABLEnotify_test(iint);
Nowwearereadytodefinethetrigger.Asthisisasimpleexample,wedefineatriggerwhichisinvokedonINSERTandcallsthefunctiononceoneachrow:
CREATETRIGGERnotify_insert_trigger
AFTERINSERTONnotify_test
FOREACHROW
EXECUTEPROCEDUREnotify_trigger();
Let’stestthisout:
postgres=#INSERTINTOnotify_testVALUES(1),(2);
NOTICE:Hi,Igotnotify_insert_triggerinvokedFORROWAFTERINSERTon
notify_test
ERROR:controlreachedendoftriggerprocedurewithoutRETURN
CONTEXT:PL/pgSQLfunctionnotify_trigger()
Hmm,itseemsweneedtoreturnsomethingfromthefunctioneventhoughitisnotneededforourpurposes.ThefunctiondefinitionsaysCREATEFUNCTION…RETURNSbutwedefinitelycannotreturnatriggerfromafunction.
Let’sgetbacktothedocumentation.OK,hereitis.ThetriggerneedstoreturnavalueoftheROWorRECORDtypeanditisignoredintheAFTERtriggers.
Fornow,let’sjustreturnNEWasthisistherighttypeandisalwayspresenteventhoughitwillbeNULLintheDELETEtrigger:
CREATEORREPLACEFUNCTIONnotify_trigger()
RETURNSTRIGGERAS$$
BEGIN
RAISENOTICE'Hi,Igot%invokedFOR%%%on%',
TG_NAME,
![Page 197: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/197.jpg)
TG_LEVEL,TG_WHEN,TG_OP,TG_TABLE_NAME;
RETURNNEW;
END;
$$LANGUAGEplpgsql;
WecanuseRETURNNULLaswellhere,asthereturnvalueoftheAFTERtriggerisignoredanyway:
postgres=#INSERTINTOnotify_testVALUES(1),(2);
NOTICE:Hi,Igotnotify_insert_triggerinvokedFORROWAFTERINSERTon
notify_test
NOTICE:Hi,Igotnotify_insert_triggerinvokedFORROWAFTERINSERTon
notify_test
INSERT02
Asyousaw,thetriggerfunctionisindeedcalledonceforeachrowthatisinserted,solet’susethesamefunctiontoalsoreporttheUPDATEandDELETEfunctions:
CREATETRIGGERnotify_update_trigger
AFTERUPDATEONnotify_test
FOREACHROW
EXECUTEPROCEDUREnotify_trigger();
CREATETRIGGERnotify_delete_trigger
AFTERDELETEONnotify_test
FOREACHROW
EXECUTEPROCEDUREnotify_trigger();
Checkwhethertheprecedingcodeworks.
First,let’stesttheUPDATEtrigger:
postgres=#updatenotify_testseti=i*10;
NOTICE:Hi,Igotnotify_update_triggerinvokedFORROWAFTERUPDATEon
notify_test
NOTICE:Hi,Igotnotify_update_triggerinvokedFORROWAFTERUPDATEon
notify_test
UPDATE2
Thisworksfine—wegetanoticefortwoinvocationsofourtriggerfunction.
Now,let’stesttheDELETEtrigger:
postgres=#deletefromnotify_test;
NOTICE:Hi,Igotnotify_delete_triggerinvokedFORROWAFTERDELETEon
notify_test
NOTICE:Hi,Igotnotify_delete_triggerinvokedFORROWAFTERDELETEon
notify_test
DELETE2
Ifyouonlywanttobenotifiedeachtimeanoperationisperformedonthetable,theprecedingcodeisenough.Onesmallimprovementcanbemadeinhowwedefinetriggers.InsteadofcreatingonetriggerforeachoftheINSERT,UPDATE,orDELETEfunctions,wecancreateasingletriggertobecalledforanyofthem.So,let’sreplacethepreviousthreetriggerswithjustthefollowing:
CREATETRIGGERnotify_trigger
![Page 198: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/198.jpg)
AFTERINSERTORUPDATEORDELETE
ONnotify_test
FOREACHROW
EXECUTEPROCEDUREnotify_trigger();
TheabilitytoputmorethanoneoftheINSERT,UPDATE,orDELETEfunctionsinthesametriggerdefinitionisaPostgreSQLextensiontotheSQLstandard.Sincetheactionpartofthetriggerdefinitionisnonstandardanyway,especiallywhenusingaPL/pgSQLtriggerfunction,thisshouldnotbeaproblem.
Let’snowdroptheindividualtriggers,truncatethetable,andtestagain:
postgres=#DROPTRIGGERnotify_insert_triggerONnotify_test;
DROPTRIGGER
postgres=#DROPTRIGGERnotify_update_triggerONnotify_test;
DROPTRIGGER
postgres=#DROPTRIGGERnotify_delete_triggerONnotify_test;
DROPTRIGGER
postgres=#TRUNCATEnotify_test;
TRUNCATETABLE
postgres=#INSERTINTOnotify_testVALUES(1);
NOTICE:Hi,Igotnotify_triggerinvokedFORROWAFTERINSERTon
notify_test
INSERT01
Thisworksfinebutitrevealsoneweakness:wedidnotgetanynotificationonTRUNCATE.
Unfortunately,wecannotsimplyaddORTRUNCATEintheprecedingtriggerdefinition.TheTRUNCATEcommanddoesnotactonsinglerows,sotheFOREACHROWtriggersmakenosensefortruncatingandarenotsupported.
YouneedtohaveaseparatetriggerdefinitionforTRUNCATE.Fortunately,wecanstillusethesamefunction,atleastforthissimple“Hey,I’mcalled”trigger:
CREATETRIGGERnotify_truncate_trigger
AFTERTRUNCATEONnotify_test
FOREACHSTATEMENT
EXECUTEPROCEDUREnotify_trigger();
NowwegetanotificationonTRUNCATEaswell,asshownhere:
postgres=#TRUNCATEnotify_test;
NOTICE:Hi,Igotnotify_truncate_triggerinvokedFORSTATEMENTAFTER
TRUNCATEonnotify_test
TRUNCATETABLE
WhileitmayseemcooltogetthesemessagesineachDataManipulationLanguage(DML)operation,ithaslittleproductionvalue.
So,let’sdevelopthisabitfurtherandlogtheeventinanauditlogtableinsteadofsendingsomethingbacktotheuser.
![Page 199: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/199.jpg)
![Page 200: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/200.jpg)
TheaudittriggerOneofthemostcommonusesoftriggersistologdatachangestotablesinaconsistentandtransparentmanner.Whencreatinganaudittrigger,wefirstmustdecidewhatwewanttolog.
Alogicalsetofthingsthatcanbeloggedarewhochangedthedata,whenthedatawaschanged,andwhichoperationchangedthedata.Thisinformationcanbesavedinthefollowingtable:
CREATETABLEaudit_log(
usernametext,—whodidthechange
event_time_utctimestamp,—whentheeventwasrecorded
table_nametext,—containsschema-qualifiedtablename
operationtext,—INSERT,UPDATE,DELETEorTRUNCATE
before_valuejson,—theOLDtuplevalue
after_valuejson—theNEWtuplevalue
);
Here’ssomeadditionalinformationonwhatwewilllog:
TheusernamewillgettheSESSION_USERvariable,soweknowwhowasloggedinandnotwhichrolehehadpotentiallyassumedusingSETROLEevent_time_utcwillcontaintheeventtimeconvertedtoCoordinatedUniversalTime(UTC)sothatallcomplexdatearithmeticcalculationsarounddaylightsavingchangetimescanbeavoidedtable_namewillbeintheschema.tableformatTheoperationwillbedirectlyfromTG_OP,althoughitcouldbejustthefirstcharacter(I/U/D/T),withoutthelossofanyinformationFinally,thebeforeandafterimagesofrowsarestoredasrowsconvertedtojson,whichisavailableasitsowndatatypestartinginPostgreSQLVersion9.2foreasyhuman-readablerepresentationoftherowvalues
Next,thetriggerfunction:
CREATEORREPLACEFUNCTIONaudit_trigger()
RETURNStriggerAS$$
DECLARE
old_rowjson:=NULL;
new_rowjson:=NULL;
BEGIN
IFTG_OPIN('UPDATE','DELETE')THEN
old_row=row_to_json(OLD);
ENDIF;
IFTG_OPIN('INSERT','UPDATE')THEN
new_row=row_to_json(NEW);
ENDIF;
INSERTINTOaudit_log(
username,
event_time_utc,
table_name,
operation,
![Page 201: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/201.jpg)
before_value,
after_value
)VALUES(
session_user,
current_timestampATTIMEZONE'UTC',
TG_TABLE_SCHEMA||'.'||TG_TABLE_NAME,
TG_OP,
old_row,
new_row
);
RETURNNEW;
END;
$$LANGUAGEplpgsql;
NoteTheconditionalexpressionsthatchecktheoperationsatthebeginningofthefunctionareneededtoovercomethefactthatNEWandOLDarenotNULLfortheDELETEandINSERTtriggerscorrespondingly.Rather,theyareunassigned.UsinganunassignedvariableinanyotherwayexceptassigningtoitinPL/pgSQLresultsinanerror.Anyerrorinthetriggerwillusuallyabortthetriggerandthecurrenttransaction.
Wearenowreadytodefineournewloggingtrigger,asshownhere:
CREATETRIGGERaudit_log
AFTERINSERTORUPDATEORDELETE
ONnotify_test
FOREACHROW
EXECUTEPROCEDUREaudit_trigger();
Let’srunasmalltest:weremoveouroriginalnotifytriggersfromthenotify_testtableandperformafewsimpleoperations:
postgres=#DROPTRIGGERnotify_triggerONnotify_test;
DROPTRIGGER
postgres=#DROPTRIGGERnotify_truncate_triggerONnotify_test;
DROPTRIGGER
postgres=#TRUNCATEnotify_test;
TRUNCATETABLE
postgres=#INSERTINTOnotify_testVALUES(1);
INSERT01
postgres=#UPDATEnotify_testSETi=2;
UPDATE1
postgres=#DELETEFROMnotify_test;
DELETE1
postgres=#SELECT*FROMaudit_log;
-[RECORD1]--+---------------------------
username|postgres
event_time_utc|2013-04-1413:14:18.501529
table_name|public.notify_test
operation|INSERT
before_value|
after_value|{"i":1}
-[RECORD2]--+---------------------------
username|postgres
event_time_utc|2013-04-1413:14:18.51216
![Page 202: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/202.jpg)
table_name|public.notify_test
operation|UPDATE
before_value|{"i":1}
after_value|{"i":2}
-[RECORD3]--+---------------------------
username|postgres
event_time_utc|2013-04-1413:14:18.52331
table_name|public.notify_test
operation|DELETE
before_value|{"i":2}
after_value|
Thisworkswell.Dependingonyourneeds,thisfunctionwilllikelyneedsometweaking.EnoughofjustwatchingandrecordingDML,itistimetostartinfluencingwhatgoesinthere.
NoteTriggersarecalledinalphabeticalorder,andthelattertriggerscanchangewhatgetsinserted,socautionneedstobeappliedwhennamingtriggers,particularlywhenauditing.
![Page 203: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/203.jpg)
![Page 204: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/204.jpg)
DisallowingDELETEWhatifourbusinessrequirementsaresuchthatthedatacanonlybeaddedandmodifiedinsometables,butnotdeleted?
OnewaytohandlethiswillbetojustrevoketheDELETErightsonthesetablesfromalltheusers(remembertoalsorevokeDELETEfromPUBLIC),butthiscanalsobeachievedusingtriggersbecauseofreasonssuchasauditingorreturningcustomexceptionmessages.
Agenericcanceltriggercanbewrittenasfollows:
CREATEORREPLACEFUNCTIONcancel_op()
RETURNSTRIGGERAS$$
BEGIN
IFTG_WHEN='AFTER'THEN
RAISEEXCEPTION'YOUARENOTALLOWEDTO%ROWSIN%.%',
TG_OP,TG_TABLE_SCHEMA,TG_TABLE_NAMENAME;
ENDIF;
RAISENOTICE'%ONROWSIN%.%WON'THAPPEN',
TG_OP,TG_TABLE_SCHEMA,TG_TABLE_NAMENAME;
RETURNNULL;
END;
$$LANGUAGEplpgsql;
ThesametriggerfunctioncanbeusedforboththeBEFOREandAFTERtriggers.IfyouuseitasaBEFOREtrigger,theoperationisskippedwithamessage.However,ifyouuseitasanAFTERtrigger,anERRORtriggerisraisedandthecurrent(sub)transactionisrolledback.
Itwillalsobeeasytoaddalogofthedeletedattemptsintoatableinthissametriggerfunctioninordertohelpenforcethecompanypolicy—justaddINSERTtoalogtablethatissimilartothetableinthepreviousexample.
Ofcourse,youcanmakeoneorboththemessagesmoremenacingifyouwant,byaddingsomethingsuchas”Authoritieswillbenotified!”or”Youwillbeterminated!”.
Let’stakealookathowthisworksinthefollowingcode:
postgres=#CREATETABLEdelete_test1(iint);
CREATETABLE
postgres=#INSERTINTOdelete_test1VALUES(1);
INSERT01
postgres=#CREATETRIGGERdisallow_deleteAFTERDELETEONdelete_test1FOR
EACHROWEXECUTEPROCEDUREcancel_op();
CREATETRIGGER
postgres=#DELETEFROMdelete_test1WHEREi=1;
ERROR:YOUARENOTALLOWEDTODELETEROWSINpublic.delete_test1
NoticethattheAFTERtriggerraisedanerror:
postgres=#CREATETRIGGERskip_deleteBEFOREDELETEONdelete_test1FOR
EACHROWEXECUTEPROCEDUREcancel_op();
CREATETRIGGER
![Page 205: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/205.jpg)
postgres=#DELETEFROMdelete_test1WHEREi=1;
NOTICE:DELETEONROWSINpublic.delete_test1WON'THAPPEN
DELETE0
Thistime,theBEFOREtriggercanceledthedeleteandtheAFTERtrigger,althoughstillthere,wasnotreached.
NoteThesametriggercanalsobeusedtoenforceano-updatepolicyorevendisallowinsertstoatablethatneedstohaveimmutablecontents.
![Page 206: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/206.jpg)
![Page 207: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/207.jpg)
DisallowingTRUNCATEYoumayhavenoticedthattheprecedingtriggercaneasilybebypassedforDELETEifyoudeleteeverythingusingTRUNCATE.
WhileyoucannotsimplyskipTRUNCATEbyreturningNULLasopposedtotherow-levelBEFOREtriggers,youcanstillmakeitimpossiblebyraisinganerrorifTRUNCATEisattempted.CreateanAFTERtriggerusingthesamefunctionastheoneusedpreviouslyforDELETE:
CREATETRIGGERdisallow_truncate
AFTERTRUNCATEONdelete_test1
FOREACHSTATEMENT
EXECUTEPROCEDUREcancel_op();
Hereyouare,withoutTRUNCATE:
postgres=#TRUNCATEdelete_test1;
ERROR:YOUARENOTALLOWEDTOTRUNCATEROWSINpublic.delete_test1
Ofcourse,youcanalsoraisetheerrorinaBEFOREtrigger,butinthatcaseyouwillneedtowriteyourownunconditionalraise-errortriggerfunctioninsteadofcancel_op().
![Page 208: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/208.jpg)
![Page 209: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/209.jpg)
ModifyingtheNEWrecordAnotherformofauditingthatisfrequentlyusedistologinformationinfieldsinthesamerowasthedata.Asanexample,let’sdefineatriggerthatlogsthetimeandtheactiveuserinthelast_changed_atandlast_changed_byfieldsateachINSERTandUPDATEtrigger.Intherow-levelBEFOREtriggers,youcanmodifywhatactuallygetswrittenbychangingtheNEWrecord.Youcaneitherassignvaluestosomefieldsorevenreturnadifferentrecordwiththesamestructure.Forexample,ifyoureturnOLDfromtheUPDATEtrigger,youeffectivelymakesurethattherowcan’tbeupdated.
![Page 210: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/210.jpg)
ThetimestampingtriggerToformthebasisofourauditlogginginthetable,westartbycreatingatriggerthatsetstheuserwhomadethelastchangeandwhenthechangeoccurred:
CREATEORREPLACEFUNCTIONchangestamp()
RETURNSTRIGGERAS$$
BEGIN
NEW.last_changed_by=SESSION_USER;
NEW.last_changed_at=CURRENT_TIMESTAMP;
RETURNNEW;
END;
$$LANGUAGEplpgsql;
Ofcourse,thisworksonlyinatablethathasthecorrectfields:
CREATETABLEmodify_test(
idserialPRIMARYKEY,
datatext,
created_bytextdefaultSESSION_USER,
created_attimestamptzdefaultCURRENT_TIMESTAMP,
last_changed_bytextdefaultSESSION_USER,
last_changed_attimestamptzdefaultCURRENT_TIMESTAMP
);
CREATETRIGGERchangestamp
BEFOREUPDATEONmodify_test
FOREACHROW
EXECUTEPROCEDUREchangestamp();
Now,let’stakealookatournewlycreatedtrigger:
postgres=#INSERTINTOmodify_test(data)VALUES('something');
INSERT01
postgres=#UPDATEmodify_testSETdata='somethingelse'WHEREid=1;
UPDATE1
postgres=#SELECT*FROMmodify_test;
-[RECORD1]---+---------------------------
id|1
data|somethingelse
created_by|postgres
created_at|2013-04-1509:28:23.966179
last_changed_by|postgres
last_changed_at|2013-04-1509:28:31.937196
![Page 211: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/211.jpg)
![Page 212: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/212.jpg)
TheimmutablefieldstriggerWhenyouaredependingonthefieldsintherowsaspartofyourauditrecord,youneedtoensurethatthevaluesreflectreality.Wewereabletomakesurethatthelast_changed_*fieldsalwayscontainthecorrectvalue,butwhataboutthecreated_byandcreated_atvalues?Thesecanbeeasilychangedinlaterupdates,buttheyshouldneverchange.Eveninitially,theycanbesettofalsevalues,sincethedefaultvaluescanbeeasilyoverriddenbygivinganyothervalueintheINSERTstatement.
So,let’smodifyourchangestamp()triggerfunctionintoausagestamp()function,whichmakessurethattheinitialvaluesarewhattheyshouldbeandthattheystaylikethat:
CREATEORREPLACEFUNCTIONusagestamp()
RETURNSTRIGGERAS$$
BEGIN
IFTG_OP='INSERT'THEN
NEW.created_by=SESSION_USER;
NEW.created_at=CURRENT_TIMESTAMP;
ELSE
NEW.created_by=OLD.created_by;
NEW.created_at=OLD.created_at;
ENDIF;
NEW.last_changed_by=SESSION_USER;
NEW.last_changed_at=CURRENT_TIMESTAMP;
RETURNNEW;
END;
$$LANGUAGEplpgsql;
IncaseofINSERT,wesetthecreated_*fieldstotherequiredvalues,regardlessofwhattheINSERTquerytriestosetthemto.IncaseofUPDATE,wejustcarryovertheoldvalues,againoverridinganyattemptedchanges.
ThisfunctionthenneedstobeusedinordertocreateaBEFOREINSERTORUPDATEtrigger:
CREATETRIGGERusagestamp
BEFOREINSERTORUPDATEONmodify_test
FOREACHROW
EXECUTEPROCEDUREusagestamp();
Now,let’strytoupdatethecreatedauditloginformation.First,wewillneedtodroptheoriginaltriggersothatwedon’thavetwotriggersfiringonthesametable.Then,wewilltrytochangethevaluesofcreated_byandcreated_at:
postgres=#DROPTRIGGERchangestampONmodify_test;
DROPTRIGGER
postgres=#UPDATEmodify_testSETcreated_by='notpostgres',created_at=
'2000-01-01';
UPDATE1
postgres=#select*frommodify_test;
-[RECORD1]---+---------------------------
id|1
![Page 213: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/213.jpg)
data|somethingelse
created_by|postgres
created_at|2013-04-1509:28:23.966179
last_changed_by|postgres
last_changed_at|2013-04-1509:33:25.386006
Fromtheresults,youcanseethatthecreatedinformationisstillthesame,butthelastchangedinformationhasbeenupdated.
![Page 214: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/214.jpg)
![Page 215: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/215.jpg)
ControllingwhenatriggeriscalledWhileitisrelativelyeasytoperformtriggeractionsconditionallyinsidethePL/pgSQLtriggerfunction,itisoftenmoreefficienttoskipinvokingthetriggeraltogether.Theperformanceeffectsoffiringatriggerarenotgenerallynoticedwhenonlyafeweventsarefired.However,ifyouarebulkloadingdataorupdatinglargeportionsofyourtable,thecumulativeeffectscancertainlybefelt.Toavoidtheoverhead,it’sbesttocallthetriggerfunctiononlywhenitisactuallyneeded.
TherearetwowaystonarrowdownwhenatriggerwillbecalledintheCREATETRIGGERcommanditself.
So,usethesamesyntaxoncemorebutwithalltheoptionsthistime:
CREATETRIGGERname
{BEFORE|AFTER|INSTEADOF}{event[ORevent…]}
[OFcolumn_name[ORcolumn_name…]]ONtable_name
[FOR[EACH]{ROW|STATEMENT}]
[WHEN(condition)]
EXECUTEPROCEDUREfunction_name(arguments)
YoucanusetheWHENclausetoonlyfireatriggerbasedonacondition(suchasacertaintimeoftheday)oronlywhencertainfieldsareupdated.Wewillnowtakealookatacoupleofexamples.
![Page 216: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/216.jpg)
ConditionaltriggersAflexiblewaytocontroltriggersistouseagenericWHENclausethatissimilartoWHEREinSQLqueries.WithaWHENclause,youcanwriteanyexpression,exceptasubquery,thatistestedbeforethetriggerfunctioniscalled.TheexpressionmustresultinaBooleanvalue,andifthevalueisFALSE(orNULL,whichisautomaticallyconvertedtoFALSE),thetriggerfunctionisnotcalled.
Forexample,youcanusethistoenforcea“NoupdatesonFridayafternoon”policy:
CREATEORREPLACEFUNCTIONcancel_with_message()
RETURNSTRIGGERAS$$
BEGIN
RAISEEXCEPTION'%',TG_ARGV[0];
RETURNNULL;
END;
$$LANGUAGEplpgsql;
ThiscodejustraisesanexceptionwiththestringpassedasanargumentintheCREATETRIGGERstatement.NoticethatwecannotuseTG_ARGV[0]directlyasthemessagebecausethePL/pgSQLsyntaxrequiresastringconstantasthethirdelementofRAISE.
Usingtheprevioustriggerfunction,youcansetuptriggersinordertoenforcevariousconstraintsbyspecifyingboththecondition(intheWHEN(...)clause)andthemessagetoberaisedifthisconditionismetastheargumenttothetriggerfunction:
CREATETABLEnew_tasks(idSERIALPRIMARYKEY,sampleTEXT);
CREATETRIGGERno_updates_on_friday_afternoon
BEFOREINSERTORUPDATEORDELETEORTRUNCATEONnew_tasks
FOREACHSTATEMENT
WHEN(CURRENT_TIME>'12:00'ANDextract(DOWfromCURRENT_TIMESTAMP)=5)
EXECUTEPROCEDUREcancel_with_message('Sorry,wehavea"Notaskchangeon
Fridayafternoon"policy!');
Now,ifanybodytriestomodifythenew_taskstableonaFridayafternoon,theygetamessageaboutthispolicy,asshownhere:
postgres=#insertintonew_tasks(sample)values("test");
ERROR:Sorry,wehavea"NotaskchangeonFridayafternoon"policy!
NoteOnethingtonoteabouttriggerargumentsisthattheargumentlistisalwaysanarrayoftext(text[]).
AlloftheargumentsgivenintheCREATETRIGGERstatementareconvertedtostrings,andthisincludesanyNULLvalues.
ThismeansthatputtingNULLintheargumentlistresultsinthetextNULLinthecorrespondingslotinTG_ARGV.
![Page 217: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/217.jpg)
TriggersonspecificfieldchangesAnotherwaytocontrolwhenatriggerisfiredisusingalistofcolumns.IntheUPDATEtriggers,youcanspecifyoneormorecomma-separatedcolumnstotellPostgreSQLthatthetriggerfunctionshouldonlybeexecutedifanyofthelistedcolumnschange.
ItispossibletoconstructthesameconditionalexpressionwithaWHENclause,butthelistofcolumnshascleanersyntax:
WHEN(
NEW.column1ISDISTINCTFROMOLD.column1
OR
NEW.column2ISDISTINCTFROMOLD.column2)
Acommonexampleofhowthisconditionalexpressionisusedisraisinganerroreachtimesomeonetriestochangeaprimarykeycolumn.TheISDISTINCTFROMfunctionmakessurethatthetriggerisonlyexecutedwhenthenewvalueofcolumn1isdifferentfromtheoldvalue.ThiscanbeeasilydonebydeclaringanAFTERtriggerusingthecancel_op()triggerfunction(definedpreviouslyinthischapter),asfollows:
CREATETRIGGERdisallow_pk_change
AFTERUPDATEOFidONtable_with_pk_id
FOREACHROW
EXECUTEPROCEDUREcancel_op();
postgres=#INSERTINTOnew_tasksDEFAULTVALUES;
INSERT01
packt=#SELECT*FROMnew_tasks;
id|sample
----+--------
1|
(1row)
packt=#UPDATEnew_tasksSETid=0whereid=1;
ERROR:YOUARENOTALLOWEDTOUPDATEROWSINpublic.new_tasks
![Page 218: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/218.jpg)
![Page 219: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/219.jpg)
VisibilitySometimes,yourtriggerfunctionsmightrunintotheMultiversionConcurrencyControl(MVCC)visibilityrulesofhowPostgreSQL’ssysteminteractswithchangestodata.
AfunctiondeclaredasSTABLEorIMMUTABLEwillneverseechangesappliedtotheunderlyingtablebytheprevioustriggers.
AVOLATILEfunctionfollowsmorecomplexruleswhichare,inanutshell,asfollows:
Thestatement-levelBEFOREtriggersdetectswhethernochangesaremadebythecurrentstatement,andthestatement-levelAFTERtriggersdetectsallofthechangesmadebythestatement.Datachangesbytheoperationtotherowcausingthetriggertofireare,ofcourse,notvisibletotheBEFOREtriggers,astheoperationhasnotoccurredyet.Changesmadebyothertriggerstootherrowsinthesamestatementarevisible,andastheorderoftherowsprocessedisundefined,youneedtobecautious.StartingfromPostgreSQL9.3,anerroristhrownifatupletobeupdatedordeletedhasalreadybeenupdatedordeletedbyaBEFOREtrigger.ThesameistruefortheINSTEADOFtriggers.Thechangesmadebythetriggersfiredinthesamecommandinthepreviousrowsarevisibletothecurrentinvocationofthetriggerfunction.Row-levelAFTERtriggersarefiredwhenallofthechangestoalltherowsoftheoutercommandarecompleteandvisibletothetriggerfunction.
Alltheserulesapplytofunctionsthatquerydatainthedatabase;theOLDandNEWrowsare,ofcourse,visibleasdescribedpreviously.
NoteThesameinformationin,perhaps,differentwordsisavailableathttp://www.postgresql.org/docs/current/static/spi-visibility.html.
![Page 220: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/220.jpg)
Mostimportantly–usetriggerscautiously!Triggersareanappropriatetoolforuseindatabase-sideactions,suchasauditing,logging,enforcingcomplexconstraints,andevenreplication(severallogicalreplicationsystemssuchasSlonyarebasedontriggersusedinproduction).However,formostapplicationlogic,itismuchbettertoavoidtriggersastheycanleadtoreallyweirdandhard-to-debugproblems.Asagoodpractice,followtherulesprovidedinthefollowingtable:
Rule Description
Rule1 Donotchangedataintheprimarykey,foreignkey,oruniquekeycolumnsofanytable
Rule2 Donotupdaterecordsinthetablethatyoureadduringthesametransaction
Rule3 Donotaggregateoverthetableyouareupdating
Rule4 Donotreaddatafromatablethatisupdatedduringthesametransaction
![Page 221: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/221.jpg)
![Page 222: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/222.jpg)
VariablespassedtothePL/pgSQLTRIGGERfunctionThefollowingisacompletelistofthevariablesavailabletoatriggerfunctionwritteninPL/pgSQL:
OLD,NEW RECORD
Thisrecordsthebeforeandafterimagesoftherowonwhichthetriggeriscalled.OLDisunassignedforINSERTandNEWisunassignedforDELETE.
BothareUNASSIGNEDinstatement-leveltriggers.
TG_NAME name Thisdenotesthenameofthetrigger(thisandfollowingfromthetriggerdefinition).
TG_WHEN text BEFORE,AFTER,orINSTEADOFarethepossiblevaluesofthevariable.
TG_LEVEL text ROWorSTATEMENTarethepossiblevaluesofthevariable.
TG_OP text INSERT,UPDATE,DELETE,orTRUNCATEarethepossiblevaluesofthevariable..
TG_RELID oid ThisdenotestheOIDofthetableonwhichthetriggeriscreated.
TG_TABLE_NAME nameThisdenotesthenameofthetable(theoldspellingTG_RELNAMEisdeprecatedbutstillavailable).
TG_TABLE_SCHEMA name Thisdenotestheschemanameofthetable.
TG_NARGS,TG_ARGV[]
Int,text[]
Thisdenotesthenumberofargumentsandthearrayoftheargumentsfromthetriggerdefinition.
TG_TAG textThisisusedinDDLoreventtriggers.Thisvariablecontainsthenameofthecommandthatresultedinthetriggerinvocation.Moreinformationonthisinthenextchapter.
Youcanreadmoreaboutthevariablesathttp://www.postgresql.org/docs/current/static/plpgsql-trigger.html.
![Page 223: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/223.jpg)
![Page 224: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/224.jpg)
SummaryAtriggerisabindingofasetofactionstocertainoperationsperformedonatableorview.Thissetofactionsisdefinedinaspecialtriggerfunctionwhichisdistinguishedbyspecifyingthetypeofthereturnedvaluetobeofaspecialpseudotypetrigger.So,eachtimeanoperation(INSERT,UPDATE,DELETE,orTRUNCATE)isperformedonthetable,thistriggerfunctioniscalledbythesystem.
Itcanbeexecutedeitherforeachroworforeachstatement.Ifexecutedforeachrow(row-leveltrigger),thefunctionispassedspecialvariablessuchasOLDandNEW.
Thiswillcontaintherow’scontents,asitiscurrentlyinthedatabase(OLD)andasitisthemomentthetriggerfunctioniscalled(NEW).WheretheOLDorNEWvalueismissing,itispassedasundefined.Ifexecutedonceperstatement(thestatement-leveltrigger),bothOLDandNEWareunassignedforalltheoperations.
Thetriggerfunctionforrow-leveltriggersonINSERT,UPDATE,andDELETEcanbesettoexecuteeitherBEFOREorAFTERtheoperationonatableandcanbesettoexecutetheINSTEADOFoperationonview.
Thetriggerfunctionforstatement-leveltriggersonINSERT,UPDATE,andDELETEcanbesettoexecuteeitherBEFOREorAFTERtheoperationonbothtablesandviews.
WhileTRUNCATEislogicallyaspecial,non-MVCCformofa“deleteall”statement,noONDELETEtriggerswillfireinthecaseofTRUNCATE.Instead,youcanuseaspecialONTRUNCATEtriggeronthesametable.Onlystatement-levelonTRUNCATEtriggersarepossible.WhileyoucannotskipstatementtriggersbyreturningNULL,youcanraiseanexceptionandabortthetransaction.
ItisalsonotpossibletodefineanyONTRUNCATEtriggersonviews.
Inthenextchapter,wewilltakealookatthenewPostgreSQLeventtriggerfeature.EventtriggersallowyoutoexecutetriggerswhenaDataDefinitionLanguage(DDL)statementisexecutedonatable.
![Page 225: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/225.jpg)
![Page 226: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/226.jpg)
Chapter6.PostgreSQLEventTriggersPostgreSQL9.3introducedaspecialtypeoftriggerstocomplementthetriggermechanismwediscussedintheprecedingchapter.Thesetriggers,aredatabase-specificandarenotattachedtoaspecifictable.Unlikeregulartriggers,eventtriggerscaptureDDLevents.EventtriggerscanbetheBEFOREandAFTERtriggers,andthetriggerfunctioncanbewritteninanylanguageexceptSQL.OtherpopulardatabasevendorssuchasOracleandSQLServeralsoprovideasimilarfunctionality.
OnecanthinkofseveralusecasesforDDLtriggers.ThemostpopularoneamongtheDBAsnormallyistodoanaudittrail.You,asaDBA,mightwanttoaudittheusersandtheDDLcommands.Schemachanges,inaproductionenvironment,shouldbedoneverycarefully;hence,theneedforanaudittrailisapparent.Eventtriggersaredisabledinthesingleusermodeandcanonlybecreatedbyasuperuser.
Inthischapter,wewillcoverthefollowingtopics:
UsecasesforeventtriggersAfullaudittrailexampleusingPL/pgsqlPreventingschemachangesusingeventtriggers
![Page 227: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/227.jpg)
UsecasesforcreatingeventtriggersInadditiontoanaudittrail,thefollowingcanbevalidusecasesforaneventtrigger:
ReplicatingDDLchangestoaremotelocationCascadingaDDLPreventingchangestotables,exceptduringapredefinedwindowProvidinglimitedDDLcapabilitytodevelopers/supportstaffusingsecuritydefinerfunctionsDisablingcertainDDLcommandsbasedonacriteriaPerformanceanalysistoseehowlongacommandtakesbetweenddl_command_startandddl_command_end
NotethattheeventtriggersupportforPL/pgsqlisnotyetcompletein9.3.ThereareseveralfeaturesthatarebeingworkeduponandwillbeavailableinfuturePostgreSQLversions,hopefully.Theseareafewofthemostnotablefeaturesthataremissingsofar:
There’snoinformationabouttheobjectthataDDLtargetsThere’snoaccesstothecommandstringThere’snosupportforthegeneratedcommands
AcommandsuchasCREATETABLEfoo(idserialPRIMARYKEY)willalsoresultintheCREATESEQUENCEandCREATEINDEXcommandstobeexecutedinternally.However,thecurrentDDLtriggerswillnotbeabletologthesegeneratedcommands.
![Page 228: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/228.jpg)
![Page 229: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/229.jpg)
CreatingeventtriggersEventtriggersarecreatedusingtheCREATEEVENTTRIGGERcommand.Beforeyoucancreateaneventtrigger,youneedafunctionthatthetriggerwillexecute.ThisfunctionmustreturnaspecialtypecalledEVENT_TRIGGER.Ifyouhappentodefinemultipleeventtriggers,theyareexecutedinthealphabeticalorderoftheirnames.
Currently,eventtriggersaresupportedonthreeevents,asfollows:
ddl_command_start:ThiseventoccursjustbeforeaCREATE,ALTER,orDROPDDLcommandisexecutedddl_command_end:ThiseventoccursjustafteraCREATE,ALTER,orDROPcommandhasfinishedexecutingsql_drop:Thiseventoccursjustbeforetheddl_command_endeventforthecommandsthatdropdatabaseobjects
YoucanspecifyaWHENclausewiththeCREATEEVENTTRIGGERcommand,sothattheeventisfiredonlyforthespecifiedcommands.
TheeventtriggerPL/pgSQLfunctionshaveaccesstothefollowingnewvariablesintroducedin9.3:
TG_TAG:Thisvariablecontainsthe“tag”orthecommandforwhichthetriggerisexecuted.Thisvariabledoesnotcontainthefullcommandstring,butjustatagsuchasCREATETABLE,DROPTABLE,ALTERTABLE,andsoon.TG_EVENT:Thisvariablecontainstheeventname,whichcanbeddl_command_start,ddl_comman_end,andsql_drop.
NoteAcompletematrixoftheeventtriggerfiringmechanismcanbefoundinthePostgreSQLdocumentationathttp://www.postgresql.org/docs/current/static/event-trigger-matrix.html.
![Page 230: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/230.jpg)
![Page 231: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/231.jpg)
CreatinganaudittrailLet’snowtakealookatthecompleteexampleofaneventtriggerthatcreatesanaudittrailofsomeDDLcommandsinthedatabase:
CREATETABLEtrack_ddl
(
eventtext,
commandtext,
ddl_timetimestamptz,
usrtext
);
CREATEORREPLACEFUNCTIONtrack_ddl_function()
RETURNSevent_trigger
AS
$$
BEGIN
INSERTINTOtrack_ddlvalues(tg_tag,tg_event,now(),session_user);
RAISENOTICE'DDLlogged';
END
$$LANGUAGEplpgsqlSECURITYDEFINER;
CREATEEVENTTRIGGERtrack_ddl_eventONddl_command_start
WHENTAGIN('CREATETABLE','DROPTABLE','ALTERTABLE')
EXECUTEPROCEDUREtrack_ddl_function();
CREATETABLEevent_check(iint);
SELECT*FROMtrack_ddl;
-[RECORD1]------------------------
event|CREATETABLE
command|ddl_command_start
ddl_time|2014-04-1316:58:40.331385
usr|testusr
Theexampleisactuallyquitesimple.Here’swhatwehavedoneintheexample:
1. First,wecreatedatablewherewestoretheauditlog.Thetableisquitesimpleatthemoment,duetoalimitedamountofinformationthatiscurrentlyavailabletoaPL/pgSQLfunction.Westorethetag,theevent,thetimestampwhenthistriggerisexecuted,andtheuserwhoexecutedthecommand.
2. Wethencreateafunctionthatisexecutedbythetriggerwheneveritisfired.Thefunctionissimpleenoughfornow.ItmustreturnthetypeEVENT_TRIGGER.ItlogstheDDLinformationintheaudittrailtable.ThefunctioncreatedisSECURITYDEFINER.Thereasonwhythisisdoneisbecauseotherusersinthedatabasedon’thaveanyprivilegesontheaudittrailtableandwedon’tactuallywantthemtoknowitisthere.Thisfunctionisexecutedasthedefiner(whichisasuperuser),andtheuseofsession_userensuresthatwelogtheuserwhologgedintothedatabase,andnottheonewhoseprivilegesareusedtoexecutethefunction.
3. Wethencreateaneventtriggerthatonlyexecuteswhencertaincommandssuchas
![Page 232: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/232.jpg)
CREATE,DROP,orALTERTABLEareexecutedbyauser.
Wethencreateanexampletableandnotethatthecommandisindeedloggedintheaudittrailtable.
![Page 233: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/233.jpg)
![Page 234: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/234.jpg)
PreventingschemachangesAnothercommonusecaseforeventtriggersistopreventtheexecutionofcertaincommandsbasedonaspecificcondition.Ifyouonlywanttostopusersfromexecutingsomecommands,youcanalwaysrevoketheprivilegesusingmoreconventionalmeans.Thetriggersmaycomeinhandyifyouwanttodothisbasedonacertaincondition,let’ssay,timeoftheday:
CREATEORREPLACEFUNCTIONabort_create_table_func()
RETURNSevent_trigger
AS
$$
DECLARE
current_hourint:=extract(hourfromnow());
BEGIN
ifcurrent_hourBETWEEN9AND16
then
RAISEEXCEPTION'Notasuitabletimetocreatetables';
endif;
END;
$$LANGUAGEplpgsqlSECURITYDEFINER;
CREATEEVENTTRIGGERabort_create_tableONddl_command_start
WHENTAGIN('CREATETABLE')
EXECUTEPROCEDUREabort_create_table_func();
Theprecedingcodeis,again,quitesimple:
1. First,wecreateatriggerfunctionthatpreventsachangeifthecurrenthourofthedayisbetween9to16.
2. WecreateatriggerthatexecutesthisfunctiononlywhenaCREATETABLEcommandisexecuted.
Youcanextendthisexampletoincludemorecomplexconditionsandalsobasethedecisiononthecurrentstateofthedatabase.ThiskindofflexibilityisnotavailablewhenyouusesimpleprivilegemanagementbasedonGRANTandREVOKE.
![Page 235: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/235.jpg)
![Page 236: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/236.jpg)
AroadmapofeventtriggersAsyoucansee,thecurrentimplementationofeventtriggersinPL/pgsqlandPostgreSQL9.4isratherlimited.However,therearemorechangesandfeaturesplannedfortheupcomingreleasesthatwillexpandthescope,inwhicheventtriggerswillbecomemoreuseful.Herearethehighlightsofwhatwecanlookforwardtointhefuture:
Accesstomoreinformation:MoreTG_*variablesaregoingtobeavailable,inordertoprovidemoreinformationaboutthecommandthatisrunningandonwhichobjectitisrunning.WecanlookforwardtothefollowingvariablesinfuturePostgreSQLversions:
TG_OBJECTID
TG_OBJECTNAME
TG_SCHEMANAME
TG_OPERATION
TG_OBTYPENAME
TG_CONTEXT
Accessors:Thesearejustfunctionswhichgiveyousomeinformation.Inthiscasethepg_get_event_command_stringfunctionwillgivethefullcommandstringoftheDDLcommandthatcausedtheeventtriggertofire.
pg_get_event_command_string()
SupportofDROPCASCADE:Here,eventtriggerswillbefiredforeachobjecteffectedinaDROPCASCADEcall.INSTEADOF:Theideahere,isforaneventtriggertotakecontrolofacommand,analogoustotheINSTEADOFDMLtriggers.CREATETABLEonINSERT:Theideahere,istojustcreateanewtablewheneverwereceiveaninsertforthefirsttimeandthetabledoesn’texist.
NoteIfyouwanttolearnmoreaboutthefeaturesinprogressandthepatches,whicharebeingdiscussedrelatedtoeventtriggersupportinPostgreSQL,pleasefollowthewikipageathttps://wiki.postgresql.org/wiki/Event_Triggers.
![Page 237: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/237.jpg)
![Page 238: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/238.jpg)
SummaryEventtriggersarenewinPostgreSQL9.3,andthecommunityisstillworkingonvariousfeaturesinordertomakethemmoreuseful.Youcanusethesetriggersforvariouspurposes,includingauditingDDLcommandsandmakinglocalcustomizedpoliciesregardingtheexecutionofDDLcommandsinthedatabase.Eventtriggersaredisabledinsingleusermode.
EventtriggersarecreatedusingtheCREATEEVENTTRIGGERcommand,andtheyexecuteafunctionthatreturnsaspecialtypecalledEVENT_TRIGGER.Therearethreetypesofeventsthatarecurrentlysupported:ddl_command_start,ddl_command_end,andsql_drop.YoucanlimitatriggerexecutionbyatagusingaWHENclause,ifyouwanttofireitforspecificcommandsonly.
Currently,therearetwonewvariablesavailableintheeventtriggerfunctioncalledTG_TAGandTG_EVENTthatprovideinformationaboutthetagandtheeventofthetrigger.FuturereleasesofPostgreSQLwillexposemorevariablesthatmakeitpossibletoauditcompleteinformationaboutfiringDDL,includingobjectsandthecommandstring.
Inthenextchapter,wewilldiscussthedifferencesbetweenrestrictedandunrestrictedlanguagesandwewilltakealookatthepracticalexamplesofboth.
![Page 239: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/239.jpg)
![Page 240: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/240.jpg)
Chapter7.DebuggingPL/pgSQLThischapterisentirelyoptional.Sinceyouhaveonlyproducedthehighestqualitybug-freecodeusingthebestpossiblealgorithms,thistextisprobablyawasteofyourtime.Ofcourse,yourfunctionsparseperfectlyonthefirsttry.Yourviewsshowexactlywhattheyshould—accordingtotheenviouslycompletebusinessandtechnicaldocumentationthatyouwrotelastmonth.Thereisnoneedforversioncontrolonyourprocedures,astherehasonlyeverbeenaVersion1.
Sinceyouarestillreadingthis,I’msurethatyou’reawholelotmorelikeme.Ispendabout10percentofmytimewritingnewcodeandabout90percentofiteditingthemistakesandoversightsthatI(andothers)madeinthefirst10percent.Infact,itcanbearguedthatnonewcodeiseverwrittenatall.Actually,amoreaccuratedescriptionoftheprocessisthatadumbassertionismadeandthenitisediteduntilthecustomercannolongerstandtheQualityAssurance(QA)process.Wethenshiptheresultinthehopesofbeingusefultotheenduser.Wasthattoomuchofrealityforyou?Sorry.
Theobjectiveofthischapteristomakeyoufasteratmakingmistakes.Asaby-product,youwillalsolearnhowtodiagnoseandfixthematanalarmingrate.Theneteffectofthis,wearehoping,isthatyourbosswillassumeyouwroteitcorrectlythefirsttime.Thisis,ofcourse,aliebutaveryusefulone.
Thisconceptiscriticaltoagilesoftwaredevelopment.Inthisphilosophy,itiscalled“prototyping.”Theideaistocreateafeaturequicklyanddemonstrateitasaconversationpoint,ratherthantryingtoproduceanentiresystem(presumablyperfectly)fromconceptualdocumentation.Otherauthorsrefertoitas“failingquickly.”Itrecognizesthefactthatthefirstthreeorfourdevelopmentiterationswillprobablynotbeacceptabletothecustomerandshouldn’tbeadvertisedasfinaluntilsomediscussionhastakenplace.
Thisprocesseffectivelyrequiresthedeveloperto“live”inthedebugger.Thedevelopercontinuallychangestheoutputsandroutinesuntilthedesiredeffectisachieved.PostgreSQLhasawonderfulsetofdebuggingtoolsavailabletohelpyoufixyourmess.Letmeshowyouhowtheywork.
![Page 241: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/241.jpg)
ManualdebuggingwithRAISENOTICEHere’sthefirstpromisedexample:
CREATEORREPLACEFUNCTIONformat_us_full_name_debug(
prefixtext,
firstnametext,
mitext,
lastnametext,
suffixtext)
RETURNStextAS
$BODY$
DECLARE
fname_mitext;
fmi_lnametext;
prefix_fmiltext;
pfmil_suffixtext;
BEGIN
fname_mi:=CONCAT_WS('',CASEtrim(firstname)WHEN''THENNULLELSE
firstnameEND,CASEtrim(mi)WHEN''THENNULLELSEmiEND||'.');
RAISENOTICE'firstnamemi.:%',fname_mi;
fmi_lname:=CONCAT_WS('',CASEfname_miWHEN''THENNULLELSEfname_mi
END,CASEtrim(lastname)WHEN''THENNULLELSElastnameEND);
RAISENOTICE'firstnamemi.lastname:%',fmi_lname;
prefix_fmil:=CONCAT_WS('.',CASEtrim(prefix)WHEN''THENNULLELSE
prefixEND,CASEfmi_lnameWHEN''THENNULLELSEfmi_lnameEND);
RAISENOTICE'prefix.firstnamemilastname:%',prefix_fmil;
pfmil_suffix:=CONCAT_WS(',',CASEprefix_fmilWHEN''THENNULLELSE
prefix_fmilEND,CASEtrim(suffix)WHEN''THENNULLELSEsuffix||'.'
END);
RAISENOTICE'prefix.firstnamemilastname,suffix.:%',pfmil_suffix;
RETURNpfmil_suffix;
END;
$BODY$
LANGUAGEplpgsqlVOLATILE;
Inthisexample,weformataperson’sfullnameusingthemagicoftheNULLpropagation.
TheNULLpropagationiswhatoccurswhenanyorallofthemembersofanexpressionarenull.Inthemyvar:=null||'something'expression,myvarwillevaluatetonull.PostgreSQL9.1introducedahandynewfunctionnamedCONCAT_WS(concatenatewithaseparator)totakeadvantageofthiseffect.
Takeanexampleofthefollowinglineofcode:
lastfirst:=CONCAT_WS(',',lastname,firstname);
Theprecedingcodewillnotprintthecommaandwhitespacebetweenlastnameandfirstnameifeitherfirstnameorlastnameisnotpresent.Thiseffectisusedintheformat_us_address()functionwithmanylevelsofnestinginordertoprovideanaddressthatisvisuallyappealingaswellaspostal-processingfriendly.
ThereareseveralstatementsinthecodeexamplethatshowyouhowtouseRAISENOTICE
![Page 242: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/242.jpg)
alongwithsometextandavariabletoprovidedebugginginformationasthefunctionisbeingcalled.Forexample,runningourfunctioninpgAdmin3willproducesomenotificationmessages,asshownhere:
NOTICE:firstnamemi.:KirkL.
NOTICE:firstnamemi.lastname:KirkL.Roybal
NOTICE:prefix.firstnamemilastname:Mr.KirkL.Roybal
NOTICE:prefix.firstnamemilastname,suffix.:Mr.KirkL.Roybal,
Author.
YoucanseethesemessagesinpgAdmin3undertheMessagestab,asshowninthefollowingscreenshot:
Theoutputofthesamequeryinthecommand-linepsqlclientisshowninthefollowingcode:
kroybal=#SELECT
format_us_full_name_debug('Mr','Kirk','L','Roybal','Author');
NOTICE:firstnamemi.:KirkL.
NOTICE:firstnamemi.lastname:KirkL.Roybal
NOTICE:prefix.firstnamemilastname:Mr.KirkL.Roybal
NOTICE:prefix.firstnamemilastname,suffix.:Mr.KirkL.Roybal,
Author.
format_us_full_name_debug
-----------------------------
Mr.KirkL.Roybal,Author.
(1row)
Ifyoudon’tseetheRAISENOTICEmessagesonyourscreen,youshouldcheckclient_min_messagesinyoursession,asshowninthefollowingcode.ItshouldbeNOTICEorhighertoseethemessages:
kroybal=#SHOWclient_min_messages;
![Page 243: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/243.jpg)
client_min_messages
---------------------
notice
(1row)
![Page 244: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/244.jpg)
ThrowingexceptionsTheRAISEcommandtakesseveraloperatorsexceptNOTICE.Thecommandwillalsothrowexceptionsthatareintendedforthecallingcodetocatch.Thefollowingisanexampleofhowtocreateanexception:
CREATEORREPLACEFUNCTIONvalidate_us_zip(zipcodeTEXT)
RETURNSboolean
AS$$
DECLARE
digitstext;
BEGIN
—removeanythingthatisnotadigit(POSIXcompliantly,please)
digits:=(SELECTregexp_replace(zipcode,'[^[:digit:]]','','g'));
IFdigits=''THEN
RAISEEXCEPTION'Zipcodedoesnotcontainanydigits-->%',digits
USINGHINT='IsthisaUSzipcode?',ERRCODE='P9999';
ELSIFlength(digits)<5THEN
RAISEEXCEPTION'Zipcodedoesnotcontainenoughdigits-->%',digits
USINGHINT='Zipcodehaslessthan5digits.',ERRCODE='P9998';
ELSIFlength(digits)>9THEN
RAISEEXCEPTION'Unnecessarydigitsinzipcode-->%',digitsUSING
HINT='Zipcodeismorethan9digits.',ERRCODE='P9997';
ELSIFlength(digits)>5ANDlength(digits)<9THEN
RAISEEXCEPTION'Zipcodecannotbeprocessed-->%',digitsUSINGHINT
='Zipcodeabnormallength.',ERRCODE='P9996';
ELSE
RETURNtrue;
ENDIF;
END;
$$LANGUAGEplpgsql;
ThedeveloperdefinestheERRCODEvalues.Inthisexample,IusedthegeneralPL/pgSQLerrorcodevalue(P0001orplpgsql_error),startedatthetopoftherange(P9999)oferrors,anddecrementedforeachtypeoferrorthatIwishedtoexpose.ThisisaverysimplistictechniquedesignedtopreventoverlapinthefuturefromerrorcodesusedbyPL/pgSQL.Youarefreetoinventanyerrorcodesyouwant,butyouwouldbewelladvisedtoavoidthosealreadylistedinthedocumentationathttp://www.postgresql.org/docs/current/static/errcodes-appendix.html.
Thefollowingcodeisusedtocaptureanyerrorsthrowninthepreviousexample:
CREATEORREPLACEFUNCTIONget_us_zip_validation_status(zipcodetext)
returnstext
AS
$$
BEGIN
SELECTvalidate_us_zip(zipcode);
RETURN'PassedValidation';
EXCEPTION
WHENSQLSTATE'P9999'THENRETURN'Non-USZipCode';
WHENSQLSTATE'P9998'THENRETURN'Notenoughdigits.';
WHENSQLSTATE'P9997'THENRETURN'Toomanydigits.';
![Page 245: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/245.jpg)
WHENSQLSTATE'P9996'THENRETURN'Between6and8digits.';
RAISE;—SomeotherSQLerror.
END;
$$
LANGUAGE'plpgsql';
Thiscodecanbecalledasfollows:
SELECTget_us_zip_validation_status('34955');
get_us_zip_validation_status
------------------------------
PassedValidation
(1row)
root=#SELECTget_us_zip_validation_status('349587');
get_us_zip_validation_status
------------------------------
Between6and8digits.
(1row)
root=#SELECTget_us_zip_validation_status('3495878977');
get_us_zip_validation_status
------------------------------
Toomanydigits.
(1row)
root=#SELECTget_us_zip_validation_status('BNHCGR');
get_us_zip_validation_status
------------------------------
Non-USZipCode
(1row)
root=#SELECTget_us_zip_validation_status('3467');
get_us_zip_validation_status
------------------------------
Notenoughdigits.
(1row)
![Page 246: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/246.jpg)
LoggingtoafileTheRAISEstatementexpressioncanbesenttoalogfileusinglog_min_messages.Thisparameterissetinpostgresql.conf.Thevalidvaluesaredebug5,debug4,debug3,debug2,debug1,info,notice,warning,error,log,fatal,andpanic.
Thedefaultlogginglevelisdependentonthepackagingsystem.OnUbuntu,thedefaultlogginglevelisinfo.ThelogginglevelscorrespondtothesameexpressionsfortheRAISEstatement.Asadeveloper,youcanraiseanyofthemessagesthatareavailableandhavethemrecordedinthelogfileforanalysislater.
ThesimplestwaytopostamessagetothePostgreSQLdaemonlogfileisusingRAISELOG:
RAISELOG'WhyamIdoingthis?';
Thislogfileisusuallylocatedinthe<data_directory>/pg_logfolder.
TheadvantagesofRAISENOTICEUsingtheRAISENOTICEformofdebugginghasseveraladvantages.Itcanbeusedeasilyandrepeatedlywithscriptsforregressiontesting.Thisisveryeasilyaccomplishedwiththecommand-lineclient.Considerthefollowingstatement:
psql-qtc"SELECTformat_us_full_name_debug
('Mr','Kirk','L.','Roybal','Author');"
Theprecedingstatementproducesthefollowingoutputtostdout:
NOTICE:firstnamemi.:KirkL..
NOTICE:firstnamemi.lastname:KirkL..Roybal
NOTICE:prefix.firstnamemilastname:Mr.KirkL..Roybal
NOTICE:prefix.firstnamemilastname,suffix.:Mr.KirkL..Roybal,
Author.
Mr.KirkL..Roybal,Author.
Becauseaconstantsetofinputparametersshouldalwaysproduceaknownoutput,itisveryeasytousecommand-linetoolsinordertotestforexpectedoutputs.Whenyouarereadytodeployyournewlymodifiedcodetotheproductionsystem,runyourcommand-lineteststoverifythatallofyourfunctionsstillworkasexpected.
RAISENOTICEisincludedwiththeproductandrequiresnoinstallation.ItsadvantagewillbecomeclearerlaterinthechapterwheretheratherpainfulinstallationprocedureforthePL/pgSQLdebuggerisexplained.
TheRAISEstatementiseasytounderstand.Thesyntaxisstraightforward,anditiswelldocumentedathttp://www.postgresql.org/docs/current/static/plpgsql-errors-and-messages.html.
RAISEworksinanydevelopmentenvironmentandhasbeenaroundforaverylongtime,inalmosteveryversionofPostgreSQLoneveryoperatingsystem.IhaveuseditwithpgAdmin3,phpPgAdmin,aswellasthecommand-linetoolpsql.
![Page 247: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/247.jpg)
Theseattributes,takentogether,makeRAISEaveryattractivetoolforsmall-scaledebugging.
ThedisadvantagesofRAISENOTICEUnfortunately,therearesomedisadvantagestousingthismethodofdebugging.TheprimarydisadvantageisthatyouneedtoremovetheRAISEstatementswhentheyarenolongernecessary.Themessagestendtoclutterupthepsqlcommand-lineclientandaregenerallyannoyingtootherdevelopers.Thelogmayfillupquicklywithuselessmessagesfrompreviousdebuggingsessions.TheRAISEstatementsneedtobewritten,commentedout,andrestoredwhenneeded.Theymaynotcovertheactualbugbeingsought.Theyalsoslowdowntheexecutionoftheroutine.
YouwillalsofindChapter13,PublishingYourCodeasPostgreSQL,quiteinformative.Thischapterincludessomeexamples(andanextremelyhandywaytoinstallthem)thatwillbeusefulhereinthispartofthebook.Theexampleswillbeshowninthetextofthischapteraswell,buttheywillbequiteabiteasierforyoutoinstallasanextension.
![Page 248: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/248.jpg)
![Page 249: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/249.jpg)
VisualdebuggingThePL/pgSQLdebuggerisaprojecthostedonPostgreSQLGitthatprovidesadebugginginterfaceintoPostgreSQLVersion8.2orhigher.Theprojectishostedathttp://git.postgresql.org/gitweb/?p=pldebugger.git;a=summary.
ThePL/pgSQLdebuggerletsyoustepthroughthePL/pgSQLcode,setandclearbreakpoints,viewandmodifyvariables,andwalkthroughthecallstack.
Asyoucanseefromthedescription,thePL/pgSQLdebuggercanbequiteahandylittletooltohaveinyourarsenal.
![Page 250: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/250.jpg)
InstallingthedebuggerOK,nowwewillmovepasttheglamourandactuallygetthedebuggerrunningonoursystem.IfyouinstallPostgreSQLwithoneofthepackagesthatcontainsthedebugger,theinstallationisprettysimple.Otherwise,youwillneedtobuilditfromthesource.
AdetaileddiscussionofhowtoinstallthePL/pgSQLdebuggerfromthesourceisbeyondthescopeofthisbook,butIwilljustlistthesetofstepstoinstallthedebuggerquickly.ThebestwaytobuildthesourcewillbetopullthelatestversionfromtheGitrepositoryandfollowtheREADMEfileinthedirectory.IfyouwanttogetstartedwithitquicklyandyouhaveaWindowsmachineavailable,thesimplestwaytousethedebuggerisusingthePostgreSQLWindowsinstallerfromhttp://www.postgresql.org/download/windows/.
![Page 251: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/251.jpg)
InstallingthedebuggerfromthesourceHereisasetofsimplestepsthatshouldgetyouupandrunningifyouwanttoinstallfromthesource:
1. ClonetheGitrepositoryasshown.Youcanviewtherepositoryathttp://git.postgresql.org/gitweb/?p=pldebugger.git;a=summary:
gitclonehttp://git.postgresql.org/git/pldebugger.git
2. Copythispldebugger/directorytocontrib/inyourPostgreSQLsourcetree.3. Runmake&&makeinstallinthepldebuggerfolder.4. Modifytheshared_preload_librariesconfigurationoptioninpostgresql.confas
follows:
shared_preload_libraries='$libdir/plugin_debugger'
5. RestartPostgreSQL.6. Createthedebuggerextension:
CREATEEXTENSIONpldbgapi;
ThisshouldinstallthePLdebuggerandyoushouldbeabletouseitwithpgAdmin3.
TipYoucanalsoinstallPostgreSQLusingEnterpriseDB’sone-clickinstallersformostplatforms,whichalsoincludesthePLdebuggerathttp://www.enterprisedb.com/products-services-training/pgdownload.
![Page 252: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/252.jpg)
InstallingpgAdmin3ThePL/pgSQLdebuggermoduleworkswithpgAdmin3.Youdon’tneedtoperformspecialstepswiththeinstallationofpgAdmin3forthedebuggertofunction.Installitasusualfromyourpackagemanagerontheplatformthatyouareusing.ForUbuntu10.04LTS,thecommandisasfollows:
sudoapt-getinstallpgadmin3
![Page 253: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/253.jpg)
UsingthedebuggerWhenthedebuggerisavailableforaparticulardatabase,itcanbeseeninthecontextmenuwhenyouright-clickonaPL/pgSQLfunction.Wehavealreadycreatedsomeofthedebuggersintheearlierpartofthischapter.Usingformat_us_full_nameasanexample,right-clickonitandnavigatetoDebugging|Debug:
Asaresult,youwillseethefollowingdialog:
Entersomevaluesintothecolumns,asseenintheprecedingscreenshot,andclickontheDebugbutton.Youwillbedepositedintothedebugger:
![Page 254: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/254.jpg)
Thiswillallowyoutostepthroughthecodeandseethevaluesofanyvariablesastheyarebeingchanged.Clickonthestep-intobuttonafewtimestoseehowthevaluesaremodifiedasthefunctionisperformed.
TheadvantagesofthedebuggerThePL/pgSQLdebuggerdoesnotrequireanyresourcesontheserverwhennotactuallyinuse.BecauseitisinvokedmanuallyfromwithinpgAdmin3,itisnotresidentinmemoryuntilitisactuallycalledupon.Thisarchitecturedoesnotrequireanybackgroundprocessesoradditionaldaemonsforthesakeofdebugging.
Also,thePL/pgSQLdebuggerdoesnotrequireanyspecial“calling”functionstobewritteninordertoinvokethedebuggingprocess.Therearenoerrorstotrapandnotablesoferrorcodestointerpret.Everythingnecessarytothedebuggingprocessisavailableinasimplewindow.
Ifyouconnecttoyourdatabaseasasuperuser,youalsohavetheabilitytosetaglobalbreakpoint.Thisbreakpointcanbesetonanyfunctionortriggeranditwillstopthenexttimeanycodepathcallsthefunction.Thisisparticularlyusefulifyouwanttodebugyourfunctionsortriggersinthecontextofyourentirerunningapplication.
ThegreatestadvantageofthePL/pgSQLdebuggeristhatitdoesnotrequireanyspecialrigginginthefunctionsthatarebeingdebugged.
Thereisnocodetobeinsertedorremoved,andgoodcodingpracticesdon’tneedtobemodifiedwithrespecttodebugging.Thereisnopossibilityto“forget”thedebuggingcodewhenmovingtoproduction.AllofyourPL/pgSQLfunctionsarenowinstantlyreadytodebugwithoutanyspecialaction.
Thedisadvantagesofthedebugger
![Page 255: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/255.jpg)
Asyouhavebecomepainfullyaware,theinstallationofthedebuggerleavesalottobedesired.ThisdebuggerhasnotbecomeverypopularinthePostgreSQLcommunityatlargebecauseoftheratherlargelearningcurveinvolved,andthat’sjusttogetitinstalled.
Thisformofdebuggingismeantforpersonalproductivitywhileactivelydevelopingfunctions.Itdoesnotworkwellasanautomationtool.
![Page 256: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/256.jpg)
![Page 257: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/257.jpg)
SummaryThedebuggingmethodsthatwehaveseeninthischapteraredesignedtobeusedinconjunctionwithoneanother.Theycomplementeachotheratdifferentpointsinthedevelopmentprocess.WheredebuggingusingthePL/pgSQLdebuggerishighlyeffectivewhileeditinganexisting(hopefullywell-written)function,otherformsofdebuggingmaybebettersuitedtothequalityassuranceorautomateddataprocessingapplications.
BecausethePL/pgSQLdebuggerismeanttobeavisualtooltoworkwithinpgAdmin3,itispossiblethatthedevelopermaywanttoforegothevisualdebuggerintheinterestofsomeotherfeature.
Inthenextchapter,wewilltakealookathowtowritesomeadvancedfunctionsinC.
![Page 258: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/258.jpg)
![Page 259: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/259.jpg)
Chapter8.UsingUnrestrictedLanguagesYoumayhavenoticed,thatsomeofthePLsinPostgreSQLcanbedeclaredasuntrusted.Theyallendintheletterutoremindyouthattheyareuntrustedeachtimeyouusethemtocreateafunction.Unrestrictedlanguagesallowyoutodothingsthatrestrictedortrustedlanguagesarenotallowedtodo;forexample,interactingwiththeenvironmentandcreatingfilesandopeningsockets.Inthischapter,wewilllookatsomeexamplesindetail.
Thisuntrustednessbringsupmanyquestions:
Doesbeinguntrustedmeanthatsuchlanguagesaresomehowinferiortotrustedones?CanIstillwriteanimportantfunctioninanuntrustedlanguage?Willtheysilentlyeatmydataandcorruptthedatabase?
Theanswersareno,yes,andmayberespectively.Let’snowdiscussthesequestionsinorder.
![Page 260: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/260.jpg)
Areuntrustedlanguagesinferiortotrustedones?No,onthecontrary,theselanguagesareuntrustedinthesamewaythatasharpknifeisuntrustedandshouldbekeptoutofthereachofverysmallchildren,unlessthereisadultsupervision.TheyhaveextrapowersthatordinarySQL,oreventhetrustedlanguages(suchasPL/pgSQL)andtrustedvariantsofthesamelanguage(PL/PerlversusPL/PerlU)don’thave.
Youcanusetheuntrustedlanguagestodirectlyreadandwriteontheserver’sdisks,andyoucanuseittoopensocketsandmakeInternetqueriestotheoutsideworld.Youcanevensendarbitrarysignalstoanyprocessrunningonthedatabasehost.Generally,youcandoanythingthenativelanguageofthePLcando.
However,youprobablyshouldnottrustarbitrarydatabaseuserstohavetherighttodefinefunctionsintheselanguages.Alwaysthinktwicebeforegivingallprivilegesonanuntrustedlanguagetoauserorgroup,byusingthe*ulanguagesforimportantfunctions.
![Page 261: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/261.jpg)
![Page 262: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/262.jpg)
Canyouuseuntrustedlanguagesforimportantfunctions?Absolutely!Sometimes,itmaybetheonlywaytoaccomplishsometasksfrominsidetheserver.Performingsimplequeriesandcomputationsshoulddonothingharmfultoyourdatabase,andneithershouldconnectingtotheexternalworldforsendinge-mails,fetchingwebpages,orperformingSOAPrequests.However,becarefulaboutperformingoperationsthatmaycausedelaysandevenqueriesthatgetstuck,butthesecanusuallybedealtwithbysettinganupperlimitastohowlongaquerycanrun,byusinganappropriatestatementtime-outvalue.Settingareasonablestatementtime-outvaluebydefaultisagoodpracticeanyway.
So,ifyoudon’tdeliberatelydoriskythings,theprobabilityofharmingthedatabaseisnobiggerthanusinga“trusted”(alsoknownasrestricted)variantofthelanguage.However,ifyougivethelanguagetosomeonewhostartschangingbytesontheproductiondatabase“toseewhathappens”,youwillgetwhatyouaskedfor.
![Page 263: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/263.jpg)
![Page 264: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/264.jpg)
Willuntrustedlanguagescorruptthedatabase?Thepowertocorruptthedatabaseisdefinitelythere,sincethefunctionsrunasthesystemuserofthedatabaseserverwithfullaccesstothefilesystem.So,ifyoublindlystartwritingintothedatafilesanddeletingimportantlogs,itispossiblethatyourdatabasewillbecorrupted.
Additionaltypesofdenial-of-serviceattacksarealsopossible,suchasusingupallmemoryoropeningallIPports.But,therearewaystooverloadthedatabaseusingplainSQLaswell,sothatpartisnotmuchdifferentfromthetrusteddatabaseaccesswiththeabilitytojustrunarbitraryqueries.
Soyes,youcancorruptthedatabase,butpleasedon’tdoitonaproductionserver.Ifyoudo,youwillbesorry.
![Page 265: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/265.jpg)
![Page 266: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/266.jpg)
Whyuntrusted?PostgreSQL’sabilitytouseanuntrustedlanguageisapowerfulwaytoperformsomenon-traditionalthingsfromdatabasefunctions.CreatingthesefunctionsinaPLisataskofsmallermagnitudethanwritinganextensionfunctioninC.Forexample,afunctiontolookupahostnameforanIPaddressisonlyafewlinesinPL/PythonU:
CREATELANGUAGEplpythonu;
CREATEFUNCTIONgethostbyname(hostnametext)
RETURNSinet
AS$$
importsocket
returnsocket.gethostbyname(hostname)
$$LANGUAGEplpythonuSECURITYDEFINER;
Youcantestitimmediatelyaftercreatingthefunctionbyusingpsql:
hannu=#SELECTgethostbyname('www.postgresql.org');
gethostbyname
----------------
98.129.198.126
(1row)
Creatingthesamefunctioninthemostuntrustedlanguage,C,involveswritingtensoflinesofboilerplatecode,worryingaboutmemoryleaks,andalltheotherproblemscomingfromwritingcodeinalow-levellanguage.WhilewewilllookatextendingPostgreSQLinCinthenextchapter,IrecommendprototypinginaPLlanguageifpossible,andinanuntrustedlanguageifthefunctionneedssomethingthattherestrictedlanguagesdonotoffer.
![Page 267: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/267.jpg)
WhyPL/Python?AllofthesetaskscouldbedoneequallywellusingPL/PerlUorPL/TclU.IchosePL/PythonUmainlybecausePythonisthelanguageIammostcomfortablewith.ThisalsotranslatestohavingwrittensomePL/Pythoncode,whichIplantodiscussandsharewithyouinthischapter.
![Page 268: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/268.jpg)
![Page 269: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/269.jpg)
QuickintroductiontoPL/PythonInthepreviouschapters,wediscussedPL/pgSQLwhichisoneofthestandardprocedurallanguagesdistributedwithPostgreSQL.PL/pgSQLisalanguageuniquetoPostgreSQLandwasdesignedtoaddblocksofcomputationandSQLinsidethedatabase.Whileithasgrowninitsbreadthoffunctionality,itstilllacksthecompletenessofsyntaxofafullprogramminglanguage.PL/PythonallowsyourdatabasefunctionstobewritteninPythonwithallthedepthandmaturityofwritingaPythoncodeoutsidethedatabase.
![Page 270: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/270.jpg)
AminimalPL/PythonfunctionLet’sstartfromtheverybeginning,yetagain:
CREATEFUNCTIONhello(nametext)
RETURNStext
AS$$
return'hello%s!'%name
$$LANGUAGEplpythonu;
Here,weseethatcreatingafunctionstartsbydefiningitasanyotherPostgreSQLfunctionwithaRETURNSdefinitionofatextfield:
CREATEFUNCTIONhello(nametext)
RETURNStext
Thedifferencefromwhatwehaveseenbefore,isthatthelanguagepartisspecifyingplpythonu(thelanguageIDforthePL/PythonUlanguage):
$$LANGUAGEplpythonu;
Insidethefunctionbody,itisverymuchanormalPythonfunctionreturningavalueobtainedbythenamepassedasanargumentformattedintoastring'hello%s!',usingthestandardPythonformattingoperator%:
return'hello%s!'%name
Finally,let’stesthowthisworks:
hannu=#SELECThello('world');
hello
---------------
helloworld!
(1row)
Andyes,itreturnsexactlywhatisexpected!
![Page 271: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/271.jpg)
DatatypeconversionsThefirstandlastthingshappeningwhenaPLfunctioniscalledbyPostgreSQL,areconvertingargumentvaluesbetweenthePostgreSQLandPLtypes.ThePostgreSQLtypesneedtobeconvertedtothePLtypesonenteringthefunction,andthenthereturnvalueneedstobeconvertedbackintothePostgreSQLtypes.
ExceptforPL/pgSQL,whichusesPostgreSQL’sownnativetypesincomputations,thePLsarebasedonexistinglanguageswiththeirownunderstandingofwhattypes(integer,string,date,andsoon)are,howtheyshouldbehave,andhowtheyarerepresentedinternally.TheyaremostlysimilartoPostgreSQL’sunderstandingbutquiteoftenarenotexactlythesame.PL/PythonconvertsdatafromPostgreSQLtypestoPythontypes,asshowninthefollowingtable:
PostgreSQL Python2
Python3 Comments
int2,int4 int int
int8 long int
real,double,numeric float float Thismayloseprecisionfornumericvalues.
bytea str bytesNoencodingconversionisdone,norshouldanyencodingbeassumed.
text,char(),varchar(),andothertexttypes
str strOnPython2,thestringwillbeinserverencoding.
OnPython3,itisaunicodestring.
Allothertypes str strPostgreSQL’stypeoutputfunctionisusedtoconverttothisstring.
Insidethefunction,allcomputationisdoneusingPythontypesandthereturnvalueisconvertedbacktoPostgreSQLusingthefollowingrules(theserulesarethedirectquotesfromofficialPL/Pythondocumentationathttp://www.postgresql.org/docs/current/static/plpython-data.html):
WhenthePostgreSQLreturntypeisBoolean,thereturnvaluewillbeevaluatedfortruth,accordingtothePythonrules.Thatis,0andemptystringsarefalse,butnotablyfistrue.WhenthePostgreSQLreturntypeisbytea,thereturnvaluewillbeconvertedtoastring(Python2)orbytes(Python3)usingtherespectivePythonbuilt-ins,withtheresultbeingconvertedbytea.ForallotherPostgreSQLreturntypes,thereturnedPythonvalueisconvertedtoastringusingPython’sbuilt-instr,andtheresultispassedtotheinputfunctionofthePostgreSQLdatatype.
StringsinPython2arerequiredtobeinthePostgreSQLserverencodingwhentheyarepassedtoPostgreSQL.Stringsthatarenotvalidinthecurrentserverencodingwillraise
![Page 272: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/272.jpg)
anerror.Butnotallencodingmismatchescanbedetected,sogarbagedatacanstillresultwhenthisisnotdonecorrectly.Unicodestringsareconvertedtothecorrectencodingautomatically,soitcanbesaferandmoreconvenienttousethose.InPython3,allstringsareUnicodestrings.
Inotherwords,anythingbut0,False,andanemptysequence,includingemptystrings'',oradictionarybecomesPostgreSQLfalse.
Onenotableexceptiontothis,isthatthecheckforNoneisdonebeforeanyotherconversions.EvenforBooleans,NoneisalwaysconvertedtoNULLandnottotheBooleanvaluefalse.
Forthebyteatype,thePostgreSQLbytearray,theconversionfromPython’sstringrepresentation,isanexactcopywithnoencodingorotherconversionsapplied.
![Page 273: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/273.jpg)
WritingsimplefunctionsinPL/PythonWritingfunctionsinPL/PythonisnotmuchdifferentinprinciplefromwritingfunctionsinPL/pgSQL.Youstillhavetheexactsamesyntaxaroundthefunctionbodyin$$,andtheargumentname,types,andreturnsallmeanthesamething,regardlessoftheexactPL/languageused.
AsimplefunctionSo,asimpleadd_one()functioninPL/Pythonlookslikethis:
CREATEFUNCTIONadd_one(iint)
RETURNSintAS$$
returni+1;
$$LANGUAGEplpythonu;
usm=#SELECTadd_one(2);
add_one
---------
3
(1row)
Itcan’tgetanysimplerthanthat,canit?
WhatyouseehereisthatthePL/PythonargumentsarepassedtothePythoncodeafterconvertingthemtoappropriatetypes,andtheresultispassedbackandconvertedtotheappropriatePostgreSQLtypeforthereturnvalue.
FunctionsreturningarecordToreturnarecordfromaPythonfunction,youcanuse:
AsequenceorlistofvaluesinthesameorderasthefieldsinthereturnrecordAdictionarywithkeysmatchingthefieldsinthereturnrecordAclassortypeinstancewithattributesmatchingthefieldsinthereturnrecord
Herearesamplesofthethreewaystoreturnarecord:
First,usinganinstance:
CREATEORREPLACEFUNCTIONuserinfo(
INOUTusernamename,
OUTuser_idoid,
OUTis_superuserboolean)
AS$$
classPGUser:
def__init__(self,username,user_id,is_superuser):
self.username=username
self.user_id=user_id
self.is_superuser=is_superuser
u=plpy.execute("""\
selectusename,usesysid,usesuper
frompg_user
whereusename='%s'"""%username)[0]
user=PGUser(u['usename'],u['usesysid'],u['usesuper'])
returnuser
![Page 274: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/274.jpg)
$$LANGUAGEplpythonu;
Then,alittlesimpleroneusingadictionary:
CREATEORREPLACEFUNCTIONuserinfo(
INOUTusernamename,
OUTuser_idoid,
OUTis_superuserboolean)
AS$$
u=plpy.execute("""\
selectusename,usesysid,usesuper
frompg_user
whereusename='%s'"""%username)[0]
return{'username':u['usename'],'user_id':u['usesysid'],
'is_superuser':u['usesuper']}
$$LANGUAGEplpythonu;
Finally,usingatuple:
CREATEORREPLACEFUNCTIONuserinfo(
INOUTusernamename,
OUTuser_idoid,
OUTis_superuserboolean)
AS$$
u=plpy.execute("""\
selectusename,usesysid,usesuper
frompg_user
whereusename='%s'"""%username)[0]
return(u['usename'],u['usesysid'],u['usesuper'])
$$LANGUAGEplpythonu;
Notice[0]attheendofu=plpy.execute(...)[0]inalltheexamples.Itistheretoextractthefirstrowoftheresult,asevenforone-rowresultsplpy.executestillreturnsalistofresults.
TipDangerofSQLinjection!
Aswehaveneitherexecutedaprepare()methodandexecutedaexecute()methodwithargumentsafterit,norhaveweusedtheplpy.quote_literal()method(bothtechniquesarediscussedlater)tosafelyquotetheusernamebeforemergingitintothequery,weareopentoasecurityflawknownasSQLinjection.So,makesurethatyouonlylettrusteduserscallthisfunctionorsupplytheusernameargument.
CallingthefunctiondefinedviaanyofthesethreeCREATEcommandswilllookexactlythesame:
hannu=#SELECT*FROMuserinfo('postgres');
username|user_id|is_superuser
----------+---------+--------------
postgres|10|t
(1row)
Itusuallydoesnotmakesensetodeclareaclassinsideafunctionjusttoreturnarecordvalue.Thispossibilityisincludedmostlyforcaseswhereyoualreadyhaveasuitableclass
![Page 275: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/275.jpg)
withasetofattributesmatchingtheonesthefunctionreturns.
TablefunctionsWhenreturningasetfromPL/Pythonfunctions,youhavethreeoptions:
ReturnalistoranyothersequenceofreturntypeReturnaniteratororgeneratorTheyieldkeywordinpythonjustreturnsagenerator
Here,wehavethreewaystogenerateallevennumbersuptotheargumentvalueusingthesedifferentstyles:
First,returningalistofintegers:
CREATEFUNCTIONeven_numbers_from_list(up_toint)
RETURNSSETOFint
AS$$
returnrange(0,up_to,2)
$$LANGUAGEplpythonu;
libro=#SELECT*FROMeven_numbers_from_list(10);
even_numbers_from_list
------------------------
0
2
4
6
8
(5rows)
Thelisthere,isreturnedbyabuilt-inPythonfunctioncalledrange,whichreturnsaresultofallevennumbersbelowtheargument.Thisgetsreturnedasatableofintegers,oneintegerperrowfromthePostgreSQLfunction.IftheRETURNSclauseofthefunctiondefinitionwouldsayint[]insteadofSETOFint,thesamefunctionwouldreturnasinglenumberofevenintegersasaPostgreSQLarray.
Thenextfunctionreturnsasimilarresultusingageneratorandreturningboththeevennumberandtheoddonefollowingit.Also,noticethedifferentPostgreSQLsyntaxRETURNSTABLE(...)usedthistimefordefiningthereturnset:
CREATEFUNCTIONeven_numbers_from_generator(up_toint)
RETURNSTABLE(evenint,oddint)
AS$$
return((i,i+1)foriinxrange(0,up_to,2))
$$LANGUAGEplpythonu;
libro=#SELECT*FROMeven_numbers_from_generator(10);
even|odd
------+-----
0|1
2|3
4|5
6|7
8|9
(5rows)
![Page 276: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/276.jpg)
Thegeneratorisconstructedusingageneratorexpression(xforxin<seq>).Finally,thefunctionisdefinedusingageneratorusinganexplicityieldsyntax,andyetanotherPostgreSQLsyntaxisusedforreturningSETOFRECORDwiththerecordstructuredefinedthistimebyOUTparameters:
CREATEFUNCTIONeven_numbers_with_yield(up_toint,
OUTevenint,
OUToddint)
RETURNSSETOFRECORD
AS$$
foriinxrange(0,up_to,2):
yieldi,i+1
$$LANGUAGEplpythonu;
Theimportantparthere,isthatyoucanuseanyoftheprecedingwaystodefineaPL/Pythonsetreturningfunctionandtheyallworkthesame.Also,youarefreetoreturnamixtureofdifferenttypesforeachrowoftheset:
CREATEFUNCTIONbirthdates(OUTnametext,OUTbirthdatedate)
RETURNSSETOFRECORD
AS$$
return(
{'name':'bob','birthdate':'1980-10-10'},
{'name':'mary','birthdate':'1983-02-17'},
['jill','2010-01-15'],
)
$$LANGUAGEplpythonu;
Thisyieldstheresult,asfollows:
hannu=#SELECT*FROMbirthdates();
name|birthdate
------+------------
bob|1980-10-10
mary|1983-02-17
jill|2010-01-15
(3rows)
Asyoucansee,thedatareturningapartofPL/PythonUismuchmoreflexiblethanreturningdatafromafunctionwritteninPL/pgSQL.
![Page 277: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/277.jpg)
RunningqueriesinthedatabaseIfyouhaveeveraccessedadatabaseinPython,youknowthatmostdatabaseadaptersconformtoasomewhatloosestandardcalledPythonDatabaseAPISpecificationv2.0orDBAPI2forshort.Youcanfindthereferenceonlineathttp://legacy.python.org/dev/peps/pep-0249/
ThefirstthingyouneedtoknowaboutdatabaseaccessinPL/Pythonisthatin-databasequeriesdonotfollowthisAPI.
RunningsimplequeriesInsteadofusingthestandardAPI,therearejustthreefunctionsfordoingalldatabaseaccess.Therearetwovariants:plpy.executeforrunningaquery,andplpy.prepare()forturningaquerytextintoaqueryplanorapreparedquery.
Thesimplestwaytodoaqueryiswith:
res=plpy.execute(<querytext>,[<rowcount>])
Thistakesatextualqueryandanoptionalrowcount,andreturnsaresultobject,whichemulatesalistofdictionaries,onedictionaryperrow.
Asanexample,ifyouwanttoaccessafield'name'ofthethirdrowoftheresult,youuse:
res[2]['name']
Theindexis2andnot3becausePythonlistsareindexedstartingfrom0,sothefirstrowisres[0],thesecondrowres[1],andsoon.
UsingpreparedqueriesInanidealworld,thiswouldbeallthatisneeded,butplpy.execute(query,cnt)hastwoshortcomings:
ItdoesnotsupportparametersTheplanforthequeryisnotsaved,requiringthequerytexttobeparsedandrunthroughtheoptimizerateachinvocation
Wewillshowawaytoproperlyconstructaquerystringlater,butformostusessimpleparameterpassingisenough.So,theexecute(query,[maxrows])callbecomesasetoftwostatements:
plan=plpy.prepare(<querytext>,<listofargumenttypes>)
res=plpy.execute(plan,<listofvalues>,[<rowcount>])
Forexample,toqueryifauser‘postgres’isasuperuser,usethefollowing:
plan=plpy.prepare("selectusesuperfrompg_userwhereusename=$1",
["text"])
res=plpy.execute(plan,["postgres"])
printres[0]["usesuper"]
Thefirststatementpreparesthequery,whichparsesthequerystringintoaquerytree,
![Page 278: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/278.jpg)
optimizesthistreetoproducethebestqueryplanavailable,andreturnstheprepared_queryobject.Thesecondrowusesthepreparedplantoqueryforaspecificuser’ssuperuserstatus.
Thepreparedplancanbeusedmultipletimes,sothatyoucouldcontinuetoseeifuserbobissuperuser.
res=plpy.execute(plan,["bob"])
printres[0]["usesuper"]
CachingpreparedqueriesPreparingthequerycanbequiteanexpensivestep,especiallyformorecomplexquerieswheretheoptimizerhastochoosefromaratherlargesetofpossibleplans.So,itmakessensetore-useresultsofthisstep,ifpossible.
ThecurrentimplementationofPL/Pythondoesnotautomaticallycachequeryplans(preparedqueries),butyoucandoityourselfeasily.
try:
plan=SD['is_super_qplan']
except:
SD['is_super_qplan']=plpy.prepare("....
plan=SD['is_super_qplan']
<therestofthefunction>
TheglobaldictionarySDisavailabletostoredatabetweenfunctioncalls.Thisvariableisprivatestaticdata.TheglobaldictionaryGDispublicdata,availabletoallPythonfunctionswithinasession.Usewithcare.ThevaluesinSD[]andGD[]onlyliveinsideasingledatabasesession,soitonlymakessensetodothecachingincaseyouhavelong-livedconnections.
![Page 279: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/279.jpg)
WritingtriggerfunctionsinPL/PythonAswithotherPLs,PL/PythonUcanbeusedtowritetriggerfunctions.ThedeclarationofatriggerfunctionisdifferentfromanordinaryfunctionbythereturntypeRETURNSTRIGGER.So,asimpletriggerfunctionthatjustnotifiesthecallerthatitisindeedcalled,lookslikethis:
CREATEORREPLACEFUNCTIONnotify_on_call()
RETURNSTRIGGER
AS$$
plpy.notice('Iwascalled!')
$$LANGUAGEplpythonu;
Aftercreatingthisfunction,thetriggercanbetestedonatableusingatriggerfunction:
hannu=#CREATETABLEttable(idint);
CREATETABLE
hannu=#CREATETRIGGERttable_notifyBEFOREINSERTONttableEXECUTE
PROCEDUREnotify_on_call();
CREATETRIGGER
hannu=#INSERTINTOttableVALUES(1);
NOTICE:Iwascalled!
CONTEXT:PL/Pythonfunction"notify_on_call"
INSERT01
Ofcourse,theprecedingtriggerfunctionisquiteuseless,aswillbeanytriggerwithoutknowingwhenandonwhatdatachange,thetriggerwascalled.Allthedataneededbyatrigger,whenitiscalled,ispassedinviathetriggerdictionarycalledTD.InTD,youhavethefollowingvalues:
Key Value
TD["event"]
Theeventthetriggerfunctioniscalledfor;oneofthefollowingstringsiscontainedastheevent:
INSERT,UPDATE,DELETE,orTRUNCATE
TD["when"] OneofBEFORE,AFTER,orINSTEADOF
TD["level"] ROWorSTATEMENT
TD["old"]
Thisisthebefore-commandimageoftherow.Forlow-levelUPDATEandDELETEtriggers,thiscontainsadictionaryforthevaluesofthetriggeringrow,beforethechangeshavebeenmadebythecommand.ItisNoneforothercases.
TD["new"]
Thisistheafter-commandimageoftherow.Forlow-levelINSERTandUPDATEtriggers,thiscontainsadictionaryforthevaluesofthetriggeringrow,afterthechangeshavebeenmadebythecommand.ItisNoneforothercases.
IfyouareinaBEFOREorINSTEADOFtrigger,youcanmakechangestothisdictionaryandthensignalPostgreSQLtousethechangedtuplebyreturningthestringMODIFYfromthetriggerfunction.
TD["name"] ThetriggernamefromtheCREATETRIGGERcommand.
![Page 280: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/280.jpg)
TD["table_name"] Thenameofthetableonwhichthetriggeroccurred.
TD["table_schema"] Theschemaofthetableonwhichthetriggeroccurred.
TD["relid"] Theobjectidentifier(OID)ofthetableonwhichthetriggeroccurred.
TD["args"]IftheCREATETRIGGERcommandincludedarguments,theyareavailablefromTD["args"][0]toTD["args"][n-1].
InadditiontodoinganythingyoucandoinordinaryPL/Pythonfunctions,suchasmodifyingdataintables,writingtofilesandsockets,andsendinge-mails,youcanalsoaffectthebehaviorofthetriggeringcommand.
IfTD["when"]is("BEFORE","INSTEADOF")andTD["level"]=="ROW",youcanreturnSKIPtoaborttheevent.ReturningNoneorOKindicatesthattherowisunmodifiedanditisOKtocontinue.ReturningNoneisalsothedefaultbehaviorforPythonifthefunctiondoesasimplereturnorrunstotheendwithoutareturnstatement,inwhichcase,youdon’tneedtodoanything.
IncaseyouhavemodifiedvaluesintheTD["new"]andyouwantPostgreSQLtocontinuewiththenewvalues,youcanreturnMODIFYtoindicatetoPL/Pythonthatyou’vemodifiedthenewrow.ThiscanonlybedoneifTD["event"]isINSERTorUPDATE,otherwisethereturnvalueisignored.
ExploringtheinputsofatriggerThefollowingtriggerfunctionisusefulwhendevelopingtriggers,sothatyoucaneasilyseewhatthetriggerfunctionisreallygettingwhencalled:
CREATEORREPLACEFUNCTIONexplore_trigger()
RETURNSTRIGGER
AS$$
importpprint
nice_data=pprint.pformat(
(
('TD["table_schema"]',TD["table_schema"]),
('TD["event"]',TD["event"]),
('TD["when"]',TD["when"]),
('TD["level"]',TD["level"]),
('TD["old"]',TD["old"]),
('TD["new"]',TD["new"]),
('TD["name"]',TD["name"]),
('TD["table_name"]',TD["table_name"]),
('TD["relid"]',TD["relid"]),
('TD["args"]',TD["args"]),
)
)
plpy.notice('explore_trigger:\n'+nice_data)
$$LANGUAGEplpythonu;
ThisfunctionformatsallthedatapassedtothetriggerinTDusingpprint.pformat,andthensendsittotheclientasastandardPythoninfomessageusingplpy.notice.Fortestingthisout,wecreateasimpletableandthenputanAFTER…FOREACHROW…trigger
![Page 281: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/281.jpg)
usingthisfunctiononthattable:
CREATETABLEtest(
idserialPRIMARYKEY,
datatext,
tstimestampDEFAULTclock_timestamp()
);
CREATETRIGGERtest_explore_trigger
AFTERINSERTORUPDATEORDELETEONtest
FOREACHROW
EXECUTEPROCEDUREexplore_trigger('one',2,null);
Now,wecanexplorewhatthetriggerfunctionactuallygets:
hannu=#INSERTINTOtest(id,data)VALUES(1,'firstrowdata');
NOTICE:explore_trigger:
(('TD["table_schema"]','public'),
('TD["event"]','INSERT'),
('TD["when"]','AFTER'),
('TD["level"]','ROW'),
('TD["old"]',None),
('TD["new"]',
{'data':'firstrowdata','id':1,'ts':'2013-05-1312:04:03.676314'}),
('TD["name"]','test_explore_trigger'),
('TD["table_name"]','test'),
('TD["relid"]','35163'),
('TD["args"]',['one','2','null']))
CONTEXT:PL/Pythonfunction"explore_trigger"
INSERT01
MostofthisisexpectedandcorrespondswelltothetableoftheTDdictionaryvaluesgivenintheprevioustable.Whatmaybealittleunexpected,isthefactthattheargumentsgivenintheCREATETRIGGERstatementareallconvertedtostrings,eventheNULL.Whendevelopingyourowntriggers,eitherinPL/Pythonoranyotherlanguage,itmaybeusefultoputthistriggeronthetableaswell,tocheckthattheinputstothetriggerareasexpected.Forexample,itiseasytoseethatifyouomittheFOREACHROWpart,theTD['old']andTD['new']willbothbeempty,asthetriggerdefinitiondefaultstoFOREACHSTATEMENT.
AlogtriggerNow,wecanputthisknowledgetoworkandwriteatriggerthatlogschangestothetabletoeitherafileortoaspeciallog-collectorprocessoverthenetwork.Loggingtoafileisthesimplestwaytopermanentlylogthechangesintransactionswhichwererolledback.Ifthesewereloggedtoalogtable,theROLLBACKcommandwouldalsoremovethelogrecords.Thismaybeacrucialauditrequirementforyourbusiness.
Ofcourse,thisalsohasadownside.Youwillbeloggingthechangesthatmaynotbepermanentduetothetransactionbeingrolledback.Unfortunately,thisisthepriceyouhavetopayfornotlosingthelogrecords.
CREATEORREPLACEFUNCTIONlog_trigger()
RETURNSTRIGGERAS$$
![Page 282: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/282.jpg)
args=tuple(TD["args"])
ifnotSD.has_key(args):
protocol=args[0]
ifprotocol=='udp':
importsocket
sock=socket.socket(socket.AF_INET,
socket.SOCK_DGRAM)
deflogfunc(msg,addr=args[1],
port=int(args[2]),sock=sock):
sock.sendto(msg,(addr,port))
elifprotocol=='file':
f=open(args[1],'a+')
deflogfunc(msg,f=f):
f.write(msg+'\n')
f.flush()
else:
raiseValueError,'badlogdestinCREATETRIGGER'
SD[args]=logfunc
SD['env_plan']=plpy.prepare("""
selectclock_timestamp(),
txid_current(),
current_user,
current_database()""",[])
logfunc=SD[args]
env_info_row=plpy.execute(SD['env_plan'])[0]
importjson
log_msg=json.dumps(
{'txid':env_info_row['txid_current'],
'time':env_info_row['clock_timestamp'],
'user':env_info_row['current_user'],
'db':env_info_row['current_database'],
'table':'%s.%s'%(TD['table_name'],
TD['table_schema']),
'event':TD['event'],
'old':TD['old'],
'new':TD['new'],
}
)
logfunc(log_msg)
$$LANGUAGEplpythonu;
First,thistriggerchecksifitalreadyhasaloggerfunctiondefinedandcachedinthefunction’slocaldictionarySD[].Asthesametriggermaybeusedwithmanydifferentlogdestinations,thelogfunctionisstoredunderthekeyconstructedasaPythontuplefromthetriggerfunctionargumentsintheCREATETRIGGERstatement.WecannotusetheTD["args"]listdirectlyasakey,asPythondictionarykeyshavetobeimmutable,whichalistisnot,butatupleis.
Ifthekeyisnotpresent,meaningthisisthefirstcalltothisparticulartrigger,wehavetocreateanappropriatelogfunctionandstoreit.Todothis,weexaminethefirstargumentforthelogdestinationtype.
Fortheudplogtype,wecreateaUDPsocketforwriting.Then,wedefineafunctionpassinginthissocketandalsotheothertwotriggerargumentsasdefaultargumentsforthe
![Page 283: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/283.jpg)
function.ThisisthemostconvenientwaytocreateaclosureandtobundleafunctionwithsomedatavaluesinPython.
Forthefiletype,wejustopenthisfileintheappendmode(a+)andalsocreatealogfunction.Thelogfunctionwritesamessagetothisfileandflushesthewrite,sothedataiswrittentothefileimmediatelyandnotsometimelaterwhenthewritebufferfillsup(thisisnotpreferableforperformancecriticalsystems).ThelogfunctioncreatedineitherofthesecasesisstoredinSD[tuple(TD["args"])].
Atthispoint,wealsoprepareandsaveaqueryplanforgettingotherdatawewanttologandsavethisinSD['env_plan'].Nowthatwearedonewiththeone-timepreparations,wecanproceedwiththeactualloggingpart,whichisreallyverysimple.
Next,weretrievetheloggingfunction(logfunc=SD[args])andgettherowoftheotherloggeddata:
env_info_row=plpy.execute(SD['env_plan'])[0]
Finally,weconvertalltheloggeddataintooneJSONobject(log_msg=json.dumps({...}))andthenusetheloggingfunctiontosendittothelog,logfunc(log_msg).
Andthat’sit.
Next,let’stestitouttoseehowitworksbyaddinganothertriggertoourtesttablewecreatedearlier:
CREATETRIGGERtest_audit_trigger
AFTERINSERTORUPDATEORDELETEONtest
FOREACHROW
EXECUTEPROCEDURElog_trigger('file','/tmp/test.json.log');
AnychangestothetabledoneviaINSERT,UPDATE,orDELETEareloggedinto/tmp/test.json.log.Thisfileisinitiallyownedbythesameuserrunningtheserver,usuallypostgres.So,tolookatityouneedtoeitherbethatuserorrootuser,oryouhavetochangethepermissionsonthefilecreatedtoallowreading.
IfyouwanttotesttheUDPloggingpart,youjusthavetodefineanothertriggerwithdifferentarguments:
CREATETRIGGERtest_audit_trigger_udp
AFTERINSERTORUPDATEORDELETEONtest
FOREACHROW
EXECUTEPROCEDURElog_trigger('udp','localhost',9999);
Ofcourse,youneedsomethingtolistenattheUDPportthere.AminimalistUDPlistenerisprovidedfortestinginthelog_udp_listener.pyfileunderchapter07/logtrigger/.Justrunit,anditprintsanyUDPpacketsreceivedtostdout.
![Page 284: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/284.jpg)
ConstructingqueriesPL/Pythondoesagoodjobofmanagingvaluespassedtopreparedqueryplans,butastandardPostgreSQLqueryplancantakeanargumentinaverylimitednumberofplaces.Sometimes,youmaywanttoconstructwholequeries,notjustpassvaluestopredefinedqueries.Forexample,youcan’thaveanargumentforatablename,orafieldname.
So,howwouldyouproceedifyouwanttoconstructaqueryfromthefunction’sargumentsandbesurethateverythingisquotedproperlyandnoSQLinjectionwouldbepossible?PL/Pythonprovidesthreefunctionstohelpyouwithproperquotingofidentifiersanddata,justforthispurpose.
Thefunctionplpy.quote_ident(nameismeantforquotingidentifiers,thatis,anythingthatnamesadatabaseobjectoritsattributelikeatable,aview,afieldname,orfunctionname.Itsurroundsthenamewithdoublequotesandtakescareofproperlyescapinganythinginsidethestringwhichwouldbreakthequoting:
hannu=#DOLANGUAGEplpythonu$$plpy.notice(plpy.quote_ident(r'5"\"'))
$$;
NOTICE:"5""\"""
CONTEXT:PL/Pythonanonymouscodeblock
DO
Andyes,5"\"isalegaltableorfieldnameinPostgreSQL;youjusthavetoalwaysquoteitifyouuseitinanystatement.
NoteTheDOsyntaxcreatesananonymousblockinsideyourdatabasesession.Itisaveryhandywaytorunsomeprocedurallanguagecodewithoutneedingtocreateafunction.
Theothertwofunctionsareforquotingliteralvalues.Thefunction,plpy.quote_literal(litvalue),isforquotingstringsandplpy.quote_nullable(value_or_none)isforquotingavalue,whichmaybeNone.Bothofthesefunctionsquotestringsinasimilarway,byenclosingtheminsinglequotes(strbecomes'str')anddoublinganysinglequotesorbackslashes:
hannu=#DOLANGUAGEplpythonu$$plpy.notice(plpy.quote_literal(r"\'"))
$$;
NOTICE:E'\\'''
CONTEXT:PL/Pythonanonymouscodeblock
DO
Theonlydifferencebetweenthesetwo,isthatplpy.quote_nullable()canalsotakeavalueNone,whichwillberenderedasastringNULLwithoutanysurroundingquotes.Theargumenttobothofthesehastobeastringoraunicodestring.IfyouwantittoworkwithavalueofanyPythontype,wrappingthevalueinstr(value)usuallyworkswell.
![Page 285: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/285.jpg)
HandlingexceptionsWithanybitofcode,youneedtomakesureyouhandlewhenerrorsoccurandyourPL/Pythonfunctionsarenotanexception.
BeforeVersion9.1ofPostgreSQL,anyerrorinanSQLquerycausedthesurroundingtransactiontoberolledback:
DOLANGUAGEplpythonu$$
plpy.execute('insertintottablevalues(1)')
plpy.execute('fail!')
$$;
ERROR:spiexceptions.SyntaxError:syntaxerroratornear"fail"
LINE1:fail!
^
QUERY:fail!
CONTEXT:Traceback(mostrecentcalllast):
PL/Pythonanonymouscodeblock,line3,in<module>
plpy.execute('fail!')
PL/Pythonanonymouscodeblock
YoucanmanuallyusetheSAVEPOINTattributestocontroltheboundariesoftherolled-backblock,atleastasfarbackasVersion8.4ofPostgreSQL.Thiswillreducetheamountofthetransactionthatisrolledback:
CREATEORREPLACEFUNCTIONsyntax_error_rollback_test()
RETURNSvoid
AS$$
plpy.execute('insertintottablevalues(1)')
try:
plpy.execute('SAVEPOINTfoo;')
plpy.execute('insertintottablevalues(2)')
plpy.execute('fail!')
except:
pass
plpy.execute('insertintottablevalues(3)')
$$LANGUAGEplpythonu;
hannu=#SELECTsyntax_error_rollback_test();
syntax_error_rollback_test
---------------------------
(1row)
WhentheSAVEPOINTfoo;commandisexecutedinPL/Python,anSQLerrorwillnotcausefullROLLBACK;butanequivalentofROLLBACKTOSAVEPOINTfoo;,so,onlytheeffectsofcommandsbetweenSAVEPOINTandtheerrorarerolledback:
hannu=#SELECT*FROMttable;
id
----
1
3
(2rows)
![Page 286: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/286.jpg)
StartinginVersion9.1,therearetwoimportantchangesinhowPostgreSQLexceptionsarehandled.IfnoSAVEPOINTorsubtransactionisused,eachinvocationofplpy.prepare()andplpy.execute()isruninitsownsubtransaction,sothatanerrorwillonlyrollbackthissubtransactionandnotallofthecurrenttransaction.Sinceusingaseparatesubtransactionforeachdatabaseinteractioninvolvesextracosts,andyoumaywanttocontrolthesubtransactionboundariesanyway,anewPythoncontextmanager,plpy.subtransaction(),isprovided.
ForanexplanationofPython’scontextmanagers,refertohttp://docs.python.org/library/stdtypes.html#context-manager-types,sothatyoucanusethewithstatementinPython2.6,ornewer,towrapagroupofdatabaseinteractionsinonesubtransactioninamorePythonicway:
hannu=#CREATETABLEtest_ex(iint);
CREATETABLE
DOLANGUAGEplpythonu$$
plpy.execute('insertintotest_exvalues(1)')
try:
withplpy.subtransaction():
plpy.execute('insertintotest_exvalues(2)')
plpy.execute('fail!')
exceptplpy.spiexceptions.SyntaxError:
pass#silentlyignore,avoiddoingthisinprod.code
plpy.execute('insertintotest_exvalues(3)')
$$;
DO
hannu=#SELECT*FROMtest_ex;
i
---
1
3
(2rows)
![Page 287: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/287.jpg)
AtomicityinPythonWhilethesubtransactionsmanagedatachangesinthePostgreSQLdatabase,thevariablesonthePythonsideofthefencelivetheirseparatelives.Pythondoesnotprovideevenasingle-statementlevelatomicity,asdemonstratedbythefollowing:
>>>a=1
>>>a[1]=a=2
Traceback(mostrecentcalllast):
File"<stdin>",line1,in<module>
TypeError:'int'objectdoesnotsupportitemassignment
>>>a
1
>>>a=a[1]=2
Traceback(mostrecentcalllast):
File"<stdin>",line1,in<module>
TypeError:'int'objectdoesnotsupportitemassignment
>>>a
2
Asyoucansee,itispossiblethatevenasinglemulti-assignmentstatementcanbeexecutedonlyhalfwaythrough.ThismeansthatyouhavetobepreparedtofullymanageyourPythondatayourself.Thefunction,plpy.subtransaction(),won’thelpyouinanywaywithmanagingPythonvariables.
![Page 288: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/288.jpg)
DebuggingPL/PythonFirst,let’sstartbystatingthatthereisnodebuggersupportwhenrunningfunctionsinPL/Python;so,itisagoodideatodevelopanddebugaPL/PythonfunctionasapurePythonfunctionasmuchaspossibleandonlydothefinalintegrationinPL/Python.Tohelpwiththis,youcanhaveasimilarenvironmentinyourPythondevelopmentenvironmentusingtheplpymodule.
JustputthemoduleinyourpathanddoimportplpybeforeyoutryrunningyourprospectivePL/PythonUfunctionsinanordinaryinterpreter.Ifyouuseanyoftheplpy.execute(...)orplpy.prepare()functions,youalsoneedtosetupadatabaseconnectionbeforeusingthesebycallingplpy.connect(<connectstring>).
Usingplpy.notice()totrackthefunction’sprogressThedebuggingtechnologyIusemostofteninanylanguage,isprintingoutintermediatevaluesasthefunctionprogresses.Iftheprintoutrollspasttoofast,youcanslowitdownbysleepingasecondortwoaftereachprint.
InstandardPython,itwouldlooklikethis:
deffact(x):
f=1
while(x>0):
f=f*x
x=x–1
print'f:%d,x:%d'%(f,x)
returnf
Itwillprintoutallintermediatevaluesforfandxasitruns:
>>>fact(3)
f:3,x:2
f:6,x:1
f:6,x:0
6
IfyoutrytouseprintinaPL/Pythonfunction,youwilldiscoverthatnothingisprinted.Infact,thereisnosinglelogicalplacetoprinttowhenrunningapluggablelanguageinsideaPostgreSQLserver.
TheclosestthingtoprintinPL/Pythonisthefunctionplpy.notice(),whichsendsaPostgreSQLNOTICEtotheclientandalsototheserverlogiflog_min_messagesissettothevaluenoticeorsmaller.
CREATEFUNCTIONfact(xint)RETURNSint
AS$$
globalx
f=1
while(x>0):
f=f*x
x=x-1
plpy.notice('f:%d,x:%d'%(f,x))
![Page 289: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/289.jpg)
returnf
$$LANGUAGEplpythonu;
Runningthisismuchmoreverbosethantheversionwithprint,becauseeachNOTICEalsoincludesinformationabouttheCONTEXTfromwheretheNOTICEcomes:
hannu=#SELECTfact(3);
NOTICE:f:3,x:2
CONTEXT:PL/Pythonfunction"fact"
NOTICE:f:6,x:1
CONTEXT:PL/Pythonfunction"fact"
NOTICE:f:6,x:0
CONTEXT:PL/Pythonfunction"fact"
fact
------
6
(1row)
TipPL/PythonUfunctionargumentsarepassedinasglobals
Ifyoucomparedthefact(x)functioninPythonandPL/Python,younoticedanextralineatthebeginningofthePL/Pythonfunction:
globalx
ThisisneededtoovercomeanimplementationdetailthatoftensurprisesPL/PythonUdevelopers;thefunctionargumentsarenotthefunctionargumentsinthePythonsenseandneitheraretheylocals.Theyarepassedinasvariablesinthefunction’sglobalscope.
UsingassertSimilartoordinaryPythonprogramming,youcanalsousePython’sassertstatementtocatchconditionswhichshouldnothappen:
CREATEORREPLACEFUNCTIONfact(xint)
RETURNSint
AS$$
globalx
assertx>=0,"argumentmustbeapositiveinteger"
f=1
while(x>0):
f=f*x
x=x-1
returnf
$$LANGUAGEplpythonu;
Totestthis,callfact()withanegativenumber:
hannu=#SELECTfact(-1);
ERROR:AssertionError:argumentmustbeapositiveinteger
CONTEXT:Traceback(mostrecentcalllast):
PL/Pythonfunction"fact",line3,in<module>
assertx>=0,"argumentmustbeapositiveinteger"
PL/Pythonfunction"fact"
![Page 290: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/290.jpg)
YouwillgetamessageaboutAssertionError,togetherwiththelocationofthefailinglinenumber.
Redirectingsys.stdoutandsys.stderrIfallthecodeyouneedtodebugisyourown,theprecedingtwotechniqueswillcovermostofyourneeds.However,whatdoyoudoincaseswhereyouusesomethirdpartylibrarieswhichprintoutdebuginformationtosys.stdoutand/orsys.stderr?
Well,inthosecasesyoucanreplacePython’ssys.stdoutandsys.stdinwithyourownpseudofileobjectthatstoreseverythingwrittenthereforlaterretrieval.Hereisapairoffunctions,thefirstofwhichdoesthecapturingofsys.stdoutoruncapturingifitiscalledwiththeargument,do_capturesettofalse,andthesecondonereturnseverythingcaptured:
CREATEORREPLACEFUNCTIONcapture_stdout(do_capturebool)
RETURNStext
AS$$
importsys
ifdo_capture:
try:
sys.stdout=GD['stdout_to_notice']
exceptKeyError:
classWriteAsNotice:
def__init__(self,old_stdout):
self.old_stdout=old_stdout
self.printed=[]
defwrite(self,s):
self.printed.append(s)
defread(self):
text=''.join(self.printed)
self.printed=[]
returntext
GD['stdout_to_notice']=WriteAsNotice(sys.stdout)
sys.stdout=GD['stdout_to_notice']
return"sys.stdoutcaptured"
else:
sys.stdout=GD['stdout_to_notice'].old_stdout
return"restoredoriginalsys.stdout"
$$LANGUAGEplpythonu;
CREATEORREPLACEFUNCTIONread_stdout()
RETURNStext
AS$$
returnGD['stdout_to_notice'].read()
$$LANGUAGEplpythonu;
Hereisasamplesessionusingtheprecedingfunctions:
hannu=#SELECTcapture_stdout(true);
capture_stdout
---------------------
sys.stdoutcaptured
(1row)
![Page 291: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/291.jpg)
DOLANGUAGEplpythonu$$
print'TESTINGsys.stdoutCAPTURING'
importpprint
pprint.pprint({'a':[1,2,3],'b':[4,5,6]})
$$;
DO
hannu=#SELECTread_stdout();
read_stdout
----------------------------------
TESTINGsys.stdoutCAPTURING+
{'a':[1,2,3],'b':[4,5,6]}+
(1row)
![Page 292: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/292.jpg)
![Page 293: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/293.jpg)
Thinkingoutofthe“SQLdatabaseserver”boxWe’llwrapupthechapteronPL/PythonwithacoupleofsamplePL/PythonUfunctionsfordoingsomethingsyouwouldnotusuallyconsiderdoinginsidethedatabasefunctionortrigger.
![Page 294: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/294.jpg)
GeneratingthumbnailswhensavingimagesOurfirstexample,usesPython’spowerfulPythonImagingLibrary(PIL)moduletogeneratethumbnailsofuploadedphotos.Foreaseofinterfacingwithvariousclientlibraries,thisprogramtakestheincomingimagedataasaBase64encodedstring:
CREATEFUNCTIONsave_image_with_thumbnail(image64text)
RETURNSint
AS$$
importImage,cStringIO
size=(64,64)#thumbnailsize
#convertbase64encodedtexttobinaryimagedata
raw_image_data=image64.decode('base64')
#createapseudo-filetoreadimagefrom
infile=cStringIO.StringIO(raw_image_data)
pil_img=Image.open(infile)
pil_img.thumbnail(size,Image.ANTIALIAS)
#createastreamtowritethethumbnailto
outfile=cStringIO.StringIO()
pil_img.save(outfile,'JPEG')
raw_thumbnail=outfile.getvalue()
#storeresultintodatabaseandreturnrowid
q=plpy.prepare('''
INSERTINTOphotos(image,thumbnail)
VALUES($1,$2)
RETURNINGid''',('bytea','bytea'))
res=plpy.execute(q,(raw_image_data,raw_thumbnail))
#returncolumnidoffirstrow
returnres[0]['id']
$$LANGUAGEplpythonu;
ThePythoncodeismoreorlessastraightrewritefromthePILtutorial,exceptthatthefilestoreadtheimagefrom,andwritethethumbnailimageto,arereplacedwithPython’sstandardfile-likeStringIOobjects.Forallthistowork,youneedtohavePILinstalledonyourdatabaseserverhost.
InDebian/Ubuntu,thiscanbedonebyrunningsudoapt-getinstallpython-imaging.OnmostmodernLinuxdistributions,analternativeistousePython’sownpackagedistributionsystembyrunningsudoeasy_installPIL.
![Page 295: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/295.jpg)
Sendingane-mailThenextsampleisafunctionforsendinge-mailsfrominsideadatabasefunction:
CREATEORREPLACEFUNCTIONsend_email(
sendertext,—sendere-mail
recipientstext,—comma-separatedlistofrecipientaddresses
subjecttext,—emailsubject
messagetext,—textofthemessage
smtp_servertext—SMTPservertouseforsending
)RETURNSvoid
AS$$
importsmtplib;
msg="From:%s\r\nTo:%s\r\nSubject:%s\r\n\r\n%s"%\
(sender,recipients,subject,message)
recipients_list=[r.strip()forr
inrecipients.split(',')]
server=smtplib.SMTP(smtp_server)
server.sendmail(sender,recipients_list,msg)
server.quit()
$$LANGUAGEplpythonu;
test=#SELECTsend_email('[email protected]','[email protected]','test
subject','message','localhost');
Thisfunctionformatsamessage(msg=""),convertsacomma-separatedTo:addressintoalistofe-mailaddresses(recipients_list=[r.strip()...),connectstoaSMTPserver,andthenpassesthemessagetotheSMTPserverfordelivery.
Tousethisfunctioninaproductionsystem,itwouldprobablyrequireabitmorecheckingontheformatsandsomeextraerrorhandling,incasesomethinggoeswrong.YoucanreadmoreaboutPython’ssmtplibathttp://docs.python.org/library/smtplib.html.
![Page 296: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/296.jpg)
ListingdirectorycontentsHereisanotherinterestingusecaseforanuntrustedlanguage.Thefunctionbelowcanlistthecontentsofadirectoryinyoursystem:
CREATEORREPLACEFUNCTIONlist_folder(
directoryVARCHAR—directorythatwillbewalked
)RETURNSSETOFVARCHAR
AS$$
importos;
file_paths=[];
#Walkthetree.
forroot,directories,filesinos.walk(directory):
forfilenameinfiles:
#Jointhetwostringsinordertoformthefullfilepath.
filepath=os.path.join(root,filename)
file_paths.append(filepath)#Addittothelist.
returnfile_paths
$$LANGUAGEplpythonu;
Letusnowtryandrunthefunction:
test_db=#SELECTlist_folder('/usr/local/pgsql/bin');
list_folder
-------------------------------------
/usr/local/pgsql/bin/clusterdb
/usr/local/pgsql/bin/createdb
/usr/local/pgsql/bin/createlang
/usr/local/pgsql/bin/createuser
/usr/local/pgsql/bin/dropdb
/usr/local/pgsql/bin/droplang
/usr/local/pgsql/bin/dropuser
/usr/local/pgsql/bin/ecpg
/usr/local/pgsql/bin/initdb
/usr/local/pgsql/bin/pg_basebackup
/usr/local/pgsql/bin/pg_config
/usr/local/pgsql/bin/pg_controldata
/usr/local/pgsql/bin/pg_ctl
/usr/local/pgsql/bin/pg_dump
/usr/local/pgsql/bin/pg_dumpall
/usr/local/pgsql/bin/pg_isready
/usr/local/pgsql/bin/pg_receivexlog
/usr/local/pgsql/bin/pg_resetxlog
/usr/local/pgsql/bin/pg_restore
/usr/local/pgsql/bin/postgres
/usr/local/pgsql/bin/postmaster
/usr/local/pgsql/bin/psql
/usr/local/pgsql/bin/reindexdb
/usr/local/pgsql/bin/vacuumdb
(24rows)
ThefunctionaboveusesthePythonosmoduleandwalksthedirectorytree,top-down.Thisfunctionwillnotwalkdownintosymboliclinksthatresolvetodirectories.Theerrors
![Page 297: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/297.jpg)
areignoredbydefault.YoucanlearnmoreabouthowPython’sos.walk()behavesinPython2’s(sincethatiswhattheexampleuses)documentationherehttps://docs.python.org/2/library/os.html.
![Page 298: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/298.jpg)
![Page 299: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/299.jpg)
SummaryInthischapter,wesawthatitisrelativelyeasytodothingswaybeyondwhatasimpleSQLdatabaseservernormallysupports;thankstoitspluggablelanguage’ssupport.
Infact,youcandoalmostanythinginthePostgreSQLserverthatyoucoulddoinanyotherapplicationserver.Hopefully,thischapterjustscratchedthesurfaceofwhatcanbedoneinsideaPostgreSQLserver.
Inthenextchapter,wewilllearnaboutwritingPostgreSQL’smoreadvancedfunctionsinC.ThiswillgiveyoudeeperaccesstoPostgreSQL,allowingyoutouseaPostgreSQLserverformuchmorepowerfulthings.
![Page 300: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/300.jpg)
![Page 301: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/301.jpg)
Chapter9.WritingAdvancedFunctionsinCInthepreviouschapter,weintroducedyoutothepossibilitiesofuntrustedpluggablelanguagesbeingavailabletoaPostgreSQLdevelopertoachievethingsimpossibleinmostotherrelationaldatabases.
Whileusingapluggablescriptinglanguageisenoughforalargeclassofproblems,therearetwomaincategories,wheretheymayfallshort:performanceanddepthoffunctionality.
MostscriptinglanguagesarequiteabitslowerthanoptimizedCcodewhenexecutingthesamealgorithms.Forasinglefunction,thismaynotbethecasebecausecommonthingssuchasdictionarylookupsorstringmatchinghavebeenoptimizedsowellovertheyears.Butingeneral,Ccodewillbefasterthanscriptedcode.Also,incaseswherethefunctioniscalledmillionsoftimesperquery,theoverheadofactuallycallingthefunctionandconvertingtheargumentsandreturnvaluestoandfromthescriptinglanguagecounterpartscanbeasignificantportionoftheruntime.
ThesecondpotentialproblemwithpluggablelanguagesisthatmostofthemjustdonotsupportthefullrangeofpossibilitiesthatareprovidedbyPostgreSQL.ThereareafewthingsthatsimplycannotbecodedinanythingelsebutC.Forexample,whenyoudefineacompletelynewtypeforPostgreSQL,thetypeinputandoutputfunctions,whichconvertthetype’stextrepresentationtointernalrepresentationandback,needtohandlePostgreSQL’spseudotypecstring.ThisisbasicallytheCstringorazero-terminatedstring.ReturningcstringissimplynotsupportedbyanyofthePLlanguagesincludedinthecoredistribution,atleastnotasofPostgreSQLVersion9.3.ThePLlanguagesalsodonotsupportpseudotypesANYELEMENT,ANYARRAYandespecially“any”VARIADIC.
Inthefollowingsections,wewillgostep-by-stepthroughwritingsomePostgreSQLextensionfunctionsinincreasingcomplexityinC.
Wewillstartfromthesimplestadd2argumentsfunctionwhichisquitesimilartotheoneinPostgreSQLmanual,butwewillpresentthematerialinadifferentorder.So,settingupthebuildenvironmentcomesearlyenoughsothatyoucanfollowushands-onfromtheverybeginning.
Afterthat,wewilldescribesomeimportantthingstobeawareofwhendesigningandwritingcodethatrunsinsidetheserver,suchasmemorymanagement,executingqueries,andretrievingresults.
AsthetopicofwritingC-languagePostgreSQLfunctionscanbequitelargeandourspaceforthistopicislimited,wewilloccasionallyskipsomeofthedetailsandreferyoutothePostgreSQLmanualforextrainformationandspecifications.WearealsolimitingthissectiontoreferencePostgreSQL9.3.Whilemostthingswillworkperfectlyfineacrossversions,therearereferencestopathsthatwillbespecifictoaversion.
![Page 302: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/302.jpg)
ThesimplestCfunction–return(a+b)Let’sstartwithasimplefunction,whichtakestwointegerargumentsandreturnsthesumofthese.Wefirstpresentthesourcecodeandthenwillmoveontoshowyouhowtocompileit,loaditintoPostgreSQL,andthenuseitasanynativefunction.
![Page 303: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/303.jpg)
add_func.cACsourcefileimplementingadd(int,int)returnsintfunctionlookslikethefollowingcodesnippet:
#include"postgres.h"
#include"fmgr.h"
PG_MODULE_MAGIC;
PG_FUNCTION_INFO_V1(add_ab);
Datum
add_ab(PG_FUNCTION_ARGS)
{
int32arg_a=PG_GETARG_INT32(0);
int32arg_b=PG_GETARG_INT32(1);
PG_RETURN_INT32(arg_a+arg_b);
}
Let’sgooverthecodeexplainingtheuseofeachsegment:
#include"postgres.h":ThisincludesmostofthebasicdefinitionsanddeclarationsneededforwritinganyCcodeforrunninginPostgreSQL.#include"fmgr.h":ThisincludesthedefinitionsforPG_*macrosusedinthiscode.PG_MODULE_MAGIC;:Thisisa“magicblock”definedinfmgr.h.ThisblockisusedbytheservertoensurethatitdoesnotloadcodecompiledbyadifferentversionofPostgreSQL,potentiallycrashingtheserver.ItwasintroducedinVersion8.2ofPostgreSQL.IfyoureallyneedtowritecodewhichcanalsobecompiledforPostgreSQLversionsbefore8.2youneedtoputthisbetween#ifdefPG_MODULE_MAGIC/#endif.YouseethisalotinsamplesavailableontheInternet,butyouprobablywillnotneedtodotheifdefforanynewcode.Thelatestpre-8.2Versionbecameofficiallyobsolete(thatisunsupported)inNovember2010,andeven8.2communitysupportendedinDecember2011.PG_FUNCTION_INFO_V1(add_ab);:ThisintroducesthefunctiontoPostgreSQLasVersion1callingaconventionfunction.Withoutthisline,itwillbetreatedasanold-styleVersion0function.(SeetheinformationboxfollowingtheVersion0reference.)Datum:ThisisthereturntypeofaC-languagePostgreSQLfunction.add_ab(PG_FUNCTION_ARGS):Thefunctionnameisadd_abandtherestareitsarguments.ThePG_FUNCTION_ARGSdefinitioncanrepresentanynumberofargumentsandhastobepresent,evenforafunctiontakingnoarguments.int32arg_a=PG_GETARG_INT32(0);:YouneedtousethePG_GETARG_INT32(<argnr>)macro(orcorrespondingPG_GETARG_xxx(<argnr>)forotherargumenttypes)togettheargumentvalue.Theargumentsarenumberedstartingfrom0.int32arg_b=PG_GETARG_INT32(1);:Similartothepreviousdescription.PG_RETURN_INT32(arg_a+arg_b);:Finally,youusethePG_RETURN_<rettype>(<retvalue>)macrotobuildandreturnasuitablereturnvalue.
![Page 304: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/304.jpg)
Youcouldalsohavewrittenthewholefunctionbodyasthefollowingcode:
PG_RETURN_INT32(PG_GETARG_INT32(0)+PG_GETARG_INT32(1));
But,itismuchmorereadableaswritten,andmostlikelyagoodoptimizingCcompilerwillcompilebothintoanequivalentlyfastcode.
Mostcompilerswillissueawarningmessageas:warning:nopreviousprototypefor'add_ab'fortheprecedingcode,soitisagoodideatoalsoputaprototypeforthefunctioninthefile:
Datumadd_ab(PG_FUNCTION_ARGS);
Theusualplacetoputit,isjustbeforethecodelinePG_FUNCTION_INFO_V1(add_ab);.
NoteWhiletheprototypeisnotstrictlyrequired,itenablesmuchcleanercompileswithnowarnings.
Version0callconventionsThereisanevensimplerwaytowritePostgreSQLfunctionsinC,calledtheVersion0callingconventions.Theprecedinga+bfunctioncanbewrittenasthefollowingcode:
intadd_ab(intarg_a,intarg_b)
{
returnarg_a+arg_b;
}
Version0isshorterforverysimplefunctions,butitisseverelylimitedformostotherusages—youcan’tdoevensomebasicthingssuchascheckingifapassbyvalueargumentisnull,returnasetofvalues,orwriteaggregatefunctions.Also,Version0doesnotautomaticallytakecareofhidingmostdifferencesofpassbyvalueandpassbyreferencetypesthatVersion1does.Therefore,itisbettertojustwriteallyourfunctionsusingVersion1callingconventionsandignorethefactthatVersion0evenexists.
Fromthispointforward,weareonlygoingtodiscussVersion1callingconventionsforaCfunction.
NoteIncaseyouareinterested,thereissomemoreinformationonVersion0athttp://www.postgresql.org/docs/current/static/xfunc-c.html#AEN50495,inthesectiontitled35.9.3.Version0CallingConventions.
![Page 305: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/305.jpg)
MakefileThenextstepiscompilingandlinkingthe.csourcefileintoaformthatcanbeloadedintothePostgreSQLserver.ThiscanallbedoneasaseriesofcommandsdefinedinaMakefilefunction.
ThePostgreSQLmanualhasacompletesectionaboutwhichflagsandincludedpathsyoushouldpassoneachofthesupportedplatforms,andhowtodeterminecorrectpathsforincludingfilesandlibraries.
Fortunately,allofthisisalsoautomatednicelyfordevelopersviathePostgreSQLextensionbuildinginfrastructure—orPGXSforshort—whichmakesthisreallyeasyformostmodules.
NoteDependingonwhichversionofPostgreSQLyouhaveinstalled,youmayneedtoaddthedevelopmentpackageforyourplatform.Theseareusuallythe-devor-develpackages.
Now,let’screateourMakefilefunction.Itwilllooklikethefollowingcode:
MODULES=add_func
PG_CONFIG=pg_config
PGXS:=$(shell$(PG_CONFIG)--pgxs)
include$(PGXS)
Andyoucancompileandlinkthemodulebysimplyrunningmake:
$make
gcc…-c-oadd_func.oadd_func.c
gcc…-oadd_func.soadd_func.o
rmadd_func.o
Here,“…”standsforquitesomeamountofflags,includes,andlibrariesaddedbyPGXS.
ThisproducesadynamicallyloadablemoduleinthecurrentdirectorywhichcanbeuseddirectlybyPostgreSQL,ifyourserverhasaccesstothisdirectory,whichmaybethecaseonadevelopmentserver.
Fora“standard”server,asinstalledbyyourpackagemanagementsystem,youwillneedtoputthemoduleinastandardplace.ThiscanbedoneusingthePGXSaswell.
Yousimplyexecutesudomakeinstallandeverythingwillbecopiedtotherightplace,$sudomakeinstall:
[sudo]passwordforhannu:
/bin/mkdir-p'/usr/lib/postgresql/9.3/lib'
/bin/sh
/usr/lib/postgresql/9.3/lib/pgxs/src/makefiles/../../config/install-sh-c-
m755add_func.so'/usr/lib/postgresql/9.3/lib/'
![Page 306: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/306.jpg)
CREATEFUNCTIONadd(int,int)Youarejustonestepawayfrombeingabletousethisfunctioninyourdatabase.YoujustneedtointroducethemoduleyoujustcompiledtoaPostgreSQLdatabaseusingtheCREATEFUNCTIONstatement.
Ifyoufollowedthesamplesuptothispoint,thefollowingstatementisallthatisneeded,alongwithadjustingthepathappropriatelytowherePostgreSQLisinstalledonyourserver:
hannu=#CREATEFUNCTIONadd(int,int)
hannu-#RETURNSint
hannu-#AS'/usr/lib/postgresql/9.3/lib/add_func','add_ab_null'
hannu-#LANGUAGECSTRICT;
CREATEFUNCTION
Andvoilá—youhavecreatedyourfirstPostgreSQLC-languageextensionfunction:
hannu=#selectadd(1,2);
add
-----
3
(1row)
![Page 307: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/307.jpg)
add_func.sql.inWhilewhatwejustcoveredisallthatisneededtohaveaCfunctioninyourdatabase,itisoftenmoreconvenienttoputtheprecedingCREATEFUNCTIONstatementinanSQLfile.
YouusuallydonotknowthefinalpathofwherePostgreSQLisinstalledwhenwritingthecode,especiallyinthelightofrunningonmultipleversionsofPostgreSQLand/oronmultipleoperationsystems.Herealso,PGXScanhelp.
Youneedtowriteafilecalledadd_funcs.sql.inasfollows:
CREATEFUNCTIONadd(int,int)RETURNSint
AS'MODULE_PATHNAME','add_ab'
LANGUAGECSTRICT;
ThenaddthefollowinglineinyourMakefilefunctionrightaftertheMODULES=…line:
DATA_built=add_funcs.sql
Now,whenrunningmake,theadd_funcs.sql.iniscompiledintoafileadd_funcs.sqlwithMODULE_PATHNAMEreplacedbytherealpathwherethemodulewillbeinstalled.
[add_func]$make
sed's,MODULE_PATHNAME,$libdir/add_func,g'add_func.sql.in>add_func.sql
Also,sudomakeinstallwillcopythegenerated.sqlfileintothedirectorywithother.sqlfilesforextensions,asshown:
$sudomakeinstall
/usr/bin/mkdir-p'/usr/lib/postgresql/9.3/share/contrib'
/usr/bin/mkdir-p'/usr/lib/postgresql/9.3/lib'
/bin/sh
/usr/lib/postgresql/9.3/lib/pgxs/src/makefiles/../../config/install-sh-c-
m644add_func.sql'/usr/lib/postgresql/9.3/share/contrib/'
/bin/sh
/usr/lib/postgresql/9.3/lib/pgxs/src/makefiles/../../config/install-sh-c-
m755add_func.so'/usr/lib/postgresql/9.3/lib/'
Afterthis,theintroductionofyourCfunctionstoaPostgreSQLdatabaseisassimpleashannu=#\i/usr/lib/postgresql/9.3/share/contrib/add_func.sql:
CREATEFUNCTION
Thepath/usr/lib/postgresql/9.3/share/contrib/toadd_funcs.sqlneedstobelookedupfromtheoutputofthemakeinstallcommand.
NoteThereisamuchcleanerwaytopackageupyourcodecalledExtensionswhereyoudon’tneedtolookupforanypathsandtheprecedingstepwouldjustbeasfollows:CREATEEXTENSIONchap8_add;
Butitisrelativelymorecomplextosetup,sowearenotexplainingithere.Chapter13,PublishingYourCodeasPostgreSQLExtensionsdedicatedtoextensionsappearslaterinthisbook.
![Page 308: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/308.jpg)
SummaryforwritingaCfunctionWritingaCfunctionusedinPostgreSQLisastraightforwardprocess:
1. WritetheCcodeinmodulename.c.2. WritetheSQLcodeforCREATEFUNCTIONinmodulename.sql.in.3. WriteaMakefilefunction.4. RunmaketocompileaCfileandgeneratemodulename.sql.5. Runsudomakeinstalltoinstallthegeneratedfiles.6. Runthegeneratedmodulename.sqlinyourtargetdatabase:
hannu#\i/<path>/modulename.sql
NoteYoumustruntheSQLcodeinanydatabaseyouwanttouseyourfunction.Ifyouwantallyournewdatabasestohaveaccesstoyournewlygeneratedfunction,addthefunctiontoyourtemplatedatabasebyrunningthemodulename.sqlfileindatabasetemplate1oranyotherdatabaseyouareexplicitlyspecifyingintheCREATEDATABASEcommand.
Youmayhavenoticedthatwhilecreatingthefunction,youspecifiedthenameoftheloadableobjectfileandthenameoftheCfunction.WhentheSQLfunctioniscalledforthefirsttime,thedynamicloaderloadstheobjectfileinmemory.Ifyouwouldlikesomeobjectfilestobepreloadedatserverstartup,youshouldspecifytheminthePostgreSQLshared_preload_librariesconfigurationparameter.
![Page 309: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/309.jpg)
![Page 310: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/310.jpg)
Addingfunctionalitytoadd(int,int)Whileourfunctionworks,itaddsnothingintheprecedingcodejustusingSELECTA+B.ButfunctionswritteninCarecapableofsomuchmore.Solet’sstartaddingsomemorefunctionalitytoourfunction.
![Page 311: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/311.jpg)
SmarthandlingofNULLargumentsNoticetheuseofaSTRICTkeywordintheCREATEFUNCTIONadd(inta,intb)inthepreviouslymentionedcode.ThismeansthatthefunctionwillnotbecalledifanyoftheargumentsareNULL,butinsteadNULLisreturnedstraightaway.ThisissimilartohowmostPostgreSQLoperatorswork,includingthe+signwhenaddingtwointegers—ifanyoftheargumentsareNULLthecompleteresultisNULLaswell.
Next,wewillextendourfunctiontobesmarteraboutNULLinputsandactlikePostgreSQL’ssum()aggregatefunction,whichignoresNULLvaluesininputsandstillproducesthesumofallnon-nullvalues.
Forthis,weneedtodotwothings:
MakesurethatthefunctioniscalledwheneitheroftheargumentsareNULL.HandleNULLargumentsbyeffectivelyconvertingaNULLargumentto0andreturningNULLonlyincaseswherebothargumentsarenull.
Thefirstoneiseasy—justleaveouttheSTRICTkeywordwhendeclaringthefunction.ThelatteronealsoseemseasyaswejustleaveoutSTRICTandletthefunctionexecute.Forafunctionwithintarguments,thisalmostseemstodothetrick.AllNULLvaluesshowupas0s,andtheonlythingyoumisswillbereturningNULLifbothargumentsareNULL.
Unfortunately,thisonlyworksbycoincidenceandisnotguaranteedtoworkinfutureversions.Worsestill,ifyoudoitthesamewayforpassbyreferencetypes,itwillcausePostgreSQLtocrashonnullpointerreferences.
Next,weshowyouhowtodoitproperly.Weneednowtodotwothings:recordifwehaveanynon-nullvaluesandaddallthenon-nullvalueswesee:
PG_FUNCTION_INFO_V1(add_ab_null);
Datum
add_ab_null(PG_FUNCTION_ARGS)
{
int32not_null=0;
int32sum=0;
if(!PG_ARGISNULL(0)){
sum+=PG_GETARG_INT32(0);
not_null=1;
}
if(!PG_ARGISNULL(1)){
sum+=PG_GETARG_INT32(1);
not_null=1;
}
if(not_null){
PG_RETURN_INT32(sum);
}
PG_RETURN_NULL();
}
Thisindeeddoeswhatweneed:
hannu=#CREATEFUNCTIONadd(int,int)RETURNSint
![Page 312: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/312.jpg)
AS'$libdir/add_func','add_ab_null'
LANGUAGEC;
CREATEFUNCTION
hannu=#SELECTadd(NULL,NULL)asmust_be_null,add(NULL,1)as
must_be_one;
-[RECORD1]+--
must_be_null|
must_be_one|1
AchievingthesameresultusingstandardPostgreSQLstatements,functions,andoperatorswouldbemuchmoreverbose:
hannu=#SELECT(casewhen(aisnull)and(bisnull)
hannu(#thennull
hannu(#elsecoalesce(a,0)+coalesce(b,0)
hannu(#end)
hannu-#FROM(select1::intasa,null::intasb)s;
-[RECORD1]
case|1
Inadditiontorestructuringthecode,wealsointroducedtwonewmacrosPG_ARGISNULL(<argnr>)forcheckingiftheargument<argnr>isNULLandPG_RETURN_NULL()forreturningNULLfromafunction.
NotePG_RETURN_NULL()isdifferentfromPG_RETURN_VOID().Thelatterisforusingfunctionswhicharedeclaredtoreturnpseudotypevoidorinotherwords,nottoreturnanything.
![Page 313: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/313.jpg)
WorkingwithanynumberofargumentsAftertherewritetohandleNULLvalues,itseemsthatwithjustalittlemoreeffort,wecouldmakeitworkwithanynumberofarguments.Justmovethefollowingcodeinsidethefor(;;)cycleovertheargumentsandwearedone:
if(!PG_ARGISNULL(<N>)){
sum+=PG_GETARG_INT32(<N>);
not_null=1;
}
Actually,makingthecodeuseanarrayinsteadofasimpletypeisnotthatsimpleafterall.Tomakethingsmoredifficult,thereisnoinformationorsamplecodeonhowtoworkwitharraysintheofficialPostgreSQLmanualforC-languageextensionfunctions.Thelinebetween“supported”and“unsupported”whenwritingC-languagefunctionsisquiteblurred,andtheprogrammerdoingsoisexpectedtobeabletofiguresomethingsoutindependently.
ThebrightsideisthatthefriendlyfolksatthePostgreSQLmailinglistsareusuallyhappytohelpyououtiftheyseethatyourquestionisaseriousoneandthatyouhavemadesomeefforttofigureoutthebasicstuffyourself.
Toseehowargumentsofarraytypesarehandled,youhavetostartdiggingaroundontheInternetand/orinthebackendcode.Oneplacewhereyoucanfindasampleisthecontrib/hstore/moduleinthePostgreSQLsourcecode.ThecontribmodulesareagreatreferenceforexamplesofofficiallysupportedextensionmodulesfromPostgreSQL.
Thoughthecodetheredoesnotdoexactlywhatweneed—itworksontext[]andnotint[]—itiscloseenoughtofigureoutwhatisneeded,bysupplyingthebasicstructureofarrayhandlingandsampleusageofsomeutilitymacrosandfunctions.
Aftersomediggingaroundinthebackendcodeanddoingsomewebsearches,itisnotveryhardtocomeupwithacodeforintegerarrays.
So,hereistheCcodeforafunctionwhichsumsallnon-nullelementsinitsargumentarray.Thecodeshouldbeaddedtoadd_func.c:
#include"utils/array.h"//arrayutilityfunctionsandmacros
#include"catalog/pg_type.h"//forINT4OID
PG_MODULE_MAGIC;
Datumadd_int32_array(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(add_int32_array);
Datum
add_int32_array(PG_FUNCTION_ARGS)
{
ArrayType*input_array;
int32sum=0;
![Page 314: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/314.jpg)
boolnot_null=false;
//variablesfor"deconstructed"array
Datum*datums;
bool*nulls;
intcount;
//forloopcounter
inti;
input_array=PG_GETARG_ARRAYTYPE_P(0);
//checkthatwedoindeedhaveaone-dimensionalintarray
Assert(ARR_ELEMTYPE(input_array)==INT4OID);
if(ARR_NDIM(input_array)>1)
ereport(ERROR,
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
errmsg("1-dimensionalarrayneeded")));
deconstruct_array(input_array,//one-dimensionalarray
INT4OID,//ofintegers
4,//sizeofintegerinbytes
true,//int4ispass-byvalue
'i',//alignmenttypeis'i'
&datums,&nulls,&count);//resulthere
for(i=0;i<count;i++){
//firstcheckandignorenullelements
if(nulls[i])
continue;
//accumulateandremembertherewerenon-nullvalues
sum+=DatumGetInt32(datums[i]);
not_null=true;
}
if(not_null)
PG_RETURN_INT32(sum);
PG_RETURN_NULL();
}
So,whatnewthingsareneededforhandlingarraytypesasarguments?First,youneedtoincludedefinitionsforarrayutilityfunctions:
#include"utils/array.h"
Next,youneedapointertoyourarray:
ArrayType*input_array;
Noticethatthereisnospecificarray-of-integerstypebutjustagenericArrayType,whichisusedforanyarray.
Toinitializethearrayfromthefirstargument,youuseanalreadyfamiliarlookingmacro:
input_array=PG_GETARG_ARRAYTYPE_P(0);
ExceptthatinsteadofreturninganINT32value,itreturnsanarraypointerARRAYTYPE_P.
![Page 315: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/315.jpg)
Aftergettingthearraypointer,weperformacoupleofchecks:
Assert(ARR_ELEMTYPE(input_array)==INT4OID);
Weassertthattheelementtypeofreturnedarrayisindeedaninteger.(TherearesomeinconsistenciesinPostgreSQLcodeastheplainintegertypecanbecalledeitherint32orint4dependingonwherethedefinitioncomesfrom.Buttheybothmeanthesamething,exceptthatoneisbasedonthelengthinbitsandtheotherinbytes.)
Thetypecheckisanassertandnotaplainruntimecheck,becauseafteryouhaveyourSQLdefinitionpartofthefunctioninplace,PostgreSQLitselftakescarenottocallthefunctionwithanyothertypeofarray.
Thesecondcheckisforcheckingthattheargumentisreallyaone-dimensionalarray(PostgreSQLarrayscanhave1tondimensionsandstillbeofthesametype),asshown:
if(ARR_NDIM(input_array)>1)
ereport(ERROR,
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
errmsg("useonlyone-dimensionalarrays!")));
Iftheinputarrayhasmorethanonedimension,weraiseanerror.(WewilldiscussPostgreSQL’serrorreportinginClater,initsownsection.)
Ifyouneedtoworkonarraysofanarbitrarynumberofdimensions,takealookatthesourcecodeoftheunnest()SQLfunctionwhichturnsanyarrayintoasetofarrayelements.
NoteThecodeislocatedinthebackend/utils/adt/arrayfuncs.cfileintheCfunctionarray_unnest(...).
Afterwehavedonebasicsanitycheckingontheargument,wearereadytostartprocessingthearray.AsaPostgreSQLarraycanbequiteacomplexbeast,withmultipledimensionsandarrayelementsstartingatanarbitraryindex,itiseasiesttouseaready-madeutilityfunctionformosttasks.So,hereweusethedeconstruct_array(...)functiontoextractaPostgreSQLarrayinthreeseparateCvariables:
Datum*datums;
bool*nulls;
intcount;
Thedatumspointerwillbesettopointtoanarrayfilledwithactualelements.The*nullspointerwillcontainapointertoanarrayofBooleans,whichwillbetrueifthecorrespondingarrayelementwasNULL,andcountwillbesettothenumberofelementsfoundinthearray,asshown:
deconstruct_array(input_array,//one-dimensionalarray
INT4OID,//ofintegers
4,//sizeofintegerinbytes
true,//int4ispass-byvalue
'i',//alignmenttypeis'i'
&datums,&nulls,&count);//resulthere
![Page 316: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/316.jpg)
Theotherargumentsareasfollows:
input_array:ThisisthepointertothePostgreSQLarrayINT4OID:Thisisthetypeofarrayelementelementsize:Thisisthein-memorysizeoftheelementtypetrue:Thisistheelementpass-by-valueelementalignmentid
ThetypeOIDforint4(=23)isalreadyconvenientlydefinedasINT4OID.Theothers,youjusthavetolookup.
Theeasiestwaytogetthevaluesfortype,size,passbyvalue,andalignmentistoquerythesefromthedatabase:
c_samples=#selectoid,typlen,typbyval,typalignfrompg_type
c_samples-#wheretypname='int4';
-[RECORD1]
oid|23
typlen|4
typbyval|t
typalign|i
Afterthecalltodeconstruct_array(...)therestiseasy—justiterateoverthevalueandnullarraysandaccumulatethesum:
for(i=0;i<count;i++){
//firstcheckandignorenullelements
if(nulls[i])
continue;
//accumulateandremembertherewerenon-nullvalues
sum+=DatumGetInt32(datums[i]);
not_null=true;
}
TheonlyPostgreSQL-specificthinghereistheuseoftheDatumGetInt32(<datum>)macroforconvertingtheDatumtointeger.TheDatumGetInt32(<datum>)macroperformsnocheckingofitsargumenttoverifythatitisindeedaninteger(ifyouremember,thisisC,sonotypeofinfoisavailableinthedataitself),butusingtheDatumGet*()macrohelpsustomakethecompilerhappy.
Wearealmostdonehere,asreturningthesum(orNULLincaseallelementswereNULLvalues)isexactlythesameasinourpreviousfunction.
WhilethisisallfromtheCside,westillneedtoteachPostgreSQLaboutthisnewfunction.Thesimplestwayistodeclareafunctionwhichtakesanint[]argument:
CREATEORREPLACEFUNCTIONadd_arr(int[])RETURNSint
AS'$libdir/add_func','add_int32_array'
LANGUAGECSTRICT;
Itworksfineforanyintegerarrayyoupassitfor:
hannu=#SELECTadd_arr('{1,2,3,4,5,6,7,8,9}');
-[RECORD1]
![Page 317: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/317.jpg)
add_arr|45
hannu=#SELECTadd_arr(ARRAY[1,2,NULL]);
-[RECORD1]
add_arr|3
hannu=#SELECTadd_arr(ARRAY[NULL::int]);
-[RECORD1]
add_arr|
Itevendetectsmultidimensionalarraysanderrorsoutifitispassedone:
hannu=#selectadd_arr('{{1,2,3},{4,5,6}}');
ERROR:1-dimensionalarrayneeded
Whatifwewanttouseitthesamewayasourtwo-argumentadd(a,b)function?
SinceVersion8.4ofPostgreSQL,itispossibleusingsupportforVARIADICfunctions,orfunctionstakingavariablenumberofarguments.
Createthefunctionasfollows:
CREATEORREPLACEFUNCTIONadd(VARIADICaint[])RETURNSint
AS'$libdir/add_func','add_int32_array'
LANGUAGECSTRICT;
Thepreviouscallstoadd_arr()canberewrittenas:
hannu=#selectadd(1,2,3,4,5,6,7,8,9);
-[RECORD1]
add|45
hannu=#selectadd(NULL);
-[RECORD1]
add|
hannu=#selectadd(1,2,NULL);
-[RECORD1]
add|3
Noticethatyoucan’teasilygetERROR:1-dimensionalarrayneededasVARIADICalwaysconstructsaone-dimensionalarrayfromthearguments.
Theonlythingmissingisthatyoucan’thavePostgreSQL’sfunctionoverloadingmechanismtodistinguishbetweenadd(aint[])andadd(VARIADICaint[])—yousimplycan’tdeclarebothoftheseatthesametimebecauseforPostgreSQLtheyarethesamefunctionwithonlytheinitialargumentdetectiondonedifferently.Thatiswhythearrayversionofthefunctionwasnamedadd_arr.IncaseyouneedtocalloneVARIADICfunctionfromanother,thereisaway.YoucancalltheVARIADICversionwithanargumentofthearraytypebyprefixingtheargumentwithVARIADIConthecallsideashannu=#selectadd(ARRAY[1,2,NULL]);:
ERROR:functionadd(integer[])doesnotexist
LINE1:selectadd(ARRAY[1,2,NULL]);
HINT:Nofunctionmatchesthegivennameandargumenttypes.Youmight
needtoaddexplicittypecasts.
![Page 318: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/318.jpg)
hannu=#selectadd(VARIADICARRAY[1,2,NULL]);
-[RECORD1]
add|3
Youcanevensmuggleinamultidimensionalarray:
hannu=#selectadd(VARIADIC'{{1,2,3},{4,5,6}}');
ERROR:1-dimensionalarrayneeded
Thiscallingconventionalsomeans,thatevenwhenyoucreateVARIADICfunctions,youneedtocheckthearraydimensions.
![Page 319: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/319.jpg)
![Page 320: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/320.jpg)
BasicguidelinesforwritingCcodeAfterhavingwrittenourfirstfunction,let’slookatsomeofthebasiccodingguidelinesforPostgreSQLbackendcoding.
![Page 321: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/321.jpg)
MemoryallocationOneoftheplacesyouhavetobeextracarefulwhenwritingCcodeingeneralismemorymanagement.Foranynon-trivialCprogram,youhavetocarefullydesignandimplementyourprograms,sothatallyourallocatedmemoryisfreedwhenyouaredonewithit,orelseyouwill“leakmemory”andwillprobablyrunoutofmemoryatsomepoint.
AsthisisalsoacommonconcernforPostgreSQL,ithasitsownsolution—memorycontexts.Let’stakeadeeperdiveintothem.
Usepalloc()andpfree()MostPostgreSQLmemoryallocationsaredoneusingPostgreSQL’smemoryallocationfunctionpalloc()andnotstandardCmalloc().Whatmakespalloc()specialisthatitallocatesthememoryinthecurrentcontextandthewholememoryisfreedinonegowhenthecontextisdestroyed.Forexample,thetransactioncontext—whichisthecurrentcontextwhenauser-definedfunctioniscalled—isdestroyedandmemoryallocatedisfreedattheendoftransaction.Thismeansthatmosttimestheprogrammersdonotneedtoworryabouttrackingpalloc()allocatedmemoryandfreeingit.
Itisalsoeasytocreateyourownmemorycontextsifyouhavesomememoryallocationneedswithdifferentlifespans.Forexample,thefunctionsforreturningasetofrows(describedinfurtherdetaillaterinthischapter)haveastructurepassedtothem,whereoneofthemembersisreservedforapointertoatemporarycontextspecificallyforkeepingafunction-levelmemorycontext.
Zero-fillthestructuresAlwaysmakesurethatnewstructuresarezero-filled,eitherbyusingmemsetafterallocatingthemorusingpalloc0().
PostgreSQLsometimesreliesonlogicallyequivalentdataitemsbeingalsothesameforbit-wisecomparisons.Evenwhenyousetalltheitemsinastructure,itispossiblethatsomealignmentissuesleavegarbageintheareasbetweenstructureelementsifanyalignmentpaddingwasdonebythecompiler.
Ifyoudon’tdothis,thenhashindexesandhashjoinsofPostgreSQLmayworkinefficientlyorevengivewrongresults.Theplanner’sconstantcomparisonsmayalsobewrongifconstantswhicharelogicallythesamearenotthesameviabit-wiseequality,resultinginundesirableplanningresults.
IncludefilesMostofPostgreSQLinternaltypesaredeclaredinpostgres.h,andthefunctionmanagerinterfaces(PG_MODULE_MAGIC,PG_FUNCTION_INFO_V1,PG_FUNCTION_ARGS,PG_GETARG_<type>,PG_RETURN_<type>,andsoon)areinfmgr.h.Therefore,allyourCextensionmodulesneedtoincludeatleastthesetwofiles.Itisagoodhabittoincludepostgres.hfirstasitgivesyourcodethebestportabilityby(re)definingsomeplatformdependentconstantsandmacros.Includingpostgres.halsoincludesutils/elog.handutils/palloc.hforyou.
![Page 322: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/322.jpg)
Thereareotherusefulincludefilesintheutils/subdirectorywhichyoualsomayneedtoincludelikeutils/array.husedinthelastexample.
Anotheroftenusedincludedirectoryiscatalog/whichgivesyoutheinitial(andbyconventionconstant)partofmostsystemtables,soyoudonotneedtolookupthingsliketypeidentifierfortheint4datatype,butcanuseitspredefinedvalueINT4OIDdirectly.
Thevaluesincatalog/pg_*includefilesarealwaysinsyncwithwhatgetsputintothedatabasecatalogsbyvirtueofbeingthedefinitionofthestructureandcontentsofthesystemcatalogtables.The.bkifilesusedwhentheinitdbcommandsetsupanewemptydatabaseclusteraregeneratedfromthese.hfilesbythegenbki.plscript.
PublicsymbolnamesItistheprogrammer’stasktomakesurethatanysymbolnamesvisibleinthe.sofilesdonotconflictwiththosealreadypresentinthePostgreSQLbackend,includingthoseusedbyotherdynamicallyloadedlibraries.Youwillhavetorenameyourfunctionsorvariablesifyougetmessagestothiseffect.Picksufficientlydistinctivenamesforfunctionstoavoidanysuchproblems.Avoidshortnamesthatmightbeasourceofpotentialconflict.Thismaybeabiggerproblemiftheconflictscomefromathird-partylibraryyourcodeisusing.SotestearlyinthedevelopmentifyoucanlinkalltheplannedlibrariestoyourPostgreSQLextensionmodule.
![Page 323: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/323.jpg)
![Page 324: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/324.jpg)
ErrorreportingfromCfunctionsOnethingwhichwentunexplainedintheprevioussamplewastheerrorreportingpart:
if(ARR_NDIM(input_array)>1)
ereport(ERROR,
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
errmsg("useonlyone-dimensionalarrays!")));
Allerrorreportingandotheroff-channelmessaginginPostgreSQLisdoneusingtheereport(<errorlevel>,rest)macrowhosemainpurposeistomakeerrorreportinglooklikeafunctioncall.
Theonlyparameterwhichisprocesseddirectlybyereport()isthefirstargumenterrorlevel,orperhapsmoreexactly,theseveritylevelorloglevel.Alltheotherparametersareactuallyfunctioncallswhichindependentlygenerateandstoreadditionalerrorinformationinthesystemtobewrittentologsand/orbesenttotheclient.Beingplacedintheargumentlistoftheereport()makessurethattheseotherfunctionsarecalledbeforetheactualerrorisreported.ThisisimportantbecauseinthecaseofanerrorlevelbeingERROR,FATAL,orPANICthesystemcleansupallcurrenttransactionstatesandanythingaftertheereport()callwillnevergetachancetorun.Errorstatestheendofthetransaction.
IncaseofERROR,thesystemisreturnedtoacleanstateanditwillbereadytoacceptnewcommands.
ErrorlevelFATALwillcleanupthebackendandexitthecurrentsession.
PANICisthemostdestructiveoneanditwillnotonlyendthecurrentconnection,butwillalsocauseallotherconnectionstobeterminated.PANICmeansthatsharedstate(sharedmemory)ispotentiallycorruptedanditisnotsafetocontinue.Itisusedautomaticallyforthingslikecoredumpsorother“hard”crashes.
![Page 325: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/325.jpg)
“Error”statesthatarenoterrorsWARNINGisthehighestnon-errorlevel.Itmeansthatsomethingmaybewrongandneedsuser/administratorattention.Itisagoodpracticetoperiodicallyscansystemlogsforwarnings.Usethisonlyforunexpectedconditions.Seethenextoneforthingshappeningonaregularbasis.Warningsgotoclientandserverlogsbydefault.
NOTICEisforthingswhicharelikelyofhigherinteresttousers,likeinformationaboutcreatingaprimarykeyindexorsequenceforserialtype(thoughthesestoppedtobeNOTICEinthelatestversionofPostgreSQL).Likethepreviousone,NOTICEissentbothtoclientandserverlogsbydefault.
INFOisforthingsspecificallyrequestedbyclient,likeVACUUM/ANALYSEVERBOSE.Itisalwayssenttotheclientregardlessoftheclient_min_messagesGUCsetting,butisnotwrittentoaserverlogwhenusingdefaultsettings.
LOGandCOMMERRORareforservers,operationalmessages,andbydefaultareonlywrittentotheserverlog.TheerrorlevelLOGcanalsobesenttotheclientifclient_min_messagesissetappropriately,butCOMMERRORneveris.
ThereareDEBUG1toDEBUG5inincreasingorderofverbosity.Theyarespecificallymeantforreportingdebugginginfoandarenotreallyusefulinmostothercases,exceptperhapsforcuriosity.SettinghigherDEBUGxlevelsisnotrecommendedinproductionservers,astheamountloggedorreportedcanbereallyhuge.
![Page 326: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/326.jpg)
Whenaremessagessenttotheclient?Whilemostcommunicationfromtheservertotheclienttakesplaceafterthecommandcompletes(orevenafterthetransactioniscommittedincaseofLISTEN/NOTIFY),everythingemittedbyereport()issenttotheclientimmediately,thusthementionofoff-channelmessagingpreviously.Thismakesereport()ausefultoolformonitoringlong-runningcommandssuchasVACUUMandalsoasimpledebuggingaidtoprintoutusefuldebuginfo.
NoteYoucanreadamuchmoredetaileddescriptionoferrorreportingathttp://www.postgresql.org/docs/current/static/error-message-reporting.html.
![Page 327: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/327.jpg)
![Page 328: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/328.jpg)
RunningqueriesandcallingPostgreSQLfunctionsOurnextstopisrunningSQLqueriesinsidethedatabase.Whenyouwanttorunaqueryagainstthedatabase,youneedtousesomethingcalledServerProgrammingInterface(SPI).SPIgivesprogrammertheabilitytorunSQLqueriesviaasetofinterfacefunctionsforusingPostgreSQL’sparser,planner,andexecutor.
NoteIftheSQLstatementyouarerunningviaSPIfails,thecontrolisnotreturnedtothecaller,butinsteadthesystemrevertstoacleanstateviainternalmechanismsforROLLBACK.ItispossibletocatchSQLerrorsbyestablishingasub-transactionaroundyourcalls.Itisaninvolvedprocessnotyetofficiallydeclared“stable”andtherefore,itisnotpresentinthedocumentationonCextensions.Ifyouneedit,onegoodplacetolookatwouldbethesourcecodeforvariouspluggablelanguages(PL/python,PL/proxy,andsoon)whichdoitandarelikelytobemaintainedingoodorderiftheinterfacechanges.
InthePL/pythonsource,thefunctionstoexamineareintheplpython/plpy_spi.cfileandareappropriatelynamedPly_spi_subtransaction_[begin|commit|abort]().
TheSPIfunctionsdoreturnnon-negativevaluesforsuccess,eitherdirectlyviaareturnvalueorinaglobalvariableSPI_result.ErrorsproduceanegativevalueorNull.
![Page 329: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/329.jpg)
AsampleCfunctionusingSPIHereisasamplefunctiondoinganSQLqueryviaSPI_*()functions.Itisamodifiedversionofthesamplefromthestandarddocumentation(itusesVersion1callingconventionsandoutputsanextrabitofinformation).The.c,.sql.in,andMakefilefunctionsforthissampleareavailableinthespi_samples/subdirectory.
Datum
count_returned_rows(PG_FUNCTION_ARGS)
{
char*command;
intcnt;
intret;
intproc;
/*getarguments,convertcommandtoCstring*/
command=text_to_cstring(PG_GETARG_TEXT_P(0));
cnt=PG_GETARG_INT32(1);
/*openinternalconnection*/
SPI_connect();
/*runtheSQLcommand*/
ret=SPI_exec(command,cnt);
/*savethenumberofrows*/
proc=SPI_processed;
/*Ifsomerowswerefetched,printthemviaelog(INFO).*/
if(ret>0&&SPI_tuptable!=NULL)
{
TupleDesctupdesc=SPI_tuptable->tupdesc;
SPITupleTable*tuptable=SPI_tuptable;
charbuf[8192];
inti,j;
for(j=0;j<proc;j++)
{
HeapTupletuple=tuptable->vals[j];
//constructastringrepresentingthetuple
for(i=1,buf[0]=0;i<=tupdesc->natts;i++)
snprintf(buf+strlen(buf),
sizeof(buf)–strlen(buf),
"%s(%s::%s)%s",
SPI_fname(tupdesc,i),
SPI_getvalue(tuple,tupdesc,i),
SPI_gettype(tupdesc,i),
(i==tupdesc->natts)?"":"|");
ereport(INFO,(errmsg("ROW:%s",buf)));
}
}
SPI_finish();
pfree(command);
PG_RETURN_INT32(proc);
}
![Page 330: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/330.jpg)
AftergettingtheargumentsusingthePG_GETARG_*macro,thefirstnewthingshownisopeninganinternalconnectionviaSPI_connect()whichsetsuptheinternalstateforthefollowingSPI_*()functioncalls.ThenextstepistoexecuteafullSQLstatementusingSPI_exec(command,cnt).
TheSPI_exec()functionisaconvenientvariantofSPI_execute(...)withtheread_onlyflagsettofalse.Theread_onlyflag,ifsettotruemeansthatonlyareadonlycommandcanbeexecuted.ThereisalsoathirdversionoftheexecuteatonceSPIfunction,theSPI_execute_with_args(...),whichpreparesthequery,bindsthepassed-inarguments,andexecutesinasinglecall.
Afterthequeryisexecuted,wesavetheSPI_processedvalueforreturningthenumberofrowsprocessedattheendofthefunction.Inthissample,itisnotstrictlynecessary,butingeneralyouneedtosaveanySPI_*globalvariablebecausetheycouldbeoverwrittenbythenextSPI_*(...)call.
ToshowwhatwasreturnedbythequeryandalsotoshowhowtoaccessfieldsreturnedbySPIfunctions,wenextprintoutdetailedinfoonanytuplesreturnedbythequeryviatheereport(INFO,…)call.WefirstcheckedthattheSPI_execcallwassuccessful(ret>0)andthatsometupleswerereturned(SPI_tuptable!=NULL),andthenforeachreturnedtuplefor(j=0;j<proc;...)weloopedoverthefieldsfor(i=1;i<=tupdesc->natts;...)formattingthefieldsinfointoabuffer.Wegetthestringrepresentationsofthefieldname,value,anddatatypeusingSPIfunctionsSPI_fname(),SPI_getvalue(),andSPI_gettype()andthensendtherowtotheuserusingereport(INFO,…).Ifyouwanttoreturnthevaluesfromthefunctioninstead,seethenextsectionsonreturningtheSETOFvaluesandcompositetypes.
Finally,wefreedtheSPIinternalstateusingSPI_finish();.Onecanalsofreethespaceallocatedforthecommandvariablebythetext_to_cstring(<textarg>)function,thoughitisnotstrictlynecessary,thankstothefunctioncallcontextbeingdestroyedandmemoryallocatedinitbeingfreedanywayatthefunctionexit.
![Page 331: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/331.jpg)
VisibilityofdatachangesThevisibilityrulesfordatachangesinPostgreSQLarethateachcommandcannotseeitsownchangesbutusuallycanseechangesmadebycommandswhichwerestartedbeforeit,evenwhenthecommandisstartedbytheoutercommandorquery.
Theexceptioniswhenthequeryisexecutedwitharead-onlyflagset,inwhichcasethechangesmadebyoutercommandsareinvisibletoinnerorcalledcommands.
Thevisibilityrulesaredescribedinthedocumentationathttp://www.postgresql.org/docs/current/static/spi-visibility.htmlandmaybequitecomplextounderstandatfirst,butitmayhelptothinkofaread-onlySPI_execute()callasbeingcommand-level,similartothetransactionisolationlevelserializable;andaread-writecallsimilartotheread-committedisolationlevel.
Thisisfurtherexplainedathttp://www.postgresql.org/docs/current/static/spi-examples.htmlintheSamplesessionsection.
![Page 332: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/332.jpg)
MoreinfoonSPI_*functionsThereisalotmoreinformationonspecificSPI_*()functionsintheofficialdocumentation.
ForPostgreSQLVersion9.3functions,http://www.postgresql.org/docs/current/static/spi.htmlisthestartingpointfortheSPIdocs.
MoresamplecodeisalsoavailableinthePostgreSQLsourceinregressiontestsatsrc/test/regress/regress.candinthecontrib/spi/module.
![Page 333: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/333.jpg)
![Page 334: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/334.jpg)
HandlingrecordsasargumentsorreturnedvaluesAsournextexercise,let’swriteafunctionwhichtakesarecordofthreeintegersa,b,andcasanargumentandreturnsasetofdifferentrecords—allpermutationsofa,b,andcwithanextrafieldxcomputedasa*b+c.
First,thisfunctioniswritteninPL/pythontomakeiteasiertounderstandwhatwearetryingtodo:
hannu=#CREATELANGUAGEplpythonu;
CREATELANGUAGE
hannu=#CREATETYPEabcAS(aint,bint,cint);
CREATETYPE
hannu=#CREATEORREPLACEFUNCTION
hannu-#reverse_permutations(rabc)
hannu-#RETURNSTABLE(cint,bint,aint,xint)
hannu-#AS$$
hannu$#a,b,c=r['a'],r['b'],r['c']
hannu$#yielda,b,c,a*b+c
hannu$#yielda,c,b,a*c+b
hannu$#yieldb,a,c,b*b+c
hannu$#yieldb,c,a,b*c+a
hannu$#yieldc,a,b,c*a+b
hannu$#yieldc,b,a,c*b+a
hannu$#$$LANGUAGEplpythonu;
CREATEFUNCTION
hannu=#SELECT*FROMreverse_permutations(row(2,7,13));
-[RECORD1]
c|2
b|7
a|13
x|27
-[RECORD2]
c|2
b|13
a|7
x|33
-[RECORD3]
c|7
b|2
a|13
x|62
-[RECORD4]
c|7
b|13
a|2
x|93
-[RECORD5]
c|13
b|2
a|7
x|33
![Page 335: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/335.jpg)
-[RECORD6]
c|13
b|7
a|2
x|93
TherearethreenewthingsthatwearegoingtotouchinthefollowingCimplementationofasimilarfunction:
HowtofetchanelementofRECORDpassedasanargumentHowtoconstructatupletoreturnaRECORDtypeHowtoreturnSETOF(alsoknownasTABLE)ofthisRECORD
Solet’sdiveintotheCcodeforthisrightaway(asamplecanbefoundinthechap9/c_records/directory).
Forbetterclarity,wewillexplainthisfunctionintwoparts:first,doingasimplereverse(a,b,c)function,whichreturnsjustasinglerecordof(c,b,a,x=c*b+a),andthenexpandingittoreturnasetofpermutationssuchasthesamplePL/pythonufunction.
![Page 336: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/336.jpg)
ReturningasingletupleofacomplextypeThefirststepinconstructingaversionofthereversepermutationsfunctioninCistostartwithsimplybeingabletoreturnasinglerecordoftypeabc:
Datum
c_reverse_tuple(PG_FUNCTION_ARGS)
{
HeapTupleHeaderth;
int32a,b,c;
boolaisnull,bisnull,cisnull;
TupleDescresultTupleDesc;
OidresultTypeId;
Datumretvals[4];
boolretnulls[4];
HeapTuplerettuple;
//getthetupleheaderof1stargument
th=PG_GETARG_HEAPTUPLEHEADER(0);
//getargumentDatum'sandconvertthemtoint32
a=DatumGetInt32(GetAttributeByName(th,"a",&aisnull));
b=DatumGetInt32(GetAttributeByName(th,"b",&bisnull));
c=DatumGetInt32(GetAttributeByName(th,"c",&cisnull));
//debug:reporttheextractedfieldvalues
ereport(INFO,
(errmsg("arg:(a:%d,b:%d,c:%d)",a,b,c)));
//setuptupledescriptorforresultinfo
get_call_result_type(fcinfo,&resultTypeId,&resultTupleDesc);
//checkthatSQLfunctiondefinitionissetuptoreturnarecord
Assert(resultTypeId==TYPEFUNC_COMPOSITE);
//makethetupledescriptorknowntopostgresasvalidreturntype
BlessTupleDesc(resultTupleDesc);
retvals[0]=Int32GetDatum(c);
retvals[1]=Int32GetDatum(b);
retvals[2]=Int32GetDatum(a);
retvals[3]=Int32GetDatum(retvals[0]*retvals[1]+retvals[2]);
retnulls[0]=aisnull;
retnulls[1]=bisnull;
retnulls[2]=cisnull;
retnulls[3]=aisnull||bisnull||cisnull;
rettuple=heap_form_tuple(resultTupleDesc,retvals,retnulls);
PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
}
![Page 337: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/337.jpg)
ExtractingfieldsfromanargumenttupleGettingthefieldsofanargumenttupleiseasy.First,youfetchtheHeapTupleHeaderfileoftheargumentintothethvariableusingthePG_GETARG_HEAPTUPLEHEADER(0)macro,andthenforeachfieldyougettheDatum(agenerictypewhichcanholdanyfieldvalueinPostgreSQL)bythefieldnameusingtheGetAttributeByName()functionandthenassignitsvaluetoalocalvariableafterconvertingittoint32viaDatumGetInt32():
a=DatumGetInt32(GetAttributeByName(th,"a",&aisnull));
ThethirdargumenttoGetAttributeByName(...)isanaddressofaboolwhichissettotrueifthefieldwasNULL.
ThereisalsoacompanionfunctionGetAttributeByNum()ifyouprefertogettheattributesbytheirnumbersinsteadofnames.
![Page 338: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/338.jpg)
ConstructingareturntupleConstructingthereturntuple(s)isalmostaseasy.
First,yougetthecalledfunctionsreturntypedescriptorusingtheget_call_result_type()function:
get_call_result_type(fcinfo,&resultTypeId,&resultTupleDesc);
ThefirstargumenttothisfunctionistheFunctionCallInfostructurefcinfowhichisusedwhencallingthefunctionyouarecurrentlywriting(hiddenbehindthePG_FUNCTION_ARGSmacrointheCfunctiondeclaration).TheothertwoargumentsareaddressesofthereturntypeOidandTupleDesctoreceivethereturntupledescriptorincasethefunctionreturnsarecordtype.
Next,thereisasafetyassertforcheckingthatthereturntypeisreallyarecord(orcomposite)type:
Assert(resultTypeId==TYPEFUNC_COMPOSITE);
ThisistoguardagainsterrorsintheCREATEFUNCTIONdeclarationinSQLwhichtellsPostgreSQLaboutthisnewfunction.
Andtherestillremainsonethingbeforeweconstructthetuple:
BlessTupleDesc(resultTupleDesc);
ThepurposeofBlessTupleDesc()istofillinthemissingpartsofthestructure,whicharenotneededforinternaloperationsonthetuple,butareessentialwhenthetupleisreturnedfromthefunction.
Sowearedonewiththetupledescriptorandfinally,wecanconstructthetupleorrecordittobereturned.
Thetupleisconstructedusingtheheap_form_tuple(resultTupleDesc,retvals,retnulls);functionwhichusesTupleDescwejustprepared.ItalsoneedsanarrayofDatumtobeusedasvaluesinthereturntuple,andanarrayofbool,whichisusedtodetermineifanyfieldshouldbesettoNULLinsteadoftheircorrespondingDatumvalue.Asallourfieldsareoftypeint32,theirvaluesinretvalsaresetusingInt32GetDatum(<localvar>).Thearrayretnullisasimplearrayofboolandneedsnospecialtrickstosetitsvalues.
Finallywereturntheconstructedtuple:
PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
Here,wefirstconstructDatumfromthetuplewejustconstructedusingHeapTupleGetDatum()andthenusethePG_RETURN_DATUMmacro.
![Page 339: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/339.jpg)
Interlude–whatisDatum?Inthischapter,weusesomethingcalledDatuminseveralplaces.ThiscallsforabitofexplanationaboutwhataDatumis.
Inshort,aDatumisanydataitemthePostgreSQLprocessesandpassesaround.DatumitselfdoesnotcontainanytypeinformationorinfoonwhetherthefieldisactuallyNULL.Itisjustapointertoamemory.Youalwayshavetofindout(orknowbeforehand)thetypeofanyDatumyouuseandalsohowtofindoutifyourdatamaybeNULLinsteadofanyrealvalue.
Intheprecedingexample,GetAttributeByName(th,"b",&bisnull)returnsaDatum,anditcanreturnsomethingevenwhenthefieldinthetupleisNULL,soalwayscheckfornull-nessfirst.Also,thereturnedDatumitselfcannotbeusedformuchunlessweconvertittosomerealtype,asdoneinthenextstepusingDatumGetInt32(),whichsimplyconvertsthevagueDatumtoarealint32valuebasicallydoingacastfromamemorylocationofanundefinedtypetoint32.
ThedefinitionofDatuminpostgresql.histypedefDatum*DatumPtr;thatisanythingpointedtobyaDatumPtr.EventhoughDatumPtrisdefinedastypedefuintptr_tDatum;itmaybeeasiertothinkofitasa(slightlyrestricted)void*.
Oncemore,anyrealsubstanceisaddedtoaDatumbyconvertingittoarealtype.
Youcanalsogotheotherway,turningalmostanythingintoaDatumasseenattheendofthefunction:
HeapTupleGetDatum(rettuple)
Again,foranythingelseinPostgreSQLtomakeuseofsuchDatum,thetypeinformationmustbeavailablesomewhereelse,inourcasethereturntypedefinitionsofthefunction.
![Page 340: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/340.jpg)
ReturningasetofrecordsNext,wewillmodifyourfunctiontonotjustreturnasinglerecordofreorderedfieldsfromanargumentrecord,buttoreturnallpossibleorderings.Wewillstilladdoneextrafieldxasanexampleofhowyoucanusethevaluesyouextractedfromtheargument.
Forset-returningfunctions,PostgreSQLhasaspecialcallingmechanismwherePostgreSQL’sexecutormachinerywillkeepcallingthefunctionoverandoveragainuntilitreportsbackthatitdoesnothaveanymorevaluestoreturn.Thisreturn-and-continuebehaviorisverysimilartohowtheyieldkeywordworksinPythonorJavaScript.
Allcallstothesetreturningfunctiongetanargumentapersistentstructuremaintainedoutsidethefunctionandmadeavailabletothefunctionviamacros:SRF_FIRSTCALL_INIT()forthefirstcallandSRF_PERCALL_SETUP()forsubsequentcalls.
Tofurtherclarifytheexample,weprovideaconstantarrayofpossibleorderingstobeusedwhenpermutingthevalues.
Also,wereadargumentfieldsa,b,andconlyonceatthebeginningofthefunctionandsavetheextractedvaluesinastructurec_reverse_tuple_args,whichweallocateandinitializeatthefirstcall.Forthestructuretosurvivethroughallcalls,weallocatethisstructureinaspecialmemorycontextwhichismaintainedinthefuncctx->multi_call_memory_ctxandstorethepointertothisstructureinfuncctx->user_fctx.Wealsomakeuseoffuncctxfields:call_cntrandmax_calls.
Inthesamecodesectionrunonceatthefirstcall,wealsopreparethedescriptorstructureneededforreturningthetuples.Todoso,wefetchthereturntupledescriptorbypassingtheaddresswegetinfuncctx->tuple_desctothefunctionget_call_result_type(...),andwecompletethepreparationbycallingBlessTuple(...)onittofillinthemissingbitsneededforusingitforreturningvalues.
Attheendofthissection,werestorethememorycontext.Whileyouusuallydonotneedtopfree()thethingsyouhavepalloc()allocated,youshouldalwaysremembertorestorethememorycontextwhenyouaredoneusinganycontextyouhaveswitchedto,orelseyouriskmessingupPostgreSQLinawaythatcanbehardtodebuglater!
Therestissomethingthatgetsdoneateachcall,includingthefirstone.
Westartbycheckingthatthereisstillsomethingtodobycomparingthecurrentcalltothemaxcallsparameter.Thisisbynomeanstheonlywaytodetermineifwehavereturnedallvalues,butitisindeedthesimplestwayifyouknowaheadhowmanyrowsyouaregoingtoreturn.Iftherearenomorerowstoreturn,wesignalthisbackusingSRF_RETURN_DONE().
Therestisverysimilartowhattheprevioussingle-tuplefunctiondid.Wecomputetheretvalsandretnullsarraysusingtheindexpermutationsarrayipsandthenconstructatupletoreturnusingheap_form_tuple(funcctx->tuple_desc,retvals,retnulls);.
Finally,wereturnthetupleusingmacroSRF_RETURN_NEXT(...),convertingthetupletoDatum,asthisiswhatthemacroexpects.
![Page 341: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/341.jpg)
Onemorethingtonote,allcurrentversionsofPostgreSQLwillalwayskeepcallingyourfunctionuntilitreturnsSRF_RETURN_DONE().Thereiscurrentlynowaytodoan“earlyexit”fromthecallersside.Thismeansthatifyourfunctionreturns1millionrowsandyoudo:
SELECT*FROMmymillionrowfunction()LIMIT3;
Thefunctionwillbecalled1milliontimesinternally,andalltheresultswillbecached,andonlyafterthis,thefirstthreerowswillbereturnedandtheremaining9,99,997rowsarediscarded.Thisisnotafundamentallimitation,butjustanimplementationdetailwhichislikelytochangeinsomefutureversionofPostgreSQL.Don’tholdyourbreaththough,thiswillonlyhappenifsomebodyfindsthisvaluableenoughtoimplement.
Thesourcewithmodificationsdescribedpreviouslyisasfollows:
structc_reverse_tuple_args{
int32argvals[3];
boolargnulls[3];
boolanyargnull;
};
Datum
c_permutations_x(PG_FUNCTION_ARGS)
{
FuncCallContext*funcctx;
constchar*argnames[3]={"a","b","c"};
//6possibleindexpermutationsfor0,1,2
constintips[6][3]={{0,1,2},{0,2,1},
{1,0,2},{1,2,0},
{2,0,1},{2,1,0}};
inti,call_nr;
structc_reverse_tuple_args*args;
if(SRF_IS_FIRSTCALL())
{
HeapTupleHeaderth=PG_GETARG_HEAPTUPLEHEADER(0);
MemoryContextoldcontext;
/*createafunctioncontextforcross-callpersistence*/
funcctx=SRF_FIRSTCALL_INIT();
/*switchtomemorycontextappropriateformultiplefunctioncalls
*/
oldcontext=MemoryContextSwitchTo(
funcctx->multi_call_memory_ctx
);
/*allocateandzero-fillstructforpersistingextracted
arguments*/
args=palloc0(sizeof(structc_reverse_tuple_args));
args->anyargnull=false;
funcctx->user_fctx=args;
/*totalnumberoftuplestobereturned*/
funcctx->max_calls=6;
//thereare6permutationsof3elements
//extractargumentvaluesandNULL-ness
![Page 342: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/342.jpg)
for(i=0;i<3;i++){
args->argvals[i]=DatumGetInt32(GetAttributeByName(th,
argnames[i],&(args->argnulls[i])));
if(args->argnulls[i])
args->anyargnull=true;
}
//setuptupleforresultinfo
if(get_call_result_type(fcinfo,NULL,&funcctx->tuple_desc)
!=TYPEFUNC_COMPOSITE)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("functionreturningrecordcalledincontext"
"thatcannotaccepttyperecord")));
BlessTupleDesc(funcctx->tuple_desc);
//restorememorycontext
MemoryContextSwitchTo(oldcontext);
}
funcctx=SRF_PERCALL_SETUP();
args=funcctx->user_fctx;
call_nr=funcctx->call_cntr;
if(call_nr<funcctx->max_calls){
HeapTuplerettuple;
Datumretvals[4];
boolretnulls[4];
for(i=0;i<3;i++){
retvals[i]=Int32GetDatum(args->argvals[ips[call_nr][i]]);
retnulls[i]=args->argnulls[ips[call_nr][i]];
}
retvals[3]=Int32GetDatum(args->argvals[ips[call_nr][0]]
*args->argvals[ips[call_nr][1]]
+args->argvals[ips[call_nr][2]]);
retnulls[3]=args->anyargnull;
rettuple=heap_form_tuple(funcctx->tuple_desc,retvals,retnulls);
SRF_RETURN_NEXT(funcctx,HeapTupleGetDatum(rettuple));
}
else/*dowhenthereisnomoreleft*/
{
SRF_RETURN_DONE(funcctx);
}
}
![Page 343: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/343.jpg)
![Page 344: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/344.jpg)
FastcapturingofdatabasechangesSomeobviousthingstocodeinCareloggingorauditingtriggers,whichgetcalledateachINSERT,UPDATE,orDELETEtoatable.WehavenotsetasideenoughspaceinthisbooktoexplaineverythingneededforCtriggers,butinterestedreaderscanlookupthesourcecodefortheskytoolspackagewhereyoucanfindmorethanonewaytowritetriggersinC.
ThehighlyoptimizedCsourceforthetwomaintriggers:logtrigaandlogutriga,includeseverythingyouneedtocapturethesechangestoatableandalsotodetecttablestructurechangeswhilethecodeisrunning.
Thelatestsourcecodeforskytoolscanbefoundathttp://pgfoundry.org/projects/skytools.
![Page 345: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/345.jpg)
![Page 346: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/346.jpg)
Doingsomethingatcommit/rollbackAsofthiswriting,thereisnopossibilitytodefineatriggerfunctionwhichisexecutedONCOMMITorONROLLBACK.However,ifyoureallyneedtohavesomecodeexecutedonthesedatabaseevents,youhaveapossibilitytoregisteraC-languagefunctiontobecalledontheseevents.Unfortunately,thisregistrationcannotbedoneinapermanentwayliketriggers,buttheregistrationfunctionhastobecalledeachtimeanewconnectionstarts:
RegisterXactCallback(my_xact_callback,NULL);
Usegrep-rRegisterXactCallbackinthecontrib/directoryofPostgreSQL’ssourcecodetofindfileswithexamplesofactualcallbackfunctions.
![Page 347: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/347.jpg)
![Page 348: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/348.jpg)
SynchronizingbetweenbackendsAlltheprecedingfunctionsaredesignedtoruninasingleprocess/backendasiftheotherPostgreSQLprocessesdidnotexist.
Butwhatifyouwanttologsomethingtoasinglefilefrommultiplebackends?
Seemseasy—justopenthefileandwritewhatyouwant.Unfortunately,itisnotthateasyifyouwanttodoitfrommultipleparallelprocessesandyoudonotoverwriteormixupthedatawithwhatotherprocesseswrite.
Tohavemorecontroloverthewritingorderbetweenbackends,youneedtohavesomekindofinter-processsynchronization,andtheeasiestwaytodothisinPostgreSQListousesharedmemoryandlight-weightlocks(LWLocks).
Toallocateitsownsharedmemorysegmentyour.sofileneedstobepreloaded,thatis,itshouldbeoneofthepreloadedlibrariesgiveninthepostgresql.confvariableshared_preload_libraries.
Inthe_PG_init()functionofyourmodule,youaskfortheaddressofanamesharedmemorysegment.Ifyouarethefirstoneaskingforthesegment,youarealsoresponsibleforinitializingthesharedstructures;including,creating,andstoringanyLWLocksyouwishtouseinyourmodule.
![Page 349: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/349.jpg)
![Page 350: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/350.jpg)
WritingfunctionsinC++ItisabadideatomixPostgreSQLwithC++foranumberofreasons.ItisbettertowrapyourC++codeintoCcodebehindexternCfunctions.Thiscanbeaproblemifyouheavilyusetemplatesandlibrarieslikeboost.
FormorediscussiononuseofC++readthePostgreSQLdocumentationherehttp://www.postgresql.org/docs/current/static/xfunc-c.html#EXTEND-CPP.
![Page 351: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/351.jpg)
![Page 352: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/352.jpg)
AdditionalresourcesforCInthischapter,wewereabletoonlygiveyouaverybasicintroductiontowhatispossibleinC.Hereissomeadviceonhowtogetmoreinformation.
First,thereisofcoursethechapterC-LanguageFunctionsinthePostgreSQLmanual.Thiscanbefoundonlineathttp://www.postgresql.org/docs/current/static/xfunc-c.htmlandaswithmostoftheonlinePostgreSQLmanuals,youusuallycangettoolderversionsiftheyexist.
Thenextone,surprisingly,isthePostgreSQLsourcecodeitself.However,youwillusuallynotgetveryfarbyjustopeningthefilesorusinggreptofindwhatyouneed.Ifyouaregoodwithusingctags(http://en.wikipedia.org/wiki/Ctags)oranothersimilartool,itisdefinitelyrecommended.
Also,ifyouarenewtothesetypesoflarge-codeexplorationsystems,thenareallygoodresourceforfindingandexaminingPostgreSQLinternalsismaintainedathttp://doxygen.postgresql.org/.Thispointstothelatestgitmaster,soitmaynotbeaccurateforyourversionofPostgreSQL,butitisusuallygoodenoughandatleastprovidesanicestartingpointfordiggingaroundinthesourcecodeofyourversion.
Quiteoften,youwillfindsomethingtobase(partsof)yourCsourceoninthecontrib/directoryinthesourcecode.Togetanideaofwhatliesthere,readthroughtheAppendixF,AdditionalSuppliedModules(http://www.postgresql.org/docs/current/static/contrib.html).It’sentirelypossiblethatsomebodyhasalreadywrittenwhatyouneed.Therearemanymoremodulesinhttp://pgfoundry.orgforyoutoexamineandchoosefrom.Awordofwarningthough,whilemodulesincontrib/arecheckedatleastbyoneortwocompetentPostgreSQLcoreprogrammers,thethingsatpgfoundrycanbeofwildlyvaryingquality.Thetopactiveprojectsarereallygood;however,sothemainthingstolookatwhendeterminingifyoucanusethemasalearningsourcearehowactivetheprojectisandwhenwasitlastupdated.
ThereisalsoasetofGUCparametersspecificallyfordevelopmentanddebuggingwhichareusuallyleftoutofthesamplepostgresql.conffile.Thedescriptionsandanexplanationareavailableathttp://www.postgresql.org/docs/current/static/runtime-config-developer.html.
![Page 353: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/353.jpg)
![Page 354: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/354.jpg)
SummaryAsCisthelanguagethatPostgreSQLitselfiswrittenin,itisveryhardtodrawadistinctiononwhatisanextensionfunctionusingadefinedAPIandwhatishackingPostgreSQLitself.
Someofthetopicsthatwedidnottouchatallwere:
Creatingnewinstallabletypesfromscratch—seecontrib/hstore/forafullimplementationofanewtype.Creatingnewindexmethods—downloadanolderversionofPostgreSQLtoseehowfulltextindexingsupportwasprovidedasanadd-on.ImplementinganewPL/*language—searchforpl/lolcodeforalanguage,thesolepurposeofwhichistodemonstratehowaPostgreSQL’sPL/*languageshouldbewritten(seehttp://pgfoundry.org/projects/pllolcode/).YoumayalsowanttocheckoutthesourcecodeforPL/Proxyforacleanandwell-maintainedPLlanguage.(TheusageofPL/Proxyisdescribedinthenextchapter.)
Hopefully,thischaptergaveyouenoughinfotoatleaststartwritingPostgreSQLextensionfunctionsinC.
IfyouneedmorethanwhatisavailablehereorintheofficialPostgreSQLdocumentation,thenrememberthatlotsofPostgreSQL’sbackenddeveloperdocumentation—oftenincludinganswerstothequestionsHow?andWhy?—isinthesourcefiles.AlotofthatcanalsoberelevanttoCextensions.
Soremember—UseTheSource,Luke!
InthenextchapterwewilldiscussscalingthedatabaseusingPL/Proxy.
![Page 355: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/355.jpg)
![Page 356: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/356.jpg)
Chapter10.ScalingYourDatabasewithPL/ProxyIfyouhavefollowedtheadviceinthepreviouschaptersfordoingallyourdatabaseaccessthroughfunctions,youareinagreatpositiontoscaleyourdatabasebyhorizontallydistributingthedataovermultipleservers,alsoknownasdatabasesharding.Horizontaldistributionmeansthatyoukeepjustaportionofatableoneachpartitionofthedatabase,andthatyouhaveamethodtoautomaticallyaccesstherightdatabasewhenaccessingthedata.
WewillgentlyintroducetheconceptsleadingtothePL/Proxypartitioninglanguage,andthendelveintothesyntaxandproperusageofthelanguageitself.Let’sstartwithwritingascalableapplicationfromscratch.First,wewillwriteittobeashighlyperformingaspossibleononeserver.Then,wewillscaleitbyspreadingitoutonseveralservers.WewillfirstgetthisimplementedinPL/PythonuandtheninPL/Proxy.
NoteThisapproachisworthtaking,onlyifyouhave(plansfor)areallylargedatabase.Formostdatabases,oneserverplusoneorperhapstwohotstandbyserversshouldbemorethanenough.
![Page 357: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/357.jpg)
Creatingasimplesingle-serverchatPerhaps,thesimplestapplicationneedingthiskindofscalabilityisamessaging(orchat)application;so,let’swriteone.
Theinitialsingle-serverimplementationhasthefollowingspecifications:
ThereshouldbeusersandmessagesEachuserhasausername,password,e-mail,listoffriends,andaflagtoindicateiftheuserwantstogetmessagesfromonlytheirfriends,orfromeverybodyForusers,therearemethodsfor:
RegisteringnewusersUpdatingthelistoffriendsLoggingin
Eachmessagehasasender,receiver,messagebody,andtimestampsforsendingandreadingthemessageFormessages,therearemethodsfor:
SendingamessageRetrievingnewmessages
Aminimalisticsystemimplementingthis,couldlooklikethefollowing:
Here,awebpageopensaWebSocket(ws://)toaHUB(amessageconcentrator)whichinturntalkstoadatabase.Oneachnewconnection,theHUBlogsinandonsuccessfulloginopensaWebSocketconnectiontothewebpage.Itthensendsallnewmessagesthathaveaccumulatedforthelogged-inusersincethelasttimetheyretrievedtheirmessages.Afterthat,theHUBwaitsfornewmessagesandpushesthemtothewebpageastheyarrive.
Thedatabaseparthastwotables,theuser_infotableandmessagetable.Thefollowingcodewillcreatetheuser_infotable:
CREATETABLEuser_info(
usernametextprimarykey,
pwdhashtextnotnull,—base64encodedmd5hashofpassword
emailtext,
friend_listtext[],—listofbuddiesusernames
friends_onlybooleannotnulldefaultfalse
);
Thefollowingcodewillcreatethemessagetable:
CREATETABLEmessage(
from_usertextnotnullreferencesuser_info(username),
sent_attimestampnotnulldefaultcurrent_timestamp,
to_usertextnotnullreferencesuser_info(username),
read_attimestamp,—whenwasthisretrievedbyto_user
msg_bodytextnotnull,
delivery_statustextnotnulldefault'outgoing'—('sent',"failed")
);
![Page 358: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/358.jpg)
Asthisisstillanall-in-onedatabaseimplementation,thedatabasefunctionscorrespondingtoapplicationmethodsareverysimple.
Thefollowingcodewillcreateauser:
CREATEorREPLACEFUNCTIONnew_user(
INi_usernametext,INi_pwdhashtext,INi_emailtext,
OUTstatusint,OUTmessagetext)
AS$$
BEGIN
INSERTINTOuser_info(username,pwdhash,email)
VALUES(i_username,i_pwdhash,i_email);
status=200;
message='OK';
EXCEPTIONWHENunique_violationTHEN
status=500;
message='USEREXISTS';
END;
$$LANGUAGEplpgsqlSECURITYDEFINER;
Thismethodjustfailswhentheuserisalreadydefined.Amorereal-lifefunctionwouldproposealistofavailableusernamesinthiscase.
Thefollowingmethodforloginreturnsstatus500forfailureand200or201forsuccess.Ifthemethodreturns201,itmeansthatthereareunreadmessagesforthisuser:
CREATEORREPLACEFUNCTIONlogin(
INi_usernametext,INi_pwdhashtext,
OUTstatusint,OUTmessagetext)
AS$$
BEGIN
PERFORM1FROMuser_info
WHERE(username,pwdhash)=(i_username,i_pwdhash);
IFNOTFOUNDTHEN
status=500;
message='NOTFOUND';
return;
ENDIF;
PERFORM1FROMmessage
WHEREto_user=i_username
ANDread_atISNULL;
IFFOUNDTHEN
status=201;
message='OK.NEWMESSAGES';
ELSE
status=200;
message='OK.NOMESSAGES';
ENDIF;
END;
$$LANGUAGEplpgsqlSECURITYDEFINER;
Thefollowingaretheothertwousermethodsforchangingthefriends,listandtellingthesystemwhethertheywanttoreceivemailsthatareonlyfromfriends.Errorcheckingisomittedhereforbrevity:
CREATEorREPLACEFUNCTIONset_friends_list(
![Page 359: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/359.jpg)
INi_usernametext,INi_friends_listtext[],
OUTstatusint,OUTmessagetext)
AS$$
BEGIN
UPDATEuser_info
SETfriend_list=i_friends_list
WHEREusername=i_username;
status=200;
message='OK';
END;
$$LANGUAGEplpgsqlSECURITYDEFINER;
CREATEorREPLACEFUNCTIONmsg_from_friends_only(
INi_usernametext,INi_friends_onlyboolean,OUTstatusint,OUT
messagetext)
AS$$
BEGIN
UPDATEuser_infoSETfriends_only=i_friends_only
WHEREusername=i_username;
status=200;
message='OK';
END;
$$LANGUAGEplpgsqlSECURITYDEFINER;
Thesend_message()functionisusedformessaging,whichsimplysendsmessages,asshowninthefollowingcode:
CREATEorREPLACEFUNCTIONsend_message(
INi_from_usertext,INi_to_usertext,INi_messagetext,
OUTstatusint,OUTmessagetext)
AS$$
BEGIN
PERFORM1FROMuser_info
WHEREusername=i_to_user
AND(NOTfriends_onlyORfriend_list@>ARRAY[i_from_user]);
IFNOTFOUNDTHEN
status=400;
message='SENDINGFAILED';
RETURN;
ENDIF;
INSERTINTOmessage(from_user,to_user,msg_body,delivery_status)
VALUES(i_from_user,i_to_user,i_message,'sent');
status=200;
message='OK';
EXCEPTION
WHENforeign_key_violationTHEN
status=500;
message='FAILED';
END;
$$LANGUAGEplpgsqlSECURITYDEFINER;
Thefunctionusedforretrievingmessages,isasfollows:
CREATEorREPLACEFUNCTIONget_new_messages(
INi_usernametext,
OUTo_statusint,OUTo_message_texttext,
![Page 360: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/360.jpg)
OUTo_from_usertext,OUTo_sent_attimestamp)
RETURNSSETOFRECORD
AS$$
BEGIN
FORo_status,o_message_text,o_from_user,o_sent_atIN
UPDATEmessage
SETread_at=CURRENT_TIMESTAMP,
delivery_status='read'
WHEREto_user=i_usernameANDread_atISNULL
RETURNING200,msg_body,from_user,sent_at
LOOP
RETURNNEXT;
ENDLOOP;
END;
$$LANGUAGEplpgsqlSECURITYDEFINER;
Wearealmostdonewiththedatabasepartofoursimpleserver.Tofinishitup,weneedtodosomeinitialperformancetuning,andforthat,weneedsomedatainourtables.Theeasiestwayistousethegenerate_series()functiontogeneratealistofnumbers,whichwewilluseasusernames.Forourinitialtesting,nameslike7or42areasgoodasBob,Mary,orJill:
hannu=#SELECTnew_user(generate_series::text,'pwd',generate_series::text
||'@pg.org')
hannu-#FROMgenerate_series(1,100000);
hannu=#WITHns(n,len)AS(
hannu(#SELECT*,(random()*10)::intFROM
generate_series(1,100000))
hannu-#SELECTset_friends_list(ns.n::text,
hannu(#ARRAY((SELECT(random()*100000)::int
hannu(#FROMgenerate_series(1,len)))::text[]
hannu(#)
hannu-#FROMns;
Now,wehave100,000userswith0to10friendseach,foratotalof501,900friends.
hannu=#SELECTcount(*)FROM(SELECTusername,unnest(friend_list)FROM
user_info)a;
-[RECORD1]-
count|501900
Now,let’ssendeachofthefriendsamessage:
hannu=#SELECTsend_message(username,unnest(friend_list),'hellofriend!')
FROMuser_info;
Lookhowfastwecanretrievethemessages:
hannu=#SELECTget_new_messages('50000');
get_new_messages
----------------------------------------------------------
(200,"hellofriend!",49992,"2012-01-0902:23:28.470979")
(200,"hellofriend!",49994,"2012-01-0902:23:28.470979")
(200,"hellofriend!",49995,"2012-01-0902:23:28.470979")
(200,"hellofriend!",49996,"2012-01-0902:23:28.470979")
![Page 361: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/361.jpg)
(200,"hellofriend!",49997,"2012-01-0902:23:28.470979")
(200,"hellofriend!",49999,"2012-01-0902:23:28.470979")
(200,"hellofriend!",50000,"2012-01-0902:23:28.470979")
(7rows)
Time:763.513ms
Spendingalmostasecondgettingsevenmessagesseemsslow,soweneedtooptimizeabit.
Thefirstthingtodoistoaddindexesforretrievingthemessages:
hannu=#CREATEINDEXmessage_from_user_ndxONmessage(from_user);
CREATEINDEX
Time:4341.890ms
hannu=#CREATEINDEXmessage_to_user_ndxONmessage(to_user);
CREATEINDEX
Time:4340.841ms
Andcheckifthishelpedtosolveourproblem:
hannu=#SELECTget_new_messages('52000');
get_new_messages
----------------------------------------------------------
(200,"hellofriend!",51993,"2012-01-0902:23:28.470979")
(200,"hellofriend!",51994,"2012-01-0902:23:28.470979")
(200,"hellofriend!",51996,"2012-01-0902:23:28.470979")
(200,"hellofriend!",51997,"2012-01-0902:23:28.470979")
(200,"hellofriend!",51998,"2012-01-0902:23:28.470979")
(200,"hellofriend!",51999,"2012-01-0902:23:28.470979")
(200,"hellofriend!",52000,"2012-01-0902:23:28.470979")
(7rows)
Time:2.949ms
Muchbetter—indexedlookupsare300timesfasterthansequentialscans,andthisdifferencewillgrowastablesgetbigger!
Asweareupdatingthemessagesandsettingtheirstatustoread,itisalsoagoodideatosetfillfactortosomethinglessthan100percentandthisisshowninthefollowingexample:
NoteFillfactortellsPostgreSQLnottofillupdatabasepagescompletely,buttoleavesomespaceforHOTupdates.WhenPostgreSQLupdatesarow,itonlymarkstheoldrowfordeletionandaddsanewrowtothedatafile.Iftherowthatisupdatedonlychangesunindexedfields,andthereisenoughroominthepagetostoreasecondcopy,aHOTupdatewillbedoneinstead.Inthiscase,thecopycanbefoundusingoriginalindexpointerstothefirstcopy,andnoexpensiveindexupdatesaredonewhileupdating.Youcanreadmoreaboutthefillfactorathttp://www.postgresql.org/docs/current/static/sql-createtable.html
hannu=#ALTERTABLEmessageSET(fillfactor=90);
ALTERTABLE
Time:75.729ms
![Page 362: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/362.jpg)
hannu=#CLUSTERmessage_from_user_ndxONmessage;
CLUSTER
Time:9797.639ms
hannu=#SELECTget_new_messages('55022');
get_new_messages
----------------------------------------------------------
(200,"hellofriend!",55014,"2012-01-0902:23:28.470979")
(200,"hellofriend!",55016,"2012-01-0902:23:28.470979")
(200,"hellofriend!",55017,"2012-01-0902:23:28.470979")
(200,"hellofriend!",55019,"2012-01-0902:23:28.470979")
(200,"hellofriend!",55020,"2012-01-0902:23:28.470979")
(200,"hellofriend!",55021,"2012-01-0902:23:28.470979")
(200,"hellofriend!",55022,"2012-01-0902:23:28.470979")
(7rows)
Time:1.895ms
Stillbetter!Thefillfactormadetheget_new_messages()functionanother20to30percentfaster,thankstoenablingthefasterHOTupdates!
![Page 363: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/363.jpg)
![Page 364: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/364.jpg)
Dealingwithsuccess–splittingtablesovermultipledatabasesNow,let’srollforwardalittleintimeandassumeyouhavebeensuccessfulenoughtoattracttensofthousandsofusersandyoursingledatabasestartscreakingundertheload.
Mygeneralruleofthumb,istostartplanningforabiggermachine,orsplittingthedatabase,whenyouareover80percentutilizationatleastforafewhoursaday.It’sgoodtohaveaplanearlier,butnowyouhavetostartdoingsomethingaboutreallycarryingouttheplan.
![Page 365: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/365.jpg)
Whatexpansionplansworkandwhen?Thereareacoupleofpopularwaystogrowdatabase-backedsystems.Dependingonyourusecase,notallwayswillwork.
MovingtoabiggerserverIfyoususpectthatyouarenearyourtoploadfortheserviceorproduct,youcansimplymovetoamorepowerfulserver.Thismaynotbethebestlong-timescalingsolutionifyouarestillinthemiddle,oreveninthebeginningofyourgrowth.Youwillrunoutofbiggermachinestobuylongbeforeyouaredone.Serversalsobecomedisproportionatelymoreexpensiveasthesizeincreases,andyouwillbeleftwithatleastonedifferent,andthusnoteasilyreplaceable,serveronceyouimplementaproperscalingsolution.
Ontheotherhand,thiswillworkforsometimeandisoftentheeasiestwaytogetsomeheadroomwhileimplementingrealscalingsolutions.
Master-slavereplication–movingreadstoslaveMaster-slavereplication,eithertrigger-basedorWAL-based,worksreasonablywellincaseswherethelargemajorityofthedatabaseaccessesarereads.Somethingsthatfallunderthiscase,arewebsitecontentmanagers,blogs,andotherpublishingsystems.
Asourchatsystemhasmoreorlessa1:1ratioofwritesandreads,movingreadstoaseparateserverwillbuyusnothing.Thereplicationitselfismoreexpensivethanthepossiblewinfromreadingfromasecondserver.
MultimasterreplicationMultimasterreplicationisevenworsethanmaster-slave(s)whentheproblemisscalingawrite-heavyworkload.Ithasalltheproblemsofmaster-slave,plusitintroducesextraloadviacross-partitionlockingorconflictresolutionrequirements,whichfurtherslowsdownthewholecluster.
![Page 366: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/366.jpg)
DatapartitioningacrossmultipleserversTheobvioussolutiontoscalingwritesistosplitthembetweenseveralservers.Ideallyyoucouldhave,forexample,fourserversandeachofthemgettingexactlyonefourthoftheload.
Inthiscase,eachserverwouldholdaquarterofusersandmessages,andserveaquarterofallrequests.
Tomakethechangetransparentfordatabaseclients,weintroducealayerofproxydatabases.Theseproxydatabasescaneitherresideonthesamehostsasthepartitiondatabasesorbeontheirownhost.Theroleoftheproxydatabasesistopretendtobethedatabaseforclients,butinfactdelegatetherealworktopartitionsbycallingtherightfunctionintherightpartitiondatabase.
Thisclienttransparencyisnotterriblyimportantifyouhavejustoneapplicationaccessingthedatabase.Ifyoudid,youcouldthendothesplittingintheclientapplication.Itbecomesveryhandyasyoursystemgrowstohaveseveralapplications,perhapsusingmanydifferentplatformsandframeworksontheclientside.
Havingaseparatelayerofproxydatabasesenableseasymanagementofdatasplitting,sothattheclientapplicationsdon’tneedtoknowanythingabouttheunderlyingdataarchitecture.Theyjustcallthefunctionstheyneedandthat’salltheyneedtoknow.Infact,youcanswitchoutthewholedatabasestructurewithouttheclientsevernoticinganything,exceptthebetterperformancefromthenewarchitecture.
Moreonhowexactlytheproxyworkslater.Fornow,letustacklesplittingthedata.
SplittingthedataIfwesplitthedata,weneedasimpleandefficientwaytodeterminewhichserverstoreseachdatarow.Ifthedatahadanintegerprimarykey,youcouldjustgoround-robin,storethefirstrowonthefirstserver,thesecondrowonthesecond,andsoon.Thiswouldgiveyouafairlyevendistribution,evenwhenrowswithcertainIDsaremissing.
Thepartitioningfunctionforselectingbetweenfourserverswouldbesimply:
partition_nr=id&3
Thepartitioningmask3(binary11)isforthefirsttwobits.Foreightpartitions,youwoulduse7(binary111),andfor64serversitwouldbe63(00111111).Itisnotaseasywiththingslikeusernames,whereputtingallnamesstartingwithanAfirst,Bsecond,andsoon,doesnotproduceanevendistribution.
Turningtheusernameintoafairlyevenlydistributedintegerviathehashfunctionsolvesthisproblemandcanbeuseddirectlytoselectthepartition.
partition_nr=hashtext(username)&3
Thiswoulddistributetheusersinthefollowingmanner:
hannu=#SELECTusername,hashtext(username)&3aspartition_nrFROM
![Page 367: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/367.jpg)
user_info;
-[RECORD1]+--------
username|bob
partition_nr|1
-[RECORD2]+--------
username|jane
partition_nr|2
-[RECORD3]+--------
username|tom
partition_nr|1
-[RECORD4]+--------
username|mary
partition_nr|3
-[RECORD5]+--------
username|jill
partition_nr|2
-[RECORD6]+--------
username|abigail
partition_nr|3
-[RECORD7]+--------
username|ted
partition_nr|3
-[RECORD8]+--------
username|alfonso
partition_nr|0
So,partition0getsuseralfonso,partition1bobandtom,partition2janeandjill,andpartition3getsmary,abigail,andted.Thedistributionisnotexactlyonefourthtoeachpartition;butasthenumberofpartitionsincrease,itwillbeprettyclosewherethisactuallymatters.
IfwehadnoPL/Proxylanguage,wecouldwritethepartitioningfunctionsinthemostuntrustedPLlanguages.Forexample,asimpleloginproxyfunctionwritteninPL/Pythonulookslikethis:
CREATEORREPLACEFUNCTIONpylogin(
INi_usernametext,INi_pwdhashtext,
OUTstatusint,OUTmessagetext)
AS$$
importpsycopg2
partitions=[
'dbname=chap10p0port=5433',
'dbname=chap10p1port=5433',
'dbname=chap10p2port=5433',
'dbname=chap10p3port=5433',
]
partition_nr=hash(i_username)&3
con=psycopg2.connect(partitions[partition_nr])
cur=con.cursor()
cur.execute('select*fromlogin(%s,%s)',(i_username,i_pwdhash))
status,message=cur.fetchone()
return(status,message)
$$LANGUAGEplpythonuSECURITYDEFINER;
Here,wedefinedasetoffourpartitiondatabases,givenbytheirconnectstringsandstored
![Page 368: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/368.jpg)
asalistinvariablepartitions.
Whenexecutingthefunction,wefirstevaluatethehashfunctionontheusernameargument(hash(i_username))andextracttwobitsfromit(&3)togetanindexintothepartitions’list(thepartitionnumber)forexecutingeachcall.
Then,weopenaconnectiontoapartitiondatabaseusingtheconnectstringselectedbythepartitionnumber(con=psycopg2.connect(partitions[partition_nr])).
Finally,weexecutearemotequeryinthepartitiondatabaseandreturntheresultsofthistothecallerofthisproxyfunction.
Thisworksreasonablywell,ifimplementedlikethis,butitalsohasatleasttwoplaceswhereitissuboptimal:
First,itopensanewdatabaseconnectioneachtimethefunctioniscalled,whichkillsperformanceSecond,itisamaintenancenightmareifyouhard-wirethepartitioninformationinfull,inallfunctions
Theperformanceproblemcanbesolvedbycachingtheopenconnections,andthemaintenanceproblemcanbesolvedbyhavingasinglefunctionreturningthepartitioninformation.However,evenwhenwedothesechangesandstaywithPL/Pythonuforpartitioning,wewillstillbedoingalotofcopyandpasteprogrammingineachofourproxyfunctions.
Oncewehadreachedtheprecedingconclusions,whengrowingourdatabasesystemsatSkype,thenextlogicalstepwasquiteobvious.Weneededaspecialpartitioninglanguage,whichwoulddojustthisonething—callingremoteSQLfunctions,andthenmakeitasfastaspossible.Andthus,thePL/Proxydatabasepartitioninglanguagewasborn.
![Page 369: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/369.jpg)
PL/Proxy–thepartitioninglanguageTherestofthischapterisdevotedtothePL/Proxylanguage.First,wewillinstallit.Then,wewilllookatitssyntaxandwaystoconfigurethepartitionsforitsuse.Finally,wewilldiscusshowtodotheactualdatamigrationfromasingledatabasetoapartitionedoneandthenlookatseveralusageexamples.
InstallingPL/ProxyIfyouareonDebian,Ubuntu,oraRedHatvariant,installingthelanguageiseasy.
First,youhavetoinstalltherequiredpackagesonyouroperatingsystem:
sudoapt-getinstallpostgresql-9.4-plproxy
Or:
sudoyuminstallplproxy94
IfyouneedtoinstallPL/Proxyfromthesource,youcandownloaditfromhttp://pgfoundry.org/projects/plprox,extractthesourcesinthecontribfolderofyourPostgreSQLsourcetreeandrunmakeandmakeinstall.
ToinstallPL/Proxyyoushouldruntheplproxy.sqlfile,whichispartofthesourcecodeorthepackageyouinstalled.
ThePL/ProxylanguagesyntaxThePL/Proxylanguageitselfisverysimple.ThepurposeofaPL/Proxyfunctionistohandofftheprocessingtoanotherserver,sothatthelanguageonlyneedssixstatements:
CONNECTorCLUSTERandRUNONforselectingthetargetdatabasepartitionSELECTandTARGETforspecifyingthequerytorunSPLITforsplittinganARRAYargumentbetweenseveralsubarraysforrunningonmultiplepartitions
CONNECT,CLUSTER,andRUNONThefirstgroupofstatementshandlestheremoteconnectivitytothepartitions.Thehelpdetermineswhichdatabasetorunthequeryon.YouspecifytheexactpartitiontorunthequeryusingCONNECT:
CONNECT'connectstring';
Here,connectstringdeterminesthedatabasetorun.connectstringisthestandardPostgreSQLconnectstringyouwouldusetoconnecttothedatabasefromaclientapplication,forexample:dbname=p0port=5433username=testhost=localhost.
Or,youcanspecifyanameusingCLUSTER:
CLUSTER'usercluster';
Finally,youcanspecifyapartitionnumberusingRUNON:
RUNONpart_func(arg[,...]);
![Page 370: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/370.jpg)
part_func()canbeanyexistingoruser-definedPostgreSQLfunctionreturninganinteger.PL/ProxycallsthatfunctionwiththegivenargumentsandthenusesNlowerbitsfromtheresulttoselectaconnectiontoaclusterpartition.
TherearetwomoreversionsoftheRUNONstatement:
RUNONANY;
Thismeansthatthefunctioncanbeexecutedonanypartitioninacluster.Thiscanbeusedwhenalltherequireddataforafunctionispresentonallpartitions.
Theotherversionis:
RUNONALL;
Thisrunsthestatementonallpartitionsinparallelandthenreturnsaconcatenationofresultsfromthepartitions.Thishasatleastthreemainuses:
Forcaseswhenyoudon’tknowwheretherequireddatarowis,likewhengettingdatausingnon-partitionkeys.Forexample,gettingauserbyitse-mailwhenthetableispartitionedbyusername.Runningaggregatefunctionsoverlargersubsetsofdata,saycountingallusers.Forexample,gettingalltheuserswhohaveacertainuserintheirfriends’lists.Manipulatingdatathatneedstobethesameonallpartitions.Forexample,whenyouhaveapricelistthatotherfunctionsareusing,thenonesimplewaytomanagethispricelistisusingaRUNONALLfunction.
SELECTandTARGETThedefaultbehaviorofaPL/Proxyfunction,ifnoSELECTorTARGETispresent,istocallthefunctionwiththeexactsamesignatureasitselfintheremotepartition.
Supposewehavethefunction:
CREATEORREPLACEFUNCTIONlogin(
INi_usernametext,INi_pwdhashtext,
OUTstatusint,OUTmessagetext)
AS$$
CONNECT'dbname=chap10host=10.10.10.1';
$$LANGUAGEplproxySECURITYDEFINER;
Ifitisdefinedinschemapublic,thefollowingcallselect*fromlogin('bob','secret')connectstothedatabasechap10onhost10.10.10.1andrunsthefollowingSQLstatementthere:
SELECT*FROMpublic.login('bob','secret')
Thisretrievestheresultandreturnsittoitscaller.
Ifyoudon’twanttodefineafunctioninsidetheremotedatabase,youcansubstitutethedefaultselect*from<thisfunction>(<arg1>,...)callwithyourownbywritingitinthefunctionbodyofthePL/Proxyfunction:
CREATEORREPLACEFUNCTIONget_user_email(i_usernametext)
![Page 371: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/371.jpg)
RETURNSSETOFtextAS$$
CONNECT'dbname=chap10host=10.10.10.1';
SELECTemailFROMuser_infowhereusername=i_username;
$$LANGUAGEplproxySECURITYDEFINER;
OnlyasingleSELECTissupported;foranyother,ormorecomplexSQLstatements,youhavetowritearemotefunctionandcallit.
Thethirdoption,istostillcallafunctionsimilartoitself,butnameddifferently.Forexample,ifyouhaveaproxyfunctiondefinednotinaseparateproxydatabase,butinapartition,youmaywantittotargetthelocaldatabaseforsomedata:
CREATEORREPLACEFUNCTIONpublic.get_user_email(i_usernametext)RETURNS
SETOFtextAS$$
CLUSTER'messaging';
RUNONhashtext(i_username);
TARGETlocal.get_user_email;
$$LANGUAGEplproxySECURITYDEFINER;
Inthissetup,thelocalversionofget_user_email()isinschemalocalonallpartitions.Therefore,ifoneofthepartitionsconnectsbacktothesamedatabasethatitisdefinedin,itavoidscircularcalling.
SPLIT–distributingarrayelementsoverseveralpartitionsThelastPL/Proxystatementisforcaseswhereyouwantsomebiggerchunkofworktobedoneinappropriatepartitions.
Forexample,ifyouhaveafunctiontocreateseveralusersinonecallandyoustillwanttobeabletouseitafterpartitioning,theSPLITstatementisawaytotellPL/Proxytosplitthearraysbetweenthepartitionsbasedonthepartitioningfunction:
CREATEorREPLACEFUNCTIONcreate_new_users(
INi_usernametext[],INi_pwdhashtext[],INi_emailtext[],
OUTstatusint,OUTmessagetext)RETURNSSETOFRECORD
AS$$
BEGIN
FORiIN1..array_length(i_username,1)LOOP
SELECT*
INTOstatus,message
FROMnew_user(i_username[i],i_pwdhash[i],i_email[i]);
RETURNNEXT;
ENDLOOP;
END;
$$LANGUAGEplpgsqlSECURITYDEFINER;
ThefollowingPL/Proxyfunctiondefinition,createdontheproxydatabase,canbeusedtosplitthecallsacrossthepartitions:
CREATEorREPLACEFUNCTIONcreate_new_users(
INi_usernametext[],INi_pwdhashtext[],INi_emailtext[],
OUTstatusint,OUTmessagetext)RETURNSSETOFRECORD
AS$$
CLUSTER'messaging';
RUNONhashtext(i_username);
![Page 372: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/372.jpg)
SPLITi_username,i_pwdhash,i_email;
$$LANGUAGEplproxySECURITYDEFINER;
Itwouldbecalledbysendinginthreearraystothefunction:
SELECT*FROMcreate_new_users(
ARRAY['bob','jane','tom'],
ARRAY[md5('bobs_pwd'),md5('janes_pwd'),md5('toms_pwd')],
ARRAY['[email protected]','[email protected]','[email protected]']
);
Itwillresultintwoparallelcallstopartitions1and2(asusinghashtext(i_username)bobandtommaptopartition1andmarytopartition2ofthetotalforthepartitions,asexplainedearlier),withthefollowingargumentsforpartition1:
SELECT*FROMcreate_new_users(
ARRAY['bob','tom'],
ARRAY['6c6e5b564fb0b192f66b2a0a60c751bb','edcc36c33f7529f430a1bc6eb7191dfe'
],
ARRAY['[email protected]','[email protected]']
);
Andthisforpartition2:
SELECT*FROMcreate_new_users(
ARRAY['jane'],
ARRAY['cbbf391d3ef4c60afd851d851bda2dc8'],
ARRAY['[email protected]']
);
Then,itreturnsaconcatenationoftheresults:
status|message
--------+---------
200|OK
200|OK
200|OK
(3rows)
ThedistributionofdataFirst,whatisaclusterinPL/Proxy?Well,theclusterisasetofpartitionsthatmakeupthewholedatabase.Eachclusterconsistsofanumberofpartitions,asdeterminedbytheclusterconfiguration.Eachpartitionisuniquelyspecifiedbyitsconnectstring.Thelistofconnectionstringsiswhatmakesupacluster.Thepositionofthepartitioninthislistiswhatdeterminesthepartitionnumber,sothefirstelementinthelistispartition0,thesecondpartitionis1,andsoon.
ThepartitionisselectedbytheoutputoftheRUNONfunction,andthenmaskedbytherightnumberofbitstomapitonthepartitions.So,ifhashtext(i_username)returns14andtherearefourpartitions(2bits,maskbinary11or3indecimal),thepartitionnumberwillbe14and3=2,andthefunctionwillbecalledonpartition2(startingfromzero),whichisthethirdelementinthepartitionlist.
![Page 373: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/373.jpg)
NoteTheconstraintthatthenumberofpartitionshastobeapoweroftwomayseemanunnecessaryrestrictionatfirst,butitwasdoneinordertomakesurethatitis,andwillremaintobe,easytoexpandthenumberofpartitionswithouttheneedtoredistributeallthedata.
Forexample,ifyoutriedtomovefromthreepartitionstofour,mostlikelythreefourthsofthedatarowsinpartitions0to2havetobemovedtonewpartitionstoevenlycover0to3.Ontheotherhand,whenmovingfromfourtoeightpartitions,thedataforpartitions0and1isexactlythesamethatwaspreviouslyonpartition0,2-3istheold1andsoon.Thatis,yourdatadoesnotneedtobemovedimmediately,andhalfofthedatadoesnotneedtobemovedatall.
Theactualconfigurationofthecluster,thedefinitionofpartitions,canbedoneintwoways,eitherbyusingasetoffunctionsinschemaplproxy,oryoucantakeadvantageoftheSQL/MEDconnectionmanagement(SQL/MEDisavailablestartingatPostgreSQL8.4andabove).YoucanreadmoreaboutSQL/MEDherehttps://wiki.postgresql.org/wiki/SQL/MED
ConfiguringthePL/ProxyclusterusingfunctionsThisistheoriginalwaytoconfigurePL/Proxy,whichworksonallversionsofPostgreSQL.Whenaqueryneedstobeforwardedtoaremotedatabase,thefunctionplproxy.get_cluster_partitions(cluster)isinvokedbyPL/Proxytogettheconnectionstringtouseforeachpartition.
Thefollowingfunctionisanexample,whichreturnsinformationforaclusterwithfourpartitions,p0top3:
CREATEORREPLACEFUNCTIONplproxy.get_cluster_partitions(cluster_name
text)
RETURNSSETOFtextAS$$
BEGIN
IFcluster_name='messaging'THEN
RETURNNEXT'dbname=p0';
RETURNNEXT'dbname=p1';
RETURNNEXT'dbname=p2';
RETURNNEXT'dbname=p3';
ELSE
RAISEEXCEPTION'Unknowncluster';
ENDIF;
END;
$$LANGUAGEplpgsql;
Aproductionapplicationmightquerysomeconfigurationtables,orevenreadsomeconfigurationfilestoreturntheconnectionstrings.Onceagain,thenumberofpartitionsreturnedmustbeapoweroftwo.Ifyouareabsolutelysurethatsomepartitionsareneverused,youcanreturnemptystringsforthese.
Wealsoneedtodefineaplproxy.get_cluster_version(cluster_name)function.Thisiscalledoneachrequestandiftheclusterversionhasnotchanged,theoutputfroma
![Page 374: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/374.jpg)
cachedresultfromplproxy.get_cluster_partitionscanbereused.So,itisbesttomakesurethatthisfunctionisasfastaspossible:
CREATEORREPLACEFUNCTIONplproxy.get_cluster_version(cluster_nametext)
RETURNSint4AS$$
BEGIN
IFcluster_name='messaging'THEN
RETURN1;
ELSE
RAISEEXCEPTION'Unknowncluster';
ENDIF;
END;
$$LANGUAGEplpgsql;
Thelastfunctionneededisplproxy.get_cluster_config,whichenablesyoutoconfigurethebehaviorofPL/Proxy.Thissamplewillsettheconnectionlifetimeto10minutes:
CREATEORREPLACEFUNCTIONplproxy.get_cluster_config(
incluster_nametext,
outkeytext,
outvaltext)
RETURNSSETOFrecordAS$$
BEGIN
—letsusesameconfigforallclusters
key:='connection_lifetime';
val:=10*60;
RETURNNEXT;
RETURN;
END;
$$LANGUAGEplpgsql;
ConfiguringthePL/ProxyclusterusingSQL/MEDSinceversion8.4,PostgreSQLhassupportforanSQLstandardformanagementofexternaldata,usuallyreferredtoasSQL/MED.SQL/MEDissimplyastandardwaytoaccessadatabase.Usingfunctionstoconfigurepartitionsisarguablyinsecure,asanycallerofplproxy.get_cluster_partitions()canlearnconnectionstringsforpartitionsthatmaycontainsensitiveinfolikepasswords.PL/ProxyalsoprovidesawaytodotheclusterconfigurationusingSQL/MED,whichfollowsthestandardSQLsecuritypractices.
Thesameconfiguration,asdiscussedearlier,whendoneusingSQL/MED,isasfollows:
1. First,createaforeigndatawrappercalledplproxy:
proxy1=#CREATEFOREIGNDATAWRAPPERplproxy;
2. Then,createanexternalserverthatdefinesboththeconnectionoptionsandthepartitions:
proxy1=#CREATESERVERmessagingFOREIGNDATAWRAPPERplproxy
proxy1-#OPTIONS(connection_lifetime'1800',
proxy1(#p0'dbname=p0',
proxy1(#p1'dbname=p1',
proxy1(#p2'dbname=p2',
![Page 375: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/375.jpg)
proxy1(#p3'dbname=p3'
proxy1(#);
CREATESERVER
3. Then,grantusageonthisservertoeitherPUBLIC,soalluserscanuseit:
proxy1=#CREATEUSERMAPPINGFORPUBLICSERVERmessaging;
CREATEUSERMAPPING
Or,tosomespecificusersorgroups:
proxy1=#CREATEUSERMAPPINGFORbobSERVERmessaging
proxy1-#OPTIONS(user'plproxy',password'very.secret');
CREATEUSERMAPPING
4. Finally,grantusageontheclustertotheuserswhoneedtouseit:
proxy1=#GRANTUSAGEONFOREIGNSERVERmessagingTObob;
GRANT
NoteMoreinfoonSQL/MED,asimplementedinPostgreSQL,canbefoundathttp://www.postgresql.org/docs/current/static/sql-createforeigndatawrapper.html.
![Page 376: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/376.jpg)
MovingdatafromthesingletothepartitioneddatabaseIfyoucanschedulesomedowntimeandyournewpartitiondatabasesareasbigasyouroriginalsingledatabase,theeasiestwaytopartitionthedataistomakeafullcopyofeachofthenodesandthensimplydeletetherowsthatdonotbelongtothepartition:
pg_dumpchap10|psqlp0
psqlp0-c'deletefrommessagewherehashtext(to_user)&3<>0'
psqlp0-c'deletefromuser_infowherehashtext(username)&3<>0'
Repeatthisforpartitionsp1top3,eachtimedeletingrowswhichdon’tmatchthepartitionnumber(psqlchap10p1-c'delete…&3<>1).
NoteRemembertovacuumwhenyouarefinisheddeletingtherows.PostgreSQLwillleavethedeadrowsinthedatatables,sodoalittlemaintenancewhileyouhavesomedowntime.
Whentryingtodeletefromuser_info,youwillnoticethatyoucan’tdoitwithoutdroppingaforeignkeyfrommessage.from_user.
Here,wecoulddecidethatitisOkaytokeepthemessagesonthereceiverspartitiononly,andifneeded,thatthesentmessagescanberetrievedusingaRUNONALLfunction.So,wewilldroptheforeignkeyfrommessages.from_user.
psqlp0-c'altertablemessagedropconstraintmessage_from_user_fkey'
Thereareotheroptions,whensplittingthedata,thatrequirelessdiskspaceusageforadatabasesystem,ifyouarewillingtodomoremanualwork.
Forexample,youcancopyoverjusttheschemausingpg_dump-sandthenuseCOPYfromanSQLstatementtomoveoverjusttheneededrows:
pg_dump-schap10|psqlp0
psqlchap10-c"COPY(select*frommessagewherehashtext(to_user)&3=
0)TOstdout"|psqlp0-c'COPYmessagesFROMstdin'
OrevensetupaspeciallydesignedLondistereplicaanddotheswitchfromasingledatabasetoapartitionedclusterinonlyseconds,oncethereplicahasreachedastablestate.
![Page 377: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/377.jpg)
![Page 378: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/378.jpg)
ConnectionPoolingPL/Proxydoesnotincludeaconnectionpooleranditisagoodideatouseonelikepgbouncerandpgpool.Aconnectionpoolerisautilitythathelpsyoureducetheoperatingcostofdatabase,whenitslargenumberofphysicalconnectionsarepullingperformancedown.
PL/Proxyopensaconnectiontoeachpartitionfromeachbackendprocessandalargenumberofconnectionscanbringtheperformanceoftheserverdown.Usingtheconnectionpoolwillallowyoutomultiplexalotofclientconnectionsoverasmallnumberofdatabaseconnections.Thepgbouncerisarecommendedconnectionpoolerbecauseit’slightweightandveryeasytosetup.PL/ProxyattemptstoconnecttopgbouncerusingthesamedatabaseconnectioninterfacethatitusestoconnecttoanyPostgreSQLdatabase.TheclientapplicationsuppliestheIPaddressofthehostrunningpgbouncerandtheportnumberonwhichpgbouncerislisteningforconnections.
![Page 379: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/379.jpg)
![Page 380: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/380.jpg)
SummaryInthischapter,wehavegoneovertheprocessofdatabaseshardingfordatabasesthataretoobigtotakethewriteloadonasinglehost,orwhereyoujustwanttohavetheaddedresilienceofhavingasystemwhereonehostbeingdowndoesnotbringthewholesystemdown.
Inshort,theprocessis:
DecidewhichtablesyouwanttosplitovermultiplehostsDefineapartitioningkeyAddthepartitiondatabasesandmovethedataSetuptheproxyfunctionsforallthefunctionsaccessingthosetablesWatchforalittlewhilethateverythingisworkingRelax
WealsotookabrieflookatusingPL/ProxyforsimpleremotequeriestootherPostgreSQLdatabases,whichmaybehandyforsometasks,evenafterthenewForeignDataWrapper(FDW)functionalityinPostgreSQLreplaceditformanyuses.
WhilePL/Proxyisnotforeveryone,itmaywellsavethedayifyouaresuddenlyfacedwithrapiddatabasegrowthandhavetheneedforaneasyandcleanwaytospreadthedatabaseovermanyhosts.
Inthenextchapter,wewilllookatthePL/Perlprogramminglanguage.
![Page 381: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/381.jpg)
![Page 382: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/382.jpg)
Chapter11.PL/Perl–PerlProceduralLanguagePerlisafeature-richlanguage,whichhasbeenaroundforalongtime.PostgreSQLallowsyoutowritePerlroutinesthatarestoredandexecutedinsidethedatabase.ThisabilityisquiteuniquetoPostgreSQLandallowsyoutodoalotofcoolthings,suchasusingPerl’stextmanipulationfeaturesinsideadatabase.PL/PerlisoneofthemanylanguagesthatPostgreSQLsupportsforwritingserver-sideroutines.
Asdiscussedintheearlierchapters,PostgreSQLsupportstrustedanduntrustedlanguages.PL/Perlisavailableinboththeseflavors.Thetrustedversionrunsinsideasafecontainerand,therefore,nottheentiresetoffamiliarnativePerloperationsisallowed.
Inthischapter,wewillcoverthefollowingtopics:
WhentousePL/PerlHowtoinstallandwriteabasicfunctionPassingargumentstoandfromPL/PerlfunctionsWritingtriggersinPL/PerlAbriefintroductiontountrustedPL/Perl
![Page 383: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/383.jpg)
WhentousePL/PerlWewillbrieflydiscusshowtocreatePerlfunctionsandusethemintriggers.SomeofyoumightaskwhenitisbeneficialtousePL/Perl,sincePostgreSQLsupportsavarietyoflanguagesthatcanbeusedtocreatetriggersorwritestoredprocedures/functions.
YoumightbemorefamiliarwithalanguagesuchasPerlthanwithPythonorTcl.Thisisaprettygoodreasontochooseacertainlanguageovertheother.
However,iftheperformanceofthefunctionisoneofyourconsiderations,thenyoumightwanttochoosealanguagebasedonthenatureofthecodeyouwanttowrite.
Ingeneral,PL/PerlwilloutperformPL/pgSQL,ifthefocusofthestoredprocedureiscomputationaltasks,athematic,andstringparsingandmanipulation.However,PL/pgSQLwilloftenbeaclearwinnerifyouneedtoaccessthedatabase.PL/pgSQLiscloselytiedintothePostgreSQLexecutionengineandhasaverylowoverheadofrunningaquery,comparedtootherprocedurallanguages.
![Page 384: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/384.jpg)
![Page 385: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/385.jpg)
InstallingPL/PerlPL/PerlisnotinstalledbydefaultifyouusedthestandardsourcedistributiontoinstallPostgreSQL.IfyoucompilePostgreSQLfromthesource,youneedtoconfigurethescriptwiththe--with-perloption.
Ifyouusedabinarydistributiononyourplatform,youcannormallyinstallPL/Perlusingyourpackagemanager.Youcansearchforpostgresql-plperl,orasimilarpackagename,asitdiffersacrossthedistributions.OncePostgreSQLiscompiledwiththecorrectoption,oryouhaveinstalledtheappropriatepackage,youcancreatethePLlanguageusingthecreatelangutilityortheCREATELANGUAGEcommand,asshownhere:
$createlangplperltemplate1
Ortheuntrustedversion,suchasthefollowingcommand:
$createlangplperlutemplate1
hon
![Page 386: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/386.jpg)
![Page 387: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/387.jpg)
AsimplePL/PerlfunctionNow,let’swriteourfirstsimplePerlfunctiontomakesurethatPL/Perlisinstalledcorrectly.WewilluseasamplefunctionfromthePerlFAQs,athttp://perldoc.perl.org/perlfaq5.html#How-can-I-output-my-numbers-with-commas-added%3f,towriteaPL/Perlfunctionthataddscommastoanumber:
CREATEORREPLACEFUNCTIONcommafy(integer)RETURNStext
AS$$
local$_=shift;
1whiles/^([-+]?\d+)(\d{3})/$1,$2/;
return$_;
$$LANGUAGEplperl;
Thisfunctionusesasmartlywrittenregextoaddcommastoyournumbers.Let’stryandrunit:
testdb=#SELECTcommafy(1000000);
commafy
-----------
1,000,000
(1row)
ThecodeworksandthefunctionlookssimilartootherfunctionswehavebeenwritinginPL/pgSQLandPL/Python.TheCREATEFUNCTIONstatementcreatesafunction.Itneedsaname,functionargumenttypelist(youhavetouseparentheses,eveniftherearenoarguments),aresulttype,andalanguage.
ThefunctionbodyisjustananonymousPerlsubroutine.PostgreSQLpassesthisontoaPerlinterpreter,inordertorunthissubroutineandreturntheresults.Eachfunctioniscompiledoncepersession.PL/Perlfunctionargumentsarestoredin@_,justasinnormalPerlsubroutinesandyourcodecanhandlethemthesameway.
TheargumentspassedtothePL/PerlfunctionareconvertedtoUTF-8fromthedatabaseencoding,andthereturnvalueisconvertedfromUTF-8backtothedatabaseencoding.
TipUsingUTF-8fordatabaseencodingisencouragedaswell.Thiswillavoidtheoverheadofconvertingbackandforthbetweenencodings.
PL/Perlfunctionsruninascalarcontextandcannotreturnnon-scalartypessuchaslists.Youcanreturnthenon-scalartypes,suchasarrays,records,andsets,byreturningareference.
![Page 388: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/388.jpg)
![Page 389: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/389.jpg)
Passingandreturningnon-scalartypesIfyoupassarraytypesasargumentstothePL/Perlfunction,theyarepassedastheblessedostgreSQL::InServer::ARRAYobjects.InPerl,blessassociatesanobjectwithaclass.Thisobjectcanbetreatedasanarrayreferenceorasastring.Ifyouhavetoreturnanarraytype,youmustreturnanarraybyreference.Let’stakealookatthefollowingexample:
CREATEORREPLACEFUNCTIONreverse(int[])RETURNSint[]
AS$$
my$arg=shift;#getthereferenceoftheargument
my@rev=reverse@{$arg};#reversethearray
return\@rev#returnthearrayreference
$$LANGUAGEplperl;
testdb=#selectreverse(ARRAY[1,2,3,4]);
reverse
-----------
{4,3,2,1}
(1row)
TheprecedingfunctionreversesanintegerarraypassedtothefunctionusingthereversefunctionofPerl.Youcantakealookatthecommentsinthecodetounderstandit.First,wegetthereferenceofthepassedargument.Wethenreversethearrayusingareferencenotation,@{$arg},[email protected],wereturnthereferenceofthearrayusingthebackslash.Ifyoutrytoreturnthearraydirectly,youwillgetanerror.
Let’stakealookatanotherfunctionthatconcatenatestwoarraysandthenreversestheirorder:
CREATEORREPLACEFUNCTIONconcat_reverse_arrays(int[],int[])RETURNS
int[]
AS$$
my$arr1=$_[0];
my$arr2=$_[1];
push(@{$arr1},@{$arr2});
my@reverse=reverse@{$arr1};
return\@reverse;
$$LANGUAGEplperl;
testdb=#selectconcat_reverse_arrays(ARRAY[1,2,3],ARRAY[4,5,6]);
concat_reverse_arrays
-----------------------
{6,5,4,3,2,1}
Again,thecodeisquitesimple.Ittakestwointegerarraysasparameters,concatenatesthemintoarr1,andreversestheorderusingstandardPerlfunctions.
PL/Perlcantakeargumentsofcompositetypesandcanalsoreturncompositetypes.Thecompositetypesarepassedasareferencetohashes,andthekeysofthehasharesimply
![Page 390: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/390.jpg)
attributenamesofthepassedcomplextype.Let’stakealookatanexample:
CREATETABLEitem(item_namevarchar,item_priceint,discountint);
INSERTINTOitem(item_name,item_price)VALUES('macbook',1200);
INSERTINTOitem(item_name,item_price)VALUES('pen',5);
INSERTINTOitem(item_name,item_price)VALUES('fridge',1000);
CREATEORREPLACEFUNCTIONadd_discount(item)RETURNSitem
AS$$
my$item=shift;
if($item->{item_price}>=1000){
$item->{discount}=10;
}else{
$item->{discount}=5;
}
return$item;
$$LANGUAGEplperl;
testdb=#selectadd_discount(item.*)fromitem;
add_discount
-------------------
(macbook,1200,10)
(pen,5,5)
(fridge,1000,10)
(3rows)
Theprecedingfunctionisprobablynotthebestusecaseforacomplextypeexample,butitdemonstratestheconceptssufficiently.First,wecreateatableandfillitupwithsomedata,exceptthediscountfield.Wethencreateafunctionthatispassedanitemtype,anditfillsupthediscountfieldbasedontheprice.Youcanseethatsincethecomplextypesarepassedashashreferences,weneedtousethe$item->{discount}notationtoaccessthekeys,whereeachkeycorrespondstoafieldinthetype.
YoucanalsoreturntheSETOFprimitiveandcomplextypesfromaPL/Perlfunction.Inthenextexample,wewilltrytoreturnaSETOFitemtypeandalsodemonstratehowtorunanSQLqueryinaPL/Perlfunction:
CREATEORREPLACEFUNCTIONset_dicounts()RETURNSSETOFitem
AS$$
my$rv=spi_exec_query('select*fromitem;');
my$nrows=$rv->{processed};
foreachmy$rn(0..$nrows-1){
my$item=$rv->{rows}[$rn];
if($item->{item_price}>=1000){
$item->{discount}=10;
}else{
$item->{discount}=5;
}
return_next($item);
}
returnundef;
$$LANGUAGEplperl;
![Page 391: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/391.jpg)
postgres=#select*fromset_dicounts();
-[RECORD1]-------
item_name|macbook
item_price|1200
discount|10
-[RECORD2]-------
item_name|pen
item_price|5
discount|5
-[RECORD3]-------
item_name|fridge
item_price|1000
discount|10
Thefirstthingyounoticeaboutthisfunction,isthatitreturnsaSETOFitemtype.Itusesreturn_nexttobuilduptheresultsetasitprocessesrowsfromtheitemtable.Thefunctionisthenterminatedwithafinalreturnundef(youcanalsousejustreturn).spi_exec_queryexecutesSQLandreturnsthecompleteresultsetasareferencetoanarrayofhashreferences.Ifyouaredealingwithalargenumberofrows,youmaynotwanttousespi_exec_queryasitreturnsalltherowsatonce,butyou’dratherusethespi_queryandspi_fetch_rowfunctions,whichallowyoutoiterateoverthedatalikeacursor.
NoteYoucanreadmoreaboutusingdatainaPL/PerlfunctioninthePostgreSQLdocumentationathttp://www.postgresql.org/docs/current/static/plperl-builtins.html.
![Page 392: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/392.jpg)
![Page 393: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/393.jpg)
WritingPL/PerltriggersIfyouwanttowritetriggerfunctionsusingPerl,thenPL/PerlallowsyoutodoallthegoodstuffthatyouhavelearnedsofarusingPL/PgSQL.Let’srewriteanexamplewedemonstratedinChapter5,PL/pgSQLTriggerFunctions,inPL/Perl.Recallthesimple,“Hey,Iamcalled”trigger.ThePL/Perlversionoftheexamplelooksasshowninthefollowingcode.Weprobablydon’tneedtoprovideamorecomplexexample,asthissimpleexampledemonstratesthePL/Perlsyntaxinasufficientway:
CREATEORREPLACEFUNCTIONnotify_trigger_plperl()RETURNSTRIGGER
AS$$
$result=sprintf('Hi,Igot%sinvokedFOR%s%s%son%s',
$_TD->{name},
$_TD->{level},
$_TD->{when},
$_TD->{event},
$_TD->{table_name}
);
if(($_TD->{event}cmp'UPDATE')==0){
$result.=sprintf('OLD=%sANDNEW=%s',$_TD->{old}{i},$_TD->
{new}{i});
$_TD->{new}{i}=$_TD->{old}{i}+$_TD->{new}{i};
elog(NOTICE,$result);
return"MODIFY";
}elsif(($_TD->{event}cmp'DELETE')==0){
elog(NOTICE,"SkippingDelete");
return"SKIP";
}
elog(NOTICE,$result);
$$LANGUAGEplperl;
CREATETABLEnotify_test_plperl(iint);
CREATETRIGGERnotify_insert_plperl_trigger
BEFOREINSERTORUPDATEORDELETEONnotify_test_plperl
FOREACHROW
EXECUTEPROCEDUREnotify_trigger_plperl();
Let’strytoruntheINSERT,UPDATE,andDELETEcommands:
testdb=#INSERTINTOnotify_test_plperlVALUES(1);
NOTICE:Hi,Igotnotify_insert_plperl_triggerinvokedFORROWBEFORE
INSERTonnotify_test_plperl
CONTEXT:PL/Perlfunction"notify_trigger_plperl"
INSERT01
testdb=#UPDATEnotify_test_plperlSETi=10;
NOTICE:Hi,Igotnotify_insert_plperl_triggerinvokedFORROWBEFORE
UPDATEonnotify_test_plperlOLD=1ANDNEW=10
CONTEXT:PL/Perlfunction"notify_trigger_plperl"
UPDATE1
testdb=#select*fromnotify_test_plperl;
i
![Page 394: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/394.jpg)
----
11
(1row)
postgres=#DELETEFROMnotify_test_plperl;
NOTICE:SkippingDelete
CONTEXT:PL/Perlfunction"notify_trigger_plperl"
DELETE0
Let’sreviewwhatwehavedonesofar.Wehavecreatedatriggerfunction,atesttable,andanactualtriggerthatrunsbeforeanINSERT,UPDATE,orDELETEforeachrow.
Thetriggerfunctionusesacoupleofthingswehavenotdiscussedsofar.InaPL/Perltriggerfunction,thehashreference$_TDcontainsinformationaboutthecurrenttriggerevent.Youcanseethefulllistofkeysin$_TDathttp://www.postgresql.org/docs/current/static/plperl-triggers.html.
Thetriggerswehaveusedinourexampleareexplainedinthefollowingtable:
Triggername Triggerdescription
$_TD->{name} Thisdenotesthenameofthetrigger.Inourexample,thiswillcontainnotify_trigger_plperl.
$_TD->{level} ThisisaROWorSTATEMENTtrigger.Inourexample,thiswillcontainROW.
$_TD->{when} TheBEFORE,AFTER,orINSTEADOFtrigger.Inourexample,thiswillcontainBEFORE.
$_TD->{event}TheINSERT,UPDATE,DELETE,orTRUNCATEcommand.Inourexample,thiswillcontainINSERT,UPDATE,orDELETE.
$_TD->
{table_name}Thisdenotesthenameofthetable.Inourexample,thiswillcontainnotify_test_plperl.
$_TD->{old}{i} ThiswillcontaintheOLDvalueofthecolumni.Inourexample,thiswillcontain1.
TD->{new}{i} ThiswillcontaintheNEWvalueofthecolumni.Inourexample,thiswillcontain10.
Wehavealsousedautilityfunctioncalledelog()inthetriggerfunction.Thisfunctionemitslogmessages.ThelevelvaluesthatarepossibleareDEBUG,LOG,INFO,NOTICE,WARNING,andERROR.TheERRORvaluepropagatesanerrortothecallingqueryandissimilartoaPerldiecommand.
NoteYoucanviewalltheavailablebuilt-insandutilityfunctionsavailableinPL/Perlathttp://www.postgresql.org/docs/current/static/plperl-builtins.html.
Ourtriggerfunctionreturnsthespecialvalues"MODIFY"and"SKIP"inthecaseofUPDATEandDELETE,respectively.IfaPL/Perltriggerfunctionreturns"MODIFY",itmeansthattheNEWvaluehasbeenmodifiedbythetriggerfunction.IfatriggerfunctionmodifiesaNEWvaluebutdoesnotreturn"MODIFY",thenthechangedonebythefunctionwillbediscarded.The"SKIP"impliesthattheoperationshouldnotbeexecuted.
![Page 395: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/395.jpg)
![Page 396: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/396.jpg)
UntrustedPerlWediscusseduntrustedPL/PythonUinChapter8,UsingUnrestrictedLanguages.PL/Perlisalsoavailableasanuntrustedlanguage.Thetrustedversionrunsinsideasecuritycontextthatdoesnotallowinteractionwiththeenvironment.JustlikePL/Pythonu,wecanbypassthesecurityrestrictionsusingPL/Perluortheuntrustedversion.Let’srewritethedirectorylistingfunctionlist_folderfromChapter8,ListingdirectorycontentstoaPerlequivalent:
CREATEORREPLACEFUNCTIONlist_folder_plperl(directoryVARCHAR)RETURNS
SETOFTEXT
AS$$
my$d=shift;
opendir(D,"$d")||elog(ERROR,'Cantopendirectory'.$d);
my@list=readdir(D);
closedir(D);
foreachmy$f(@list){
return_next($f);
}
returnundef;
$$LANGUAGEplperlu;
Let’srunourfunction,asshownhere:
testdb=#SELECTlist_folder_plperl('/usr/local/pgsql/bin');
list_folder_plperl
--------------------
.
..
clusterdb
createdb
createlang
createuser
dropdb
droplang
dropuser
ecpg
initdb
pg_basebackup
pg_config
pg_controldata
pg_ctl
pg_dump
pg_dumpall
pg_isready
pg_receivexlog
pg_resetxlog
pg_restore
postgres
postmaster
psql
reindexdb
vacuumdb
![Page 397: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/397.jpg)
(26rows)
Ifwetrytocreatetheprecedingfunctionasplperlinsteadofplperlu,wewillgetanerrorsuchasERROR:'opendir'trappedbyoperationmaskatline3bythevalidator,becausewearetryingtoaccessthehostsystem.
![Page 398: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/398.jpg)
![Page 399: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/399.jpg)
SummaryThepowerfulPerllanguageisavailableinPostgreSQLasPL/PerlorPL/Perlu.ThisallowsyoutowritestoredproceduresinPerlandtotakeadvantageofallthecoolfeaturesthatPerlhastooffer,suchasaverylargecollectionofmodulesavailableonCPAN.YoucandoalmosteverythingyouwantwithPL/pgSQLorPL/Python,includingdatabaseaccessandwritingtriggers.TheuntrustedversionofPL/Perlallowsyoutointeractwiththeenvironment.PL/PerlwillnormallyoutperformPL/pgSQLinnon-dataintensivefunctionsthatfocusmoreonstringmanipulationandcomputation.
Inthenextchapter,wewilldiscussanotherpopularPLlanguagecalledPl/Tcl.
![Page 400: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/400.jpg)
![Page 401: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/401.jpg)
Chapter12.PL/Tcl–TclProceduralLanguageToolsCommandLanguage(Tcl),alsocommonlyknownastickle,hasbeenaroundforalongtime.ItwascreatedbyJohnOusterhoutin1988andgotalotoftractionforrapidprototypingandscriptedapplications.
Inthischapter,wewilltakeabrieflookatPL/Tcl.BetweenPL/Perl,PL/Python,andPL/pgSQL,youhaveverypowerfullanguagesavailableatyourdisposalthatcandoalmostanythingyouneed.Forsomeotherthings,youhavetheoptiontowriteyourfunctionsinC.YoumightwonderwhyitisusefultodiscussPL/Tcl.Foralongtime,intheearlydaysofPostgreSQL,PL/Tclu(untrustedPL/Tcl)wastheonlywaytodothingsoutsidePostgreSQL,suchasinteractingwiththeoperatingsystem.Alotofpeoplestilluseit,andIpersonallythinkthatitissocleanandpowerfulthatitshouldnotbeoverlooked.
PL/Tclisavailableasatrustedandanuntrustedlanguage.ThisisachievedbyprovidingtwodifferentTclinterpreters.PL/TcluusesthestandardTclinterpreter,whilePL/TclusesaspecialSafeTclmechanism.
NoteYoucanreadmoreaboutsafeTclathttp://www.tcl.tk/software/plugin/safetcl.html.
Inthischapter,wewillcoverthefollowingtopics:
InstallingPL/TclandwritingasimplefunctionPassingsimpleandcomplexparametersAccessingadatabasefromaPl/TclfunctionWritingdatabasetriggersusingPl/Tcl
![Page 402: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/402.jpg)
InstallingPL/TclPL/Tclisnotinstalledbydefault,ifyou’veusedthestandardsourcedistributiontoinstallPostgreSQL.IfyoucompiledPostgreSQLfromthesource,youneedtoruntheconfigurescriptwiththe–-with-tcloption.
Ifyou’veusedabinarydistributiononyourplatform,youcannormallyinstallPL/Tclusingyourpackagemanager.Youcansearchforpostgresql-pltcl,orasimilarpackagename,asitdiffersacrossdistributions.OncePostgreSQLiscompiledwiththecorrectoption,oryouhaveinstalledtheappropriatepackage,youcancreatethelanguageusingthecreatelangutilityortheCREATELANGUAGEcommand:
$createlangpltcltemplate1
Youcanusealsousetheuntrustedversiontocreatethelanguage,asfollows:
$createlangpltclutemplate1
![Page 403: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/403.jpg)
![Page 404: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/404.jpg)
AsimplePL/TclfunctionNow,let’swriteourfirstsimpleTclfunctiontomakesurethatPL/Tclisinstalled.Wewillwriteasimplefactorialcalculationfunction,asshownhere:
CREATEORREPLACEFUNCTIONtcl_factorial(integer)RETURNSinteger
AS$$
seti1;setfact1
while{$i<=$1}{
setfact[expr$fact*$i]
incri
}
return$fact
$$LANGUAGEpltclSTRICT;
Thisfunctioncalculatesthefactorialofanumberinaniterativeway.Let’stryandrunit:
postgres=#SELECTtcl_factorial(5);
tcl_factorial
---------------
120
(1row)
ItworksandthefunctionlookssimilartootherfunctionswehavebeenwritinginPL/pgSQLandPL/Python.TheCREATEFUNCTIONstatementcreatesafunction.Itneedsaname,functionargumenttypelist(youhavetouseparentheses,eveniftherearenoarguments),aresulttype,andalanguage.
ThebodyofthefunctionisjustaTclscript.PostgreSQLpassesthebodyontoaTclinterpretertorunthissubroutineandreturntheresults.Thefunctionargumentsarepassedontothescriptas$1,$2,…$n.
![Page 405: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/405.jpg)
NullcheckingwithStrictfunctionsTheSTRICTkeywordwillsaveusfromcheckingthenullinputparameters.IfyouhavespecifiedafunctionasSTRICTandanyoftheinputparametersarenull,itresultsinthefunctionnotbeingcalledandanullresultsetisreturnedimmediately:
postgres=#SELECTtcl_factorial(null);
tcl_factorial
---------------
(1row)
Ifyoudon’twanttocreateaSTRICTfunction,oryou’dliketodothenullcheckingyourself,youcanrewritethefunction,asshowninthefollowingcodesnippet.Thisisusefulifyouhavemultipleparametersandyouwanttoallowsomeparameterstobenull:
CREATEORREPLACEFUNCTIONtcl_factorial_ns(integer)RETURNSinteger
AS$$
if{[argisnull1]}{
elogNOTICE"inputisnull"
return-1
}
seti1;setfact1
while{$i<=$1}{
setfact[expr$fact*$i]
incri
}
return$fact
$$LANGUAGEpltcl;
Theargisnullfunctionisusedtocheckfornullvalues.Intheprecedingexample,thefunctionreturns-1iftheinputargumentisnull,justtodemonstratethatitworks.Ifyouwanttoreturnanullvaluefromthefunction,youcanusethebuilt-infunctionreturn_null.Intheprecedingexample,youcanalsoseehowtousetheelogfunctioninPL/Tcl:
postgres=#SELECTtcl_factorial_ns(null);
tcl_factorial_ns
------------------
-1
(1row)
![Page 406: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/406.jpg)
TheparameterformatAllinputparameterspassedtoPL/Tclareconvertedtotext.WithinaPL/Tclfunction,allvaluesaretext.Whenthefunctionreturns,anotherconversionisperformedfromthetextstringtothereturntypeofthefunction,aslongasthetextbeingreturnedisanappropriaterepresentationofthereturntypeofthePl/Tclfunction;otherwise,thefunctionwillresultinanerror.
![Page 407: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/407.jpg)
![Page 408: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/408.jpg)
PassingandreturningarraysIfyoupassarraytypesasanargumenttothePL/Tclfunction,theyarepassedasastringvalue,alongwiththebracketsandthecommas.Let’stakealookatanexample:
CREATEORREPLACEFUNCTIONtcl_array_test(integer[])RETURNSint
AS$$
setlength[stringlength$1]
return$length
$$LANGUAGEpltcl;
testdb=#selecttcl_array_test(ARRAY[1,2,3]);
tcl_array_test
----------------
7
(1row)
Youareprobablysurprisedatthereturnvalueoftheprecedingfunction.Youpassedanintegerarraytothefunctionthatisconvertedtoastringvalue{1,2,3},thelengthofwhichisindeed7.Ifyouwanttoprocessarrayvaluesindependently,youneedabitofstringmanipulationtoextractthelistoutofthestring,dothemanipulation,andconvertitbacktothestringformatthatyoureceiveditin.
Let’stakealookatanexamplePL/Tclfunctionthatwillreverseanintegerarrayandreturnthereversedintegerarray:
CREATEORREPLACEFUNCTIONtcl_reverse_array(integer[])RETURNSinteger[]
AS$$
setlst[regexp-all-inline{[0-9]}$1]
setlst[join[lreverse$lst]","]
setlst"{$lst}"
return$lst
$$LANGUAGEpltcl;
postgres=#selecttcl_reverse_array(ARRAY[1,2,3]);
tcl_reverse_array
-------------------
{3,2,1}
(1row)
Theprecedingfunctiondoesthefollowing:
1. Thetcl_reverse_arrayfunctioncleansuptheinputparameterbycreatingalistoutofthestringandremovingthe{and,characters.Thisisdoneusingaregularexpressionandbyonlyextractingnumericvaluesoutofthestring.
2. Itusesthelreversefunctiontoreversethecontentsofthelistandthenjointheelementsofthelistbackasanarray,usingthejoinfunctionandusing,asthejoincharacter.
3. Then,itaddsbracketstothestringbeforereturningit.Thereturnstringisconvertedtoanintegerarrayasitisreturnedbythefunction.
![Page 409: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/409.jpg)
![Page 410: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/410.jpg)
Passingcomposite-typeargumentsAcomposite-type,suchasatable,orauser-definedtypeispassedtothePL/Tclfunctionasanassociativearray(Hashtable).Theattributenamesofthecomposite-typearetheelementnamesinthearray.AttributeswithNULLvaluesarenotavailableintheTclarray.
Let’stakealookatanarbitraryexample.Wewillcreateafunctionthattakesacompositetypeasanargumentanddoessomecalculationsbasedontheattributevaluesofthetype.Let’screateourtypeandthefunction:
CREATETABLEorders(orderidint,num_peopleinteger,order_amountdecimal);
INSERTINTOordersVALUES(1,1,23);
INSERTINTOordersVALUES(2,3,157);
INSERTINTOordersVALUES(3,5,567.25);
INSERTINTOordersVALUES(4,1,100);
CREATEORREPLACEFUNCTIONtip_calculator(orders,integer)RETURNSdecimal
AS$$
if{$1(order_amount)>0}{
settip[expr(double($1(order_amount)*$2)/100)/$1(num_people)]
settip[format"%.2f"$tip]
return$tip
}
return0;
$$LANGUAGEpltcl;
Theorderstableisquitesimpletounderstand:itcontainsanorderID,thenumberofpeopleintheorderstable(num_people),andthetotalcostoftheorder(order_amount).
Thefunctioncalculatesthetipperperson,basedonthepriceofthemeal(order_amount)andnumberofpeople.Ittakesanargumentofthetypeordersandanintegervaluethatrepresentthepercentageofthetipthatshouldbepaid.
Thefunctionbodycalculatesthetipandformatstheresulttotwodecimalplaces.Ifwerunourfunction,thisiswhatweshouldsee:
postgres=#SELECTtip_calculator(orders.*,5)AS"tipperperson"FROM
orders;
tipperperson
----------------
1.15
2.62
5.67
5.00
(4rows)
Youcanseethatalltheattributesoftheorderstypecanbeaccessedinthefunctionas$1(order_amount),$1(num_people),andsoon.Thisfunctiongetscalledonceforeachrowoftheorderstableandcalculatestheamountofthetiptobepaidperpersonforeachorder,accordingtovariousparameters.
Note
![Page 411: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/411.jpg)
YoucanseethefulllistofassociativearraycommandsintheofficialdocumentationforTclathttp://www.tcl.tk/man/tcl8.5/tutorial/Tcl22.html.
Atthismoment,PL/Tclfunctionsdon’tallowthereturningofaSETOFtype,orcompositetype,fromafunction.
![Page 412: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/412.jpg)
![Page 413: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/413.jpg)
AccessingdatabasesPL/TclfunctionsprovideyouwithSPIfunctionstoaccessthedatabaseandrunDML/DDLstatements.
Thefunctionsarethefollowing:
spi_exec:ThisexecutesaSQLstatementspi_prepare:ThispreparesaSQLstatementspi_execp:Thisexecutesapreparedstatement
Thespi_execfunctionhasthefollowingsyntax:
spi_exec?-countn??-arrayname?command?loop-body?
Thespi_execfunctionrunsaSQLstatement,andittakessomeoptionalparameters,asfollows:
-count:Thisparameterallowsyoutospecifythemaximumnumberofrowsprocessedbythecommand.Ifyouprovidethevalue3,only3rowswillbeprocessed.ThisissimilartospecifyingFETCH[n]inacursor.-array:Ifthisparameterisspecified,thecolumnvaluesarestoredintoanamedassociativearrayandthecolumnnamesareusedasarrayindexes.Ifthisparameterisnotspecified,theresultvaluesarestoredintheTclvariablesofthesamename.
Ifthereisaloopbodyspecified,thenitistreatedasascriptthatisrunforeachrow.
Let’stakealookatanexampleofhowtorunSQLstatementsinsideaPL/Tclfunction.Thefollowingexample,createsafunctionthatloopsovertherowsinatableandupdatesacolumnineachrow:
CREATETABLEemp_sales(empidintPRIMARYKEY,sales_amntdecimal,
comm_percdecimal,
comm_amntdecimal);
INSERTINTOemp_salesVALUES(1,32000,5,NULL);
INSERTINTOemp_salesVALUES(2,5231.23,3,NULL);
INSERTINTOemp_salesVALUES(3,64890,7.5,NULL);
CREATEORREPLACEFUNCTIONtcl_calc_comm()RETURNSint
AS$$
spi_exec-arrayC"SELECT*FROMemp_sales"{
setcamnt[expr($C(sales_amnt)*$C(comm_perc))/100]
spi_exec"updateemp_sales
setcomm_amnt=[format"%.2f"$camnt]
whereempid=$C(empid)"
}
$$LANGUAGEpltcl;
Theprecedingexample,doesthefollowing:
Itcreatesatableemp_sales,whichcontainstheemployeeID,howmuchsalestheemployeehasmade,andwhatistheircommissionpercentage.Thelastcolumnthat
![Page 414: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/414.jpg)
representsthetotalcommissiontobepaidtotheemployeebasedonhis/hersalesandhis/hercommissionpercentageisleftblankintentionally,anditisfilledbyourfunction.Itfillsthetablewithsomerandomdata.Then,thefunctionbodyrunsaSQLstatementusingthespi_execcommand,andthecolumnvaluesarereturnedintheassociativearraycalledC.Finally,theloopbodycalculatesthecommissionvalueandupdatesthecomm_amntcolumnforeachrow.
NoteYoucanreadmoreaboutaccessingthedatabaseinaPL/Tclfunctionathttp://www.postgresql.org/docs/current/interactive/pltcl-dbaccess.html.
![Page 415: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/415.jpg)
![Page 416: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/416.jpg)
WritingPL/TcltriggersIfyouwanttowritetriggerfunctionsusingTcl,thenPL/PTclallowsyoutodoallthegoodstuffthatyouhavelearnedsofar,usingPL/pgSQL,PL/Perl,andPL/Python.Let’srewriteanexamplewedemonstratedinChapter5,PL/pgSQLTriggerFunctions.Recallthesimple,“Hey,Iamcalled”trigger.ThisishowthePL/Tclversionoftheexamplelooks:
CREATEORREPLACEFUNCTIONnotify_trigger_pltcl()RETURNSTRIGGER
AS$$
setresult[format"Hi,Igot%sinvokedFOR%s%s%son%s"$TG_name
$TG_level$TG_when$TG_op$TG_table_name]
if{$TG_op=="UPDATE"}{
appendresult[format"OLD=%sANDNEW=%s"$OLD(i)$NEW(i)]
setNEW(i)[expr$OLD(i)+$NEW(i)]
elogNOTICE$result
return[arraygetNEW]
}elseif{$TG_op=="DELETE"}{
elogNOTICE"DELETE"
returnSKIP
}elogNOTICE$result
returnOK
$$LANGUAGEpltcl;
CREATETABLEnotify_test_pltcl(iint);
CREATETRIGGERnotify_insert_pltcl_trigger
BEFOREINSERTORUPDATEORDELETEONnotify_test_pltcl
FOREACHROW
EXECUTEPROCEDUREnotify_trigger_pltcl();
TheprecedingcodeisalmostacarboncopyoftheoneinChapter11,PL/Perl–PerlProceduralLanguage,butintheTclsyntax.ItdemonstrateshowtouseTGvariables,howtomodifyNEWvalues,andhowtoSKIPanoperation.
Itprints“HeyIgotinvoked”withdifferentattributesofthetrigger.InthecaseofanUPDATE,italsoprintstheNEWandOLDvalues,aswellasmodifiestheNEWvalueandskipstheDELETEoperation.APL/Tcltriggerfunctioncanreturnthefollowingvalues:
OK:ThisisthedefaultvalueandimpliesthattheoperationexecutedbytheuserwillproceednormallySKIP:Thisreturnvalueimpliesthattheuser-executedoperationwillbesilentlyignoredLIST:ThisisreturnedbyarraygetandimpliesthatamodifiedversionoftheNEWarrayshouldbereturnedOLDandNEW:ThesevaluesareavailableasassociativearraysinaPL/Tcltriggerfunction,andtheattributesofthetablearethenamesoftheelementsinthearray
Let’srunINSERT,UPDATE,andDELETEtoseetheresults:
postgres=#INSERTINTOnotify_test_pltclVALUES(1);
NOTICE:Hi,Igotnotify_insert_pltcl_triggerinvokedFORROWBEFORE
INSERTonnotify_test_pltcl
![Page 417: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/417.jpg)
INSERT01
postgres=#UPDATEnotify_test_pltclSETi=10;
NOTICE:Hi,Igotnotify_insert_pltcl_triggerinvokedFORROWBEFORE
UPDATEonnotify_test_pltclOLD=1ANDNEW=10
UPDATE1
postgres=#DELETEFROMnotify_test_pltcl;
NOTICE:DELETE
DELETE0
postgres=#SELECT*FROMnotify_test_pltcl;
i
----
11
(1row)
InaPL/Tcltriggerfunction,the$TGvariablescontaininformationaboutthecurrenttriggerevent.Youcanseethefulllistofvariablesathttp://www.postgresql.org/docs/current/interactive/pltcl-trigger.html.
Thevariableswehaveusedinourexampleareexplainedinthefollowingtable:
Triggername Description
$TG_name Thisdenotesthenameofthetrigger.Inourexample,thiswillcontainnotify_trigger_pltcl.
$TG_level ThisisaROWorSTATEMENTtrigger.Inourexample,thiswillcontainROW.
$TG_when ThisisaBEFORE,AFTER,orINSTEADOFtrigger.Inourexample,thiswillcontainBEFORE.
$TG_opThisisanINSERT,UPDATE,DELETE,orTRUNCATEtrigger.Inourexample,thiswillcontainINSERT,UPDATE,orDELETE.
$TG_table_name Thisdenotesthenameofthetable.Inourexample,thiswillcontainnotify_test_pltcl.
$OLD(i) ThiswillcontaintheOLDvalueofthecolumni.Inourexample,thiswillcontain1.
$NEW(i) ThiswillcontaintheNEWvalueofthecolumni.Inourexample,thiswillcontain10.
![Page 418: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/418.jpg)
![Page 419: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/419.jpg)
UntrustedTclUsinguntrustedTcl(pltclu)isoneoftheoldestwaystodothingsoutsidethedatabase.pltcluisexecutedusinganormalTclinterpreterandisprettymuchfreetodoanythingyou’dlike.Tclhasalotofcommandsavailabletointeractwiththeoperatingsystemandtheenvironment.Wewillnowtakealookatafewsimpleexamples.
Thefirstexample,readsthecontentsofthefileandreturnsthemastext,asshowninthefollowingcode:
CREATEORREPLACEFUNCTIONread_file(text)RETURNStext
AS$$
setfptr[open$1]
setfile_data[read$fptr]
close$fptr#closethefileasitisalreadyread
return$file_data
$$LANGUAGEpltclu;
Thefunctionisquitesimple;itopensafileprovidedasaparameter,readsallitscontentsatonce,andreturnsthetext.
Let’sruntheprecedingfunction:
postgres=#selectread_file('/usr/local/pgsql/data/postmaster.pid');
read_file
-----------------------
61588+
/usr/local/pgsql/data+
1401041744+
5432+
/tmp+
localhost+
5432001196608+
(1row)
Hereisanotherfunctionthatdoesadirectorylisting,similartotheplperluexampleinChapter11,PL/Perl–PerlProceduralLanguage.SincePL/TcldoesnotsupportthereturningoftheSETOFtext,wewillsimplyreturnthecompletedirectorylistingasonestring.Asyoucanseeinthefollowingcode,thiscanbedonewithasinglelineinTcl:
CREATEORREPLACEFUNCTIONlist_directory(text)RETURNStext
AS$$
setdirList[glob-nocomplain-directory$1*.*]
return$dirList
$$LANGUAGEpltclu;
testdb=#SELECTlist_directory('/tmp');
list_directory
---------------------------------------------
/tmp/lu84iont.tmp/tmp/unity_support_test.0
(1row)
WereadthecontentsofthefileusingTcl’sglobfunctionandjustreturnedthecontentsasastring.
![Page 420: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/420.jpg)
Let’stakealookatonelastPL/Tclufunctionthatwillexportthecontentstoatableasa.csvfile:
CREATEORREPLACEFUNCTIONdump_table(text,text)RETURNSint
AS$$
setfilename$1
setfileId[open$filename"w"]
spi_exec-arrayemp"SELECT*FROM$2"{
setrow[format"%d,%.2f,%.2f,%.2f"$emp(empid)$emp(sales_amnt)
$emp(comm_perc)$emp(comm_amnt)]
puts$fileId$row
}
close$fileId
return0;
$$LANGUAGEpltcluSTRICT;
Again,thisfunctionisquitesimpleandusestheconceptswehavediscussedbefore.Ititeratesoverthetableprovidedasthesecondparametertothisfunctionandstoresthedatainafilenamed,asperthefirstparameterofthisfunction.Thefileiswrittenlinebylineascomma-separatedvaluesbyiteratingoverthetabledatausingspi_exec.
Let’srunthisfunctionontheemp_salestablethatwecreatedearlierinthischapter:
postgres=#selectdump_table('emp.txt','emp_sales');
dump_table
------------
0
(1row)
Thisseemstowork.Wecanverifythisbyrunningtheread_filefunctionwewroteearlier:
postgres=#selectread_file('emp.txt');
read_file
-------------------------
1,32000.00,5.00,1600.00+
2,5231.23,3.00,156.94+
3,64890.00,7.50,4866.75+
(1row)
Itseemsthatthefunctionworks,andwehaveaCSVdumpofthetableinnotime.
![Page 421: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/421.jpg)
![Page 422: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/422.jpg)
SummaryThepowerful,yetclean,TcllanguageisavailableinPostgreSQLasPL/TclandtheuntrustedPL/Tclu.BoththelanguagesusedifferentTclinterpreters.PL/TcluistheoldestlanguageusedinPostgreSQL,toaccessthingsoutsidethedatabase.ItallowsyoutowritestoredproceduresinTclandtakesadvantageofallthecoolfeaturesthatTclhastooffer.YoucandoalmosteverythingyoucanwithotherPLlanguages,includingdatabaseaccessandwritingtriggers.TheonlymajordisadvantageofPL/Tclisthatitdoesnotallowyoutoreturncompositetypesandsetsfromafunction.
Inthenextchapter,wewillexplorehowtopublishyourcodeasaPostgreSQLextension.
![Page 423: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/423.jpg)
![Page 424: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/424.jpg)
Chapter13.PublishingYourCodeasPostgreSQLExtensionsIfyouarenewtoPostgreSQL,nowisthetimetodanceforjoy.
Nowthatyou’redonedancing,I’lltellyouwhy.Youhavemanagedtoavoidthe“badolddays”ofcontribmodules.ContribmodulesaretheinstallationsystemsthatwereusedtoinstallrelatedPostgreSQLobjectspriortoVersion9.1.Theymaybeadditionaldatatypes,enhancedmanagementfunctions,orjustreallyanytypeofmoduleyouwanttoaddtoPostgreSQL.Theyconsistofanygroupofrelatedfunctions,views,tables,operators,types,andindexesthatwerelumpedintoaninstallationfileandcommittedtothedatabaseinonefellswoop.Unfortunately,contribmodulesonlyprovidedforinstallation,andnothingelse.Infact,theywerenotreallyaninstallationsystematall.TheywerejustsomeunrelatedSQLscriptsthathappenedtoinstalleverythingthattheauthorthoughtyouneeded.
PostgreSQLextensionsprovidemanynewservicesthatapackagemanagementsystemshouldhave.Well,atleasttheonesthatmoduleauthorscomplainedthemostaboutnotbeingpresent.
Someofthenewfeaturesthatyouwillbeintroducedtointhischapterinclude:
VersioningDependenciesUpdatesRemoval
![Page 425: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/425.jpg)
WhentocreateanextensionWell,firstyouhavetounderstandthatextensionsareallabouttogetherness.Oncetheobjectsfromacontribmodulewereinstalled,PostgreSQLprovidednowaytoshowarelationshipbetweenthem.Thisledmanydeveloperstocreatetheirown(andattimesratheringenious)methodstoversion,update,upgrade,anduninstallallofthenecessary“stuff”togetafeaturetowork.
So,thefirstquestiontoaskyourselfwhencontemplatingaPostgreSQLextensionasawaytopublishyourcodeis“Howdoesallofthe‘stuff’inmyextensionrelatetogether?”
Thisquestionwillhelpyoumakeextensionsthatareasgranularasreasonable.IftheobjectiveistoenhancePostgreSQLwiththeabilitytoprovideaninventorymanagementsystem,itmightbebettertostartwithanextensionthatprovidesabillofmaterialsdatatypefirst,andsubsequentlybuildadditionalextensionsthataredependentuponthatone.Themoralofthestoryistodreambig,butcreateeachextensionwithonlythesmallestnumberofrelateditemsthatmakesense.
AgoodexampleofanextensionthatprovidesafeaturetoPostgreSQLisOpenFTS.ThisextensionprovidesfulltextsearchingcapabilitiestoPostgreSQLbycreatingdatatypes,indexes,andfunctionsthatarewellrelatedtoeachother.
AnothertypeofextensionisPostGIS,whichprovidesarichsetoftoolstodealwithgeographicinformationsystems.AlthoughthisextensionprovidesmanymorebitsoffunctionalitythanOpenFTS,itisstillasgranularaspossiblebyvirtueofthefactthateverythingthatisprovidedisnecessaryforgeographicsoftwaredevelopment.
Possibly,youareabookauthor,andtheonlyrelationshipthattheobjectsinyourextensionhaveisthattheyneedtobeconvenientlyremovedwhenyourpoorvictim…ahem…thereaderisthroughwiththem.Welcometothewondersofextensions.
Foralistofveryusefulextensionsthathavegainedsomecommunitypopularity,youmightwanttotakealookatthispagefairlyoften:http://www.postgresql.org/download/products/6/.
YoushouldalsotakealookatthePostgreSQLextensionnetworkathttp://www.pgxn.org.Pleasenotethatinstallingextensionsgenerallymeansrunningascriptasasuperuser;andnearlyanyonecanuploadtopgxn,meaningthatindividualsreallyneedtovetanythingtheygetfrompgxnverycarefully.
NoteTofindoutwhatobjectscanbepackagedintoanextension,lookattheALTEREXTENSIONADDcommandinthePostgreSQLdocumentation:
http://www.postgresql.org/docs/current/static/sql-alterextension.html
![Page 426: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/426.jpg)
![Page 427: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/427.jpg)
UnpackagedextensionsStartingwithVersion9.1,PostgreSQLprovidesaconvenientwaytomovefromtheprimordialoozeofunversionedcontribmodulesintothebravenewworldofextensions.Basically,youprovideaSQLfiletoshowtherelationshipoftheobjectstotheextension.Thecontribmodule’scubeprovidesagoodexampleofthisincube--unpackaged--1.0.sql:
/*contrib/cube/cube--unpackaged--1.0.sql*/
—complainifscriptissourcedinpsql,ratherthanviaCREATEEXTENSION
\echoUse"CREATEEXTENSIONcube"toloadthisfile.\quit
ALTEREXTENSIONcubeADDtypecube;
ALTEREXTENSIONcubeADDfunctioncube_in(cstring);
ALTEREXTENSIONcubeADDfunctioncube(doubleprecision[],double
precision[]);
ALTEREXTENSIONcubeADDfunctioncube(doubleprecision[]);
...
ThecodethatprovidesmultidimensionalcubesforPostgreSQLhasbeenstableforquitesometime.Itisunlikelythatanewversionwillbecreatedanytimesoon.Theonlyreasonforthismoduletobeconvertedintoanextensionistoallowforeasyinstallationandremoval.
Youwouldthenexecutethecommand:
CREATEEXTENSIONcubeFROMunpackaged;
Theunrelateditemsarenowgroupedtogetherintotheextensionnamedcube.Thisalsomakesiteasierforthepackagingmaintaineronanyplatformtoincludeyourextensionintotherepository.We’llshowyouhowtomakethepackagestoinstallyourextensionintheBuildinganextensionsection.
![Page 428: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/428.jpg)
![Page 429: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/429.jpg)
ExtensionversionsTheversionmechanismforPostgreSQLextensionsissimple.Nameitwhateveryouwantandgiveitwhateveralphanumericversionnumberthatsuitsyourfancy.Easy,eh?Justnamethefilesinthisformat:
extension--version.sql
Ifyouwanttoprovideanupgradepathfromoneversionofyourextensiontoanother,youwouldprovidethefile:
extension--oldversion--newversion.sql
ThissimplemechanismallowsPostgreSQLtoupdateanextensionthatisalreadyinplace.Gonearethedaysofpainfulexportingandre-importingdatajusttochangethedefinitionofadatatype.So,let’sgoaheadandupdateourexampleextensionusingthefilepostal--1.0--1.1.sql.Thisupdateisaseasyas:
ALTEREXTENSIONpostalUPDATETO'1.1';
NoteAnoteofcaution:PostgreSQLdoesnothaveanyconceptofwhatyourversionnumbermeans.Inthisexample,theextensionwasupdatedfromVersion1.0to1.1becauseweexplicitlyprovidedascriptforthatspecificconversion.PostgreSQLdidnotdeducethat1.1follows1.0.Wecouldhavejustaseasilyusedthenamesoffruitsorhistoricalbattleshipsforourversionnumbersandtheresultwouldhavebeenthesame.
PostgreSQLwillusemultipleupdatefilesifnecessarytoachievethedesiredresult.Giventhefollowingcommand:
ALTEREXTENSIONpostalUPDATETO'1.4';
PostgreSQLwillapplythefilespostal--1.1--1.2.sql,postal--1.2--1.3.sqlandpostal--1.3--1.4.sqlinthecorrectordertoachievethedesiredversion.
Youmayalsousethistechniquetoprovideupgradescriptsthatareinfactdowngradescripts,thatis,theyactuallyremovefunctionality.Becarefulwiththisthough.Ifapathtoadesiredversionistodowngradebeforeanupgrade,PostgreSQLwilltaketheshortestroute.Thismayresultinsomeunintendedresults,includingdataloss.Myadvicewouldbetonotprovidedowngradescripts.Theriskjustisn’tworthit.
![Page 430: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/430.jpg)
![Page 431: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/431.jpg)
The.controlfileAlongwiththeextensioninstallationscriptfile,youmustprovidea.controlfile.The.controlfileforourexamplepostal.controllookslikethis:
#postaladdressprocessingextension
comment='utilitiesforpostalprocessing'
default_version='1.0'
module_pathname='$libdir/postal'
relocatable=true
requires='plpgsql'
Thepurposeofthe.controlfileistoprovideadescriptionofyourextension.Thismetadatamayincludedirectory,default_version,comment,encoding,module_pathname,requires,superuser,relocatable,andschema.
ThemainPostgreSQLdocumentationforthisfileislocatedathttp://www.postgresql.org/docs/current/static/extend-extensions.html.
Thisexampleshowstherequiresconfigurationparameter.OurextensiondependsontheprocedurallanguagePL/pgSQL.Onmostplatforms,itisinstalledbydefault.Unfortunately,itisnotinstalledonallplatforms,andnothingshouldbetakenforgranted.
Multipledependenciescanbeindicatedbyseparatingthemwithcommas.Thiscomesinveryhandywhenconstructingasetofservicesbasedonmultipleextensions.
Aswementionedintheprevioussection,PostgreSQLdoesnotprovideanyinterpretationoftheversionnumberofanextension.Versionscanbenamesaswellasnumbers,sothereisnowayforPostgreSQLtointerpretthatpostal--lamb.sqlcomesbeforepostal--sheep.sql.Thisdesignlimitationposesaproblemtotheextensiondeveloper,inthatthereisnowaytospecifythatyourextensiondependsonaspecificversionofanotherextension.Iwouldlovetoseethisconfigurationparameterenhancedwithasyntaxlikerequires=postgis>=1.3,butalas,nosuchconstructionexistsatthemoment.
![Page 432: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/432.jpg)
![Page 433: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/433.jpg)
BuildinganextensionWehavealreadycoveredthebasicsofcreatingascriptfileanda.controlfile.Actually,thatisallthatisnecessaryforaPostgreSQLextension.Youmaysimplycopythesefilesintothesharedextensiondirectoryonyourcomputerandexecutethefollowingcommand:
CREATEEXTENSIONpostal;
Thiswillinstallyourextensionintothecurrentlyselecteddatabase.
ThesharedextensionpathisdependentonhowPostgreSQLisinstalled,butforUbuntu,itis/usr/share/postgresql/9.2/extension.
However,thereisamuchbetterwaytodothisthatworkswithanypackagemanageronanyplatform.
PostgreSQLprovidesanextension-buildingtoolkitasapartoftheserverdevelopmentpackage.ToinstallthispackageonUbuntu,youcantype:
sudoapt-getinstallpostgresql-dev-9.4
ThiswillinstallallofthePostgreSQLsourcecodenecessarytocreateandinstallanextension.YouwouldthencreateafilenamedMakefileinthesamedirectoryastherestofyourextensionfiles.Thecontentofthisfilelookslikethis:
EXTENSION=postal
DATA=postal--1.0.sql
PG_CONFIG=pg_config
PGXS:=$(shell$(PG_CONFIG)--pgxs)
include$(PGXS)
ThissimpleMakefilefilewillcopyyourextensionscriptfileandthe.controlfileintothepropersharedextensiondirectoryonanyplatform.Invokeitwiththiscommand:
sudomakeinstall
Youwillseesomeoutputlikethis:
/bin/mkdir-p'/usr/share/postgresql/9.4/extension'
/bin/sh
/usr/lib/postgresql/9.4/lib/pgxs/src/makefiles/../../config/install-sh-c-
m644./postal.control'/usr/share/postgresql/9.4/extension/'
/bin/sh
/usr/lib/postgresql/9.4/lib/pgxs/src/makefiles/../../config/install-sh-c-
m644./postal--1.0.sql'/usr/share/postgresql/9.4/extension/'
Yourextensionisnowlocatedintheproperdirectoryforinstallation.Youcaninstallitintothecurrentdatabasewith:
CREATEEXTENSIONpostal;
Youwillthenseetheconfirmationtextlettingyouknowthatyouhavenowgonepostal:
CREATEEXTENSION
![Page 434: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/434.jpg)
![Page 435: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/435.jpg)
InstallinganextensionExtensionsthathavebeenpackagedforyoubyyourfriendlydistributionmanagerareverysimpletoinstallusingthefollowingcommand:
CREATEEXTENSIONextension_name;
MostofthepopularLinuxdistributionsincludeapackagecalledsomethinglikepostgresql-contrib-9.4.ThisnamingconventionisleftoverfromthecontribstyleinstallationofPostgreSQLobjects.Don’tworry,forPostgreSQL9.4,thispackagewillactuallyprovideextensionsratherthancontribmodules.
TofindoutwherethefileswereplacedonUbuntuLinux,youcanexecutethefollowingcommand:
pg_config--sharedir
Thiswillshowyoutheinstallationdirectoryofsharedcomponents:
/usr/share/postgresql/9.4
Theextensionswillbelocatedinadirectorycalled,extension,immediatelybelowtheshareddirectory.Thiswillthenbenamed/usr/share/postgresql/9.2/extension.
Toseewhatextensionsareavailableforyoutoinstall,trythiscommand:
ls$(pg_config–sharedir)/extension/*.control
Youcanalsoseethelistofinstalledextensionsusingtheplsqlmeta-command\dx.
ThiswillshowyoualltheextensionsthathavebeenmadeavailabletoyoubyyourLinuxdistribution’spackagemanagementsystem.
Forextensionsthatyouhavecreatedyourself,youmustcopyyourSQLscriptfileandthe.controlfiletothesharedextensiondirectorybeforeinvokingCREATEEXTENSIONinPostgreSQL.
cppostal.controlpostal--1.0.sql$(pg_config--sharedir)/extension
Toseetheprocedurefordoingthisreliablyonanytargetplatform,refertotheBuildinganExtensionsection.
![Page 436: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/436.jpg)
![Page 437: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/437.jpg)
ViewingextensionsQueryingthepg_extensionsystemvieworusingthemeta-command\dxwillshowtheextensionscurrentlyinstalledinthedatabase.
postgres=#\dx
Listofinstalledextensions
-[RECORD1]-----------------------------
Name|pgcrypto
Version|1.0
Schema|public
Description|cryptographicfunctions
-[RECORD2]-----------------------------
Name|plperl
Version|1.0
Schema|pg_catalog
Description|PL/Perlprocedurallanguage
-[RECORD3]-----------------------------
Name|plpgsql
Version|1.0
Schema|pg_catalog
Description|PL/pgSQLprocedurallanguage
Theextensionsthatarereadytobeinstalledcanbeviewedfromthepg_available_extensionsorpg_available_extension_versionssystemviews.
![Page 438: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/438.jpg)
![Page 439: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/439.jpg)
PublishingyourextensionThankyouforcontributingtothePostgreSQLcommunity!Yoursupportwillnotgounnoticedinthisgatheringoflike-mindedindividualswhoareallslightlysmarterthaneachother.Yourworkwillbeseenbydozensofdeveloperslookingforcommunitysolutionstocommonproblems.Youhaveindeedmadetheopensourceworldabetterplace.
Sincewearetalkingaboutpublication,youshouldconsiderthelicensingmodelforyourextension.Thepublicationmethodsthatweareabouttodescribeassumethattheextensionwillbemadeavailabletothegeneralpublic.Assuch,pleaseconsiderthePostgreSQLlicenseforyourextension.Youcanfindthecurrentonehere:
http://www.postgresql.org/about/licence/
![Page 440: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/440.jpg)
IntroductiontoPostgreSQLExtensionNetworkWhenyouwanttopublishyourmodule,youcouldstartwritingpackagingscriptsforeachofthedistributionsystemsforeveryoperatingsystem.ThisisthewaythePostgreSQLextensionshavebeendistributedinthepast.Thatdistributionsystemhasnotbeenveryfriendlytotheopensourcecommunity,orverywellreceived.Inanefforttomakeextensionpublicationmorepalatable,agroupofopensourcewritersandbackingcompaniesgottogetherandfoundedthePostgreSQLExtensionNetwork(PGXN).
ThePostgreSQLExtensionNetworkhttp://pgxn.org/providesacentralrepositoryforyouropensourceextensions.Bythekindnessofthemaintainers,italsoprovidesinstallationscriptsforyourextensionsthatwillworkonmostofthepopularPostgreSQLdeploymentoperatingsystems.
![Page 441: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/441.jpg)
SigninguptopublishyourextensionTosignuptopublishyourextension,performthefollowingsteps:
1. Startbyrequestinganaccountonthemanagementpage:http://manager.pgxn.org.2. ClickonRequestAccountandfillinyourpersonalinformation.ThePostgreSQL
ExtensionNetworkfolkswillgetbacktoyouviae-mail.Enrollmentrequestsarecurrentlyprocessedbyanactualhuman,sothee-mailresponsewillnotbeimmediate.
3. Clickontheprovidedlinkinthee-mailtoconfirmyouraccountandsetanewpasswordonthePGXNwebsite:
4. Youwillthenbepromptedtocreateapasswordforyouraccount:
![Page 442: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/442.jpg)
5. Setapasswordthatyouwillremember,andconfirmbytypingitagain.ClickonChangeandyouwillbewelcomedtothesite:
![Page 443: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/443.jpg)
Thatisallthereistogettingsignedup.Onceyouhaveyournewaccountsetup,youcandoafewthingsthatwillmakePostgreSQLextensionprogrammingmuchmorepainless.
![Page 444: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/444.jpg)
CreatinganextensionprojecttheeasywayFirst,let’sinstallsomeutilitypackagesthatwillcreatealotofboilerplatefilesthatwehavealreadydescribedinearliersections.ThecommandsbelowareforaDebian/Ubuntusystem:
apt-getinstallruby
apt-getinstallrubygems
apt-getinstallruby1.8-dev
apt-getinstalllibopenssl-ruby1.8
geminstallrubygems-update
/var/lib/gems/1.8/bin/update_rubygems
geminstallpgxn_utils
Youwillnowfindthatyouhaveautilityinstallednamedpgxn-utils.Thisutilitymakesitsupersimpletocreateanextensionproject.
pgxn-utilsskeletonmyextension
createmyextension
createmyextension/myextension.control
createmyextension/META.json
createmyextension/Makefile
createmyextension/README.md
createmyextension/doc/myextension.md
createmyextension/sql/myextension.sql
createmyextension/sql/uninstall_myextension.sql
createmyextension/test/expected/base.out
createmyextension/test/sql/base.sql
Wow!Allofthefilesthatwehavementionedsofarjustgotcreatedinasinglestep.Severalfilesalsogotcreatedtosupporttheoldcontribstyleofdeployment.Thenextfewsectionswillshowwhichonesareimportanttoyouforextensiondevelopment.
Thispackagemanagementsystemhasonenotablerestriction.IncontrasttoPostgreSQL,whichallowsversionnumberstobeanyalphanumerictext,thispackagemanagementrequiresversionnumberstofollowtherulesofsemanticversioning.
Thisversionformatincludesmajorversion,minorversion,andreleasenumberintheformatmajor.minor.release.Thisistoassistthepackagemanagerininstallingyourpackageonmultipleoperatingsystemplatforms.Justgowithit,you’llthankuslater.
![Page 445: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/445.jpg)
ProvidingthemetadataabouttheextensionTherearethreefilesusedtoprovidedataabouttheextension.ThePostgreSQLExtensionNetworkusesoneofthemonthewebsite,META.json,forsearchcriteriaanddescriptiontextfortheextension.META.jsonwillbelocatedinmyextension/META.json.
Hereisanexample:
{
"name":"myextension",
"abstract":"Ashortdescription",
"description":"Alongdescription",
"version":"0.0.1",
"maintainer":"Themaintainer'sname",
"license":"postgresql",
"provides":{
"myextension":{
"abstract":"Ashortdescription",
"file":"sql/myextension.sql",
"docfile":"doc/myextension.md",
"version":"0.0.1"
}
},
"release_status":"unstable",
"generated_by":"Themaintainer'sname",
"meta-spec":{
"version":"1.0.0",
"url":"http://pgxn.org/meta/spec.txt"
}
}
Youshouldaddsomesectionstoittodescribeyourkeywordsandanyadditionalresourcesthatyoumakeavailabletotheuser.Thesesectionswouldlooklikethis:
"tags":[
"curescancer",
"myextension",
"createsworldpeace"
],
"resources":{
"bugtracker":
{"web":"https://github.com/myaccount/myextension/issues/"},
"repository":{
"type":"git",
"url":"git://github.com/myaccount/myextension.git",
"web":"https://github.com/myaccount/myextension/"
}
}
Thecompletefilewouldthenlooklikethis:
{
![Page 446: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/446.jpg)
"name":"myextension",
"abstract":"Ashortdescription",
"description":"Alongdescription",
"version":"0.0.1",
"maintainer":"Themaintainer'sname",
"license":"postgresql",
"provides":{
"myextension":{
"abstract":"Ashortdescription",
"file":"sql/myextension.sql",
"docfile":"doc/myextension.md",
"version":"0.0.1"
}
},
"release_status":"unstable",
"generated_by":"Themaintainer'sname",
"meta-spec":{
"version":"1.0.0",
"url":"http://pgxn.org/meta/spec.txt"
}
"tags":[
"curescancer",
"myextension",
"createsworldpeace"
],
"resources":{
"bugtracker":
{"web":"https://github.com/myaccount/myextension/issues/"},
"repository":{
"type":"git",
"url":"git://github.com/myaccount/myextension.git",
"web":"https://github.com/myaccount/myextension/"
}
}
}
ThenextfilethatyouwillneedtomodifyisREADME.md.Thisfileislocatedinmyextension/README.md.Anexampleisprovidedwiththecodethataccompaniesthisbook.Duetothelength,itwillnotbereproducedhere.Thisfileisdistributedalongwithyourextension.Itisamarkdownsyntaxfilethatismeantforhumanconsumption.Describeanythingyoulikeinit.MineincludesarecipeforDönerKebabs.Quitetasty!Butmostimportantly,putanicelongdescriptionofthebenefitsandeaseofuseofyourextension.Finally,wecometodoc/myextension.md.ThisfileisusedbythePostgreSQLExtensionNetworktoprovideaverynicelandingpageforyourextension.Itwilllooksomethinglikethis:
![Page 447: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/447.jpg)
Thisfileisformattedwithmarkdown.Youmayuseseveraldifferentmarkupsyntaxeshere.Adiscussionofwikimarkupisbeyondthescopeofthisdescription,buttheformattingthatisintheexampleislikelytobeallyouwilleverneedanyway.
Hereisanexampleofthecontentofthefile:
myextension
===========
Synopsis
--------
Showabriefsynopsisoftheextension.
Description
-----------
![Page 448: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/448.jpg)
Alongdescription
Usage
-----
Showusage.
Support
-------
Thereisissuestracker?Github?Putthisinformationhere.
Author
------
[Themaintainer'sname]
CopyrightandLicense
---------------------
Copyright(c)2012Themaintainer'sname.
Filloutthefilewithsomedescriptivenarrativeaboutyourextension.Addanythingthatyouthinkmightberelevanttotheuserthatisevaluatingyourextensionbeforemakingadecisiontoinstallit.ThisisyourchancetoimpressthemassesofPostgreSQLdevelopers.Sodon’tbeshyhere.
![Page 449: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/449.jpg)
WritingyourextensioncodePutyourSQLcodeinthefilethatwasprovidedforyouinmyextension/sql/myextension.sql.Thisfileshouldcontainalloftheobjectsthatmakeupyourextension.
/*myextension.sql*/
—complainifscriptissourcedinpsql,ratherthanviaCREATEEXTENSION
\echoUse"CREATEEXTENSIONmyextension"toloadthisfile.\quit
CREATEFUNCTIONfeed_the_hungry()...
YoucanprovideanyadditionalSQLfilesinthesamedirectoryformaintainingversionsasdescribedintheExtensionversionssection.Anythingnamed*.sqlthatislocatedinthisdirectorywillbeincludedinthedistribution.
![Page 450: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/450.jpg)
CreatingthepackageToultimatelysubmitourextensiontothePostgreSQLExtensionNetwork,weneedtopackageallthefilesintoasingle.zipfile.Assumingwe’refollowinggoodpractices,andwe’rekeepingallofoursourcecodeinahandyGitrepository,wecancreatethepackagethroughasimpleGitcommand.Trythisoneonforsize:
gitarchive--formatzip--prefix=myextension-0.0.1/\
--output~/Desktop/myextension-0.0.1.zipmaster
ThiscommandwillcreateapackageforyouthatissuitableforsubmissiontothePostgreSQLExtensionNetwork.Allweneedtodonowissubmitit.
![Page 451: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/451.jpg)
SubmittingthepackagetoPGXNNowthatyouhaveaniceZIPfileinhand,youcangotothePostgreSQLExtensionNetworkandmakeyouraccomplishmentavailabletothecommunity.
1. Startbygoingtohttp://www.pgxn.org:
2. AtthebottomofthepageisalinknamedReleaseIt.ClickonthelinkandyouwillbetakentothePGXNManagerwhereyoushouldloginwiththeusernameandpasswordthatyoucreatedinthefirstsection:
![Page 452: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/452.jpg)
3. ClickonthelinkUploadaDistribution.ThiswillbringyoutothescreenwhereyoucanuploadtheZIPfilethatyoucreatedintheCreatingthepackagesection:
![Page 453: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/453.jpg)
4. BrowseyourcomputerfortheZIPfileanduploadittothePostgreSQLExtensionNetwork.
That’sit.ThanksagainforcontributingtothePostgreSQLcommunity.
![Page 454: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/454.jpg)
![Page 455: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/455.jpg)
InstallinganextensionfromPGXNThePostgreSQLExtensionNetworkprovidesaplatform-independenttooltoinstallPostgreSQLextensions.ThistooliswritteninPython,andusesthePythoninstallationsystemfordistributingitself.ThisishandybecausethePythondistributionsystemexistsvirtuallyoneveryPostgreSQLsupportableplatformandmakesitverysimpletogetPostgreSQLextensionsdistributedtothecommunity.Theextensioninstallerworkswithasinglesetofinstructionsonalltargets:
easy_installpgxnclient
Installingpgxncli.pyscriptto/usr/local/bin
Installingpgxnscriptto/usr/local/bin
Processingdependenciesforpgxnclient
Finishedprocessingdependenciesforpgxnclient
NowyouhavethetoolsinstalledtomanagePostgreSQLextensionsprovidedbythePostgreSQLExtensionNetwork.
Installingextensionsisreallysimple.Forexample,ifwehadarequirementtouseanewtinyintdatatype,wecouldadditwiththiscommand:
pgxninstalltinyint
INFO:bestversion:tinyint0.1.1
INFO:saving/tmp/tmpKvr0kM/tinyint-0.1.1.zip
INFO:unpacking:/tmp/tmpKvr0kM/tinyint-0.1.1.zip
INFO:buildingextension…
Theextensionisnowavailableinthesharedextensionsdirectoryonyourmachine.Toactivateitforanydatabase,youwouldusethecommandthatwestartedthechapterwith:
CREATEEXTENSIONtinyint;
Youwillthenseetheconfirmationtextlettingyouknowthattinyinthasbeenadded:
CREATEEXTENSION
Younowhavetheextensionavailableforuseinyourlocaldatabase.Enjoy!
![Page 456: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/456.jpg)
![Page 457: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/457.jpg)
SummaryWow,thishasbeenalonghardroadtowardgettinganextensionconfiguredandinstalled.Wehaveusedprogrammingskills,systemadministrativeskills,databaseadministrativeskills,andwikiediting.Alongtheway,wesawsomeRuby,Python,shellscripting,PL/pgSQL,andMediaWiki.
Believeitornot,thisisthesimplifiedprocess.Hardtoimagine,eh?Well,continuousworkisbeingdoneonthePostgreSQLExtensionNetworktofurthersimplifythiscatastropheofadevelopmentsystem.MythanksgoouttoDavidE.Wheelerandcrewformakingthisnewsystemavailable.Astheframeworknowexiststohelpwiththetask,therewillbedramaticimprovementscominginthemonthsandyearsahead.
NowthatI’mdonecomplainingaboutit,thisextensionsystemisactuallyrevolutionary.Isaythisbecausenootherdatabaseplatformprovidesanysuchframeworkatall.PostgreSQLleadsthepackwhenitcomestotheabilitytomakechangestothebasicfunctionalityoftheproduct.ThefactthatextensionscanbeinstalledandremovedfromtheproductisanindicatorofhowinvitingPostgreSQListotheopensourcecommunity.
Extendittodowhateveryouwant,andthey’llgiveyouthetoolstodoit.ThismakesaPostgreSQLservertheperfectframeworktouseforyourdataprocessingneeds.
Inthenextchapter,wewilllearnmoreaboutPostgreSQLasanextensibledatabaseandlookathowtocreateuser-defineddatatypesandoperators.
![Page 458: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/458.jpg)
![Page 459: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/459.jpg)
Chapter14.PostgreSQLasanExtensibleRDBMSPostgreSQLisanextensibledatabase.Ihopeyou’velearnedthismuchbynow.Itisextensiblebyvirtueofthedesignthatithas.Asdiscussedbefore,PostgreSQLusesacatalog-drivendesign.Infact,PostgreSQLismorecatalog-driventhanmostofthetraditionalrelationaldatabases.Thekeybenefithereisthatthecatalogscanbechangedoraddedto,inordertomodifyorextendthedatabasefunctionality.PostgreSQLalsosupportsdynamicloading,thatis,auser-writtencodecanbeprovidedasasharedlibrary,andPostgreSQLwillloaditasrequired.
Extensibilityiscriticalformanybusinesses,whichhaveneedsthatarespecifictothatbusinessorindustry.Sometimes,thetoolsprovidedbythetraditionaldatabasesystemsdonotfulfillthoseneeds.Peopleinthosebusinessesknowbesthowtosolvetheirparticularproblems,buttheyarenotexpertsindatabaseinternals.Itisoftennotpossibleforthemtocookuptheirowndatabasekernelormodifythecoreorcustomizeitaccordingtotheirneeds.Atrulyextensibledatabasewillthenallowyoutodothefollowing:
Solvedomain-specificproblemsinaseamlessway,likeanativesolutionBuildcompletefeatureswithoutmodifyingthecoredatabaseengineExtendthedatabasewithoutinterruptingavailability
PostgreSQLnotonlyallowsyoutodoalloftheprecedingthings,butalsodoesthese,andmorewithutmostease.Intermsofextensibility,youcandothefollowingthingsinaPostgreSQLdatabase:
1. Createyourowndatatypes2. Createyourownfunctions3. Createyourownaggregates4. Createyourownoperators5. Createyourownindexaccessmethods(operatorclasses)6. Createyourownserverprogramminglanguage7. Createforeigndatawrappers(SQL/MED)andforeigntables
Sofarinthisbook,youlearnedtocreatefunctionsandtriggersinvariousprogramminglanguagesavailableinPostgreSQL,aswellascreateuser-definedtypes.Youalsolearnedhowtousethesefunctionsintriggersandrules.Asyoucansee,therearemanymoretypesofextensionsyoucandotothedatabase,andthisprovidesyouwithallthetoolsyouneedtocustomizeandextendthedatabasetosuityourbusinessneeds.Beforewediscussthepreviouslymentionedcasesbriefly,let’stakealookatwhatyoucan’textendinPostgreSQL.
![Page 460: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/460.jpg)
Whatcan’tbeextended?AlthoughPostgreSQLisanextensibleplatform,therearecertainthingsthatyoucan’tdoorchangewithoutexplicitlydoingafork,asfollows:
1. Youcan’tchangeorpluginanewstorageengine.IfyouarecomingfromtheMySQLworld,thismightannoyyoualittle.However,PostgreSQL’sstorageengineistightlycoupledwithitsexecutorandtherestofthesystem,whichhasitsownbenefits.
2. Youcan’tpluginyourownplanner/parser.Onecanargueforandagainsttheabilitytodothat,butatthemoment,theplanner,parser,optimizer,andsoonarebakedintothesystemandthereisnopossibilityofreplacingthem.Therehasbeensometalkonthistopic,andifyouareofthecuriouskind,youcanreadsomeofthediscussionathttp://bit.ly/1yRMkK7.
3. WewillnowbrieflydiscusssomemoreoftheextensibilitycapabilitiesofPostgreSQL.Wewillnotdivedeepintothetopics,butwewillpointyoutotheappropriatelinkwheremoreinformationcanbefound.Thechaptermaterialwillserveasaneasy-to-understandintroductorytutorialonthesubjectmatter.Itisbynomeansacomprehensivediscussionofthetopics.
![Page 461: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/461.jpg)
![Page 462: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/462.jpg)
CreatinganewoperatorNow,let’stakelookathowwecanaddanewoperatorinPostgreSQL.Addingnewoperatorsisnottoodifferentfromaddingnewfunctions.Infact,anoperatorissyntacticallyjustadifferentwaytouseanexistingfunction.Forexample,the+operatorcallsabuilt-infunctioncallednumeric_addandpassesitthetwoarguments.
Whenyoudefineanewoperator,youmustdefinethedatatypesthattheoperatorexpectsasargumentsanddefinewhichfunctionistobecalled.
Let’stakealookathowtodefineasimpleoperator.YouhavetousetheCREATEOPERATORcommandtocreateanoperator.
InChapter2,ServerProgrammingEnvironments,wewroteafunctiontocalculatetheFibonaccinumberofagiveninteger.Let’susethatfunctiontocreateanewFibonaccioperator,##,whichwillhaveanintegeronitsleft-handside:
CREATEOPERATOR##(PROCEDURE=fib,LEFTARG=integer);
Now,youcanusethisoperatorinyourSQLtocalculateaFibonaccinumber:
testdb=#SELECT12##;
?column?
----------
144
(1row)
Notethatwedefinedthattheoperatorwillhaveanintegerontheleft-handside.Ifyoutrytoputavalueontheright-handsideoftheoperator,youwillgetanerror:
postgres=#SELECT##12;
ERROR:operatordoesnotexist:##integeratcharacter8
HINT:Nooperatormatchesthegivennameandargumenttype(s).Youmight
needtoaddexplicittypecasts.
STATEMENT:select##12;
ERROR:operatordoesnotexist:##integer
LINE1:select##12;
^
HINT:Nooperatormatchesthegivennameandargumenttype(s).Youmight
needtoaddexplicittypecasts.
![Page 463: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/463.jpg)
OverloadinganoperatorOperatorscanbeoverloadedinthesamewayasfunctions.Thismeans,thatanoperatorcanhavethesamenameasanexistingoperatorbutwithadifferentsetofargumenttypes.Morethanoneoperatorcanhavethesamename,buttwooperatorscan’tsharethesamenameiftheyacceptthesametypesandpositionsofthearguments.Aslongasthereisafunctionthatacceptsthesamekindandnumberofargumentsthatanoperatordefines,itcanbeoverloaded.
Let’soverridethe##operatorwedefinedinthelastexample,andalsoaddtheabilitytoprovideanintegerontheright-handsideoftheoperator:
CREATEOPERATOR##(PROCEDURE=fib,RIGHTARG=integer);
Now,runningthesameSQL,whichresultedinanerrorlasttime,shouldsucceed,asshownhere:
testdb=#SELECT##12;
?column?
----------
144
(1row)
YoucandroptheoperatorusingtheDROPOPERATORcommand.
NoteYoucanreadmoreaboutcreatingandoverloadingnewoperatorsinthePostgreSQLdocumentationathttp://www.postgresql.org/docs/current/static/sql-createoperator.htmlandhttp://www.postgresql.org/docs/current/static/xoper.html.
Thereareseveraloptionalclausesintheoperatordefinitionthatcanoptimizetheexecutiontimeoftheoperatorsbyprovidinginformationaboutoperatorbehavior.Forexample,youcanspecifythecommutatorandthenegatorofanoperatorthathelptheplannerusetheoperatorsinindexscans.Youcanreadmoreabouttheseoptionalclausesathttp://www.postgresql.org/docs/current/static/xoper-optimization.html.
SincethischapterisjustanintroductiontotheadditionalextensibilitycapabilitiesofPostgreSQL,wewilljustintroduceacoupleofoptimizationoptions;anyseriousproductionqualityoperatordefinitionsshouldincludetheseoptimizationclauses,ifapplicable.
![Page 464: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/464.jpg)
OptimizingoperatorsTheoptionalclausestellthePostgreSQLserverabouthowtheoperatorsbehave.Theseoptionscanresultinconsiderablespeedupsintheexecutionofqueriesthatusetheoperator.However,ifyouprovidetheseoptionsincorrectly,itcanresultinaslowdownofthequeries.Let’stakealookattwooptimizationclausescalledcommutatorandnegator.
COMMUTATORThisclausedefinesthecommuteroftheoperator.AnoperatorAisacommutatorofoperatorBifitfulfilsthefollowingcondition:
xAy=yBx.
Itisimportanttoprovidethisinformationfortheoperatorsthatwillbeusedinindexesandjoins.Asanexample,thecommutatorfor>is<,andthecommutatorof=is=itself.
Thishelpstheoptimizertofliptheoperatorinordertouseanindex.Forexample,considerthefollowingquery:
SELECT*FROMemployeeWHEREnew_salary>salary;
Iftheindexisdefinedonthesalarycolumn,thenPostgreSQLcanrewritetheprecedingqueryasshown:
SELECT*fromemployeeWHEREsalary<new_salary
ThisallowsPostgreSQLtousearangescanontheindexcolumnsalary.Forauser-definedoperator,theoptimizercanonlydothisfliparoundifthecommutatorofauser-definedoperatorisdefined:
CREATEOPERATOR>(LEFTARG=integer,RIGHTARG=integer,PROCEDURE=comp,
COMMUTATOR=<)
NEGATORThenegatorclausedefinesthenegatoroftheoperator.Forexample,<>isanegatorof=.Considerthefollowingquery:
SELECT*FROMemployeeWHERENOT(dept=10);
Since<>isdefinedasanegatorof=,theoptimizercansimplifytheprecedingqueryasfollows:
SELECT*FROMemployeeWHEREdept<>10;
YoucanevenverifythatusingtheEXPLAINcommand:
postgres=#EXPLAINSELECT*FROMemployeeWHERENOTdept='WATERMGMNT';
QUERYPLAN
---------------------------------------------------------
ForeignScanonemployee(cost=0.00..1.10rows=1width=160)
Filter:((dept)::text<>'WATERMGMNT'::text)
ForeignFile:/Users/usamadar/testdata.csv
ForeignFileSize:197
![Page 465: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/465.jpg)
(4rows)
![Page 466: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/466.jpg)
![Page 467: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/467.jpg)
CreatingindexaccessmethodsSofarinthisbook,youcameacrossexamplesofcreatingnewdatatypesoruser-definedtypesandoperators.Whatwehaven’tdiscussedsofarishowtoindexthesetypes.InPostgreSQL,anindexismoreofaframeworkthatcanbeextendedorcustomizedforusingdifferentstrategies.Inordertocreatenewindexaccessmethods,wehavetocreateanoperatorclass.Let’stakealookatasimpleexample.
Let’sconsiderascenariowhereyouhavetostoresomespecialdatasuchasanIDorasocialsecuritynumberinthedatabase.Thenumbermaycontainnon-numericcharacters,soitisdefinedasatexttype:
CREATETABLEtest_ssn(ssntext);
INSERTINTOtest_ssnVALUES('222-11-020878');
INSERTINTOtest_ssnVALUES('111-11-020978');
Let’sassumethatthecorrectorderforthisdataissuchthatitshouldbesortedonthelastsixdigitsandnottheASCIIvalueofthestring.
Thefactthatthesenumbersneedauniquesortorderpresentsachallengewhenitcomestoindexingthedata.ThisiswherePostgreSQLoperatorclassesareuseful.Anoperatorallowsausertocreateacustomindexingstrategy.
CreatinganindexingstrategyisaboutcreatingyourownoperatorsandusingthemalongsideanormalB-tree.
Let’sstartbywritingafunctionthatchangestheorderofdigitsinthevalueandalsogetsridofthenon-numericcharactersinthestringtobeabletocomparethembetter:
CREATEORREPLACEFUNCTIONfix_ssn(text)
RETURNStextAS$$
BEGIN
RETURNsubstring($1,8)||replace(substring($1,1,7),'-','');
END;
$$LANGUAGE'plpgsql'IMMUTABLE;
Let’srunthefunctionandverifythatitworks:
testdb=#SELECTfix_ssn(ssn)FROMtest_ssn;
fix_ssn
-------------
02087822211
02097811111
(2rows)
Beforeanindexcanbeusedwithanewstrategy,wemayhavetodefinesomemorefunctionsdependingonthetypeofindex.Inourcase,weareplanningtouseasimpleB-tree,soweneedacomparisonfunction:
CREATEORREPLACEFUNCTIONssn_compareTo(text,text)
![Page 468: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/468.jpg)
RETURNSintAS
$$
BEGIN
IFfix_ssn($1)<fix_ssn($2)
THEN
RETURN-1;
ELSIFfix_ssn($1)>fix_ssn($2)
THEN
RETURN+1;
ELSE
RETURN0;
ENDIF;
END;
$$LANGUAGE'plpgsql'IMMUTABLE;
It’snowtimetocreateouroperatorclass:
CREATEOPERATORCLASSssn_ops
FORTYPEtextUSINGbtree
AS
OPERATOR1<,
OPERATOR2<=,
OPERATOR3=,
OPERATOR4>=,
OPERATOR5>,
FUNCTION1ssn_compareTo(text,text);
Youcanalsooverloadthecomparisonoperatorsifyouneedtocomparethevaluesinaspecialway,andusethefunctionsinthecompareTofunctionaswellasprovidethemintheCREATEOPERATORCLASScommand.
Wewillnowcreateourfirstindexusingourbrandnewoperatorclass:
CREATEINDEXidx_ssnONtest_ssn(ssnssn_ops);
Wecancheckwhethertheoptimizeriswillingtouseourspecialindex,asfollows:
testdb=#SETenable_seqscan=off;
testdb=#EXPLAINSELECT*FROMtest_ssnWHEREssn='02087822211';
QUERYPLAN
------------------------------------------------------------------
IndexOnlyScanusingidx_ssnontest_ssn(cost=0.13..8.14rows=1
width=32)
IndexCond:(ssn='02087822211'::text)
(2rows)
Therefore,wecanconfirmthattheoptimizerisabletouseournewindex.
YoucanreadaboutindexaccessmethodsinthePostgreSQLdocumentationathttp://www.postgresql.org/docs/current/static/xindex.html.
![Page 469: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/469.jpg)
![Page 470: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/470.jpg)
Creatinguser-definedaggregatesUser-definedaggregatefunctionsareprobablyauniquePostgreSQLfeature,yettheyarequiteobscureandperhapsnotmanypeopleknowhowtocreatethem.However,onceyouareabletocreatethisfunction,youwillwonderhowyouhavelivedforsolongwithoutusingthisfeature.
Thisfunctionalitycanbeincrediblyuseful,becauseitallowsyoutoperformcustomaggregatesinsidethedatabase,insteadofqueryingallthedatafromtheclientanddoingacustomaggregateinyourapplicationcode,thatis,thenumberofhitsonyourwebsiteperminutefromaspecificcountry.
PostgreSQLhasaverysimpleprocessfordefiningaggregates.Aggregatescanbedefinedusinganyfunctionsandinanylanguagesthatareinstalledinthedatabase.HerearethebasicstepstobuildinganaggregatefunctioninPostgreSQL:
1. Defineastartfunctionthatwilltakeinthevaluesofaresultset;thisfunctioncanbedefinedinanyPLlanguageyouwant.
2. Defineanendfunctionthatwilldosomethingwiththefinaloutputofthestartfunction.ThiscanbeinanyPLlanguageyouwant.
3. DefinetheaggregateusingtheCREATEAGGREGATEcommand,providingthestartandendfunctionsyoujustcreated.
Let’sstealanexamplefromthePostgreSQLwikiathttp://wiki.postgresql.org/wiki/Aggregate_Median.
Inthisexample,wewillcalculatethestatisticalmedianofasetofdata.Forthispurpose,wewilldefinestartandendaggregatefunctions.
Let’sdefinetheendfunctionfirst,whichtakesanarrayasaparameterandcalculatesthemedian.Weareassumingherethatourstartfunctionwillpassanarraytothefollowingendfunction:
CREATEFUNCTION_final_median(anyarray)RETURNSfloat8AS$$
WITHqAS
(
SELECTval
FROMunnest($1)val
WHEREVALISNOTNULL
ORDERBY1
),
cntAS
(
SELECTCOUNT(*)AScFROMq
)
SELECTAVG(val)::float8
FROM
(
SELECTvalFROMq
LIMIT2-MOD((SELECTcFROMcnt),2)
![Page 471: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/471.jpg)
OFFSETGREATEST(CEIL((SELECTcFROMcnt)/2.0)-1,0)
)q2;
$$LANGUAGEsqlIMMUTABLE;
Now,wecreatetheaggregateasshowninthefollowingcode:
CREATEAGGREGATEmedian(anyelement)(
SFUNC=array_append,
STYPE=anyarray,
FINALFUNC=_final_median,
INITCOND='{}'
);
Thearray_appendstartfunctionisalreadydefinedinPostgreSQL.Thisfunctionappendsanelementtotheendofanarray.
Inourexample,thestartfunctiontakesallthecolumnvaluesandcreatesanintermediatearray.Thisarrayispassedontotheendfunction,whichcalculatesthemedian.
Now,let’screateatableandsometestdatatorunourfunction:
testdb=#CREATETABLEmedian_test(tinteger);
CREATETABLE
testdb=#INSERTINTOmedian_testSELECTgenerate_series(1,10);
INSERT010
Thegenerate_seriesfunctionisasetreturningfunctionthatgeneratesaseriesofvalues,fromstarttostopwithastepsizeofone.
Now,weareallsettotestthefunction:
testdb=#SELECTmedian(t)FROMmedian_test;
median
--------
5.5
(1row)
Themechanicsoftheprecedingexamplearequiteeasytounderstand.Whenyouruntheaggregate,thestartfunctionisusedtoappendallthetabledatafromcolumntintoanarrayusingtheappend_arrayPostgreSQLbuilt-in.Thisarrayispassedontothefinalfunction,_final_median,whichcalculatesthemedianofthearrayandreturnstheresultinthesamedatatypeastheinputparameter.Thisprocessisdonetransparentlytotheuserofthefunctionwhosimplyhasaconvenientaggregatefunctionavailabletothem.
Youcanreadmoreabouttheuser-definedaggregatesinthePostgreSQLdocumentationinmuchmoredetailathttp://www.postgresql.org/docs/current/static/xaggr.html.
![Page 472: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/472.jpg)
![Page 473: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/473.jpg)
UsingforeigndatawrappersPostgreSQLforeigndatawrappers(FDW)areanimplementationofSQLManagementofExternalData(SQL/MED),whichisastandardaddedtoSQLin2013.
FDWsaredriversthatallowPostgreSQLdatabaseuserstoreadandwritedatatootherexternaldatasources,suchasotherrelationaldatabases,NoSQLdatasources,files,JSON,LDAP,andevenTwitter.
YoucanquerytheforeigndatasourcesusingSQLandcreatejoinsacrossdifferentsystemsorevenacrossdifferentdatasources.
Thereareseveraldifferenttypesofdatawrappersdevelopedbydifferentdevelopersandnotallofthemareproductionquality.YoucanseeaselectlistofwrappersonthePostgreSQLwikiathttp://wiki.postgresql.org/wiki/Foreign_data_wrappers.
AnotherlistofFDWscanbefoundonPGXNathttp://pgxn.org/tag/fdw/.
Let’stakelookatasmallexampleofusingfile_fdwtoaccessdatainaCSVfile.
First,youneedtoinstallthefile_fdwextension.IfyoucompiledPostgreSQLfromthesource,youwillneedtoinstallthefile_fdwcontribmodulethatisdistributedwiththesource.Youcandothisbygoingintothecontrib/file_fdwfolderandrunningmakeandmakeinstall.Ifyouusedaninstallerorapackageforyourplatform,thismodulemighthavebeeninstalledautomatically.
Oncethefile_fdwmoduleisinstalled,youwillneedtocreatetheextensioninthedatabase:
postgres=#CREATEEXTENSIONfile_fdw;
CREATEEXTENSION
Let’snowcreateasampleCSVfilethatusesthepipe,|,asaseparatorandcontainssomeemployeedata:
$cattestdata.csv
AARON,ELVIAJ|WATERRATETAKER|WATERMGMNT|81000.00|73862.00
AARON,JEFFERYM|POLICEOFFICER|POLICE|74628.00|74628.00
AARON,KIMBERLEIR|CHIEFCONTRACTEXPEDITER|FLEET
MANAGEMNT|77280.00|70174.00
Now,weshouldcreateaforeignserverthatisprettymuchaformalitybecausethefileisonthesameserver.Aforeignservernormallycontainstheconnectioninformationthataforeigndatawrapperusestoaccessanexternaldataresource.Theserverneedstobeuniquewithinthedatabase:
CREATESERVERfile_serverFOREIGNDATAWRAPPERfile_fdw;
Thenextstep,istocreateaforeigntablethatencapsulatesourCSVfile:
CREATEFOREIGNTABLEemployee(
emp_nameVARCHAR,
job_titleVARCHAR,
![Page 474: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/474.jpg)
deptVARCHAR,
salaryNUMERIC,
sal_after_taxNUMERIC
)SERVERfile_server
OPTIONS(format'csv',header'false',filename
'/home/pgbook/14/testdata.csv',delimiter'|',null'');'');
TheCREATEFOREIGNTABLEcommandcreatesaforeigntableandthespecificationsofthefileareprovidedintheOPTIONSsectionoftheprecedingcode.Youcanprovidetheformat,andifthefirstlineofthefileisaheader(header'false'),inourcasethereisnofileheader.
Wethenprovidethenameandpathofthefileandthedelimiterusedinthefile,whichinourcaseisthepipesymbol|.Inthisexample,wealsospecifythatthenullvaluesshouldberepresentedasanemptystring.
Let’srunaSQLcommandonourforeigntable:
postgres=#select*fromemployee;
-[RECORD1]-+-------------------------
emp_name|AARON,ELVIAJ
job_title|WATERRATETAKER
dept|WATERMGMNT
salary|81000.00
sal_after_tax|73862.00
-[RECORD2]-+-------------------------
emp_name|AARON,JEFFERYM
job_title|POLICEOFFICER
dept|POLICE
salary|74628.00
sal_after_tax|74628.00
-[RECORD3]-+-------------------------
emp_name|AARON,KIMBERLEIR
job_title|CHIEFCONTRACTEXPEDITER
dept|FLEETMANAGEMNT
salary|77280.00
sal_after_tax|70174.00
Great,lookslikeourdataissuccessfullyloadedfromthefile.
Youcanalsousethe\dmetacommandtoseethestructureoftheemployeetable:
postgres=#\demployee;
Foreigntable"public.employee"
Column|Type|Modifiers|FDWOptions
---------------+-------------------+-----------+-------------
emp_name|charactervarying||
job_title|charactervarying||
dept|charactervarying||
salary|numeric||
sal_after_tax|numeric||
Server:file_server
FDWOptions:(format'csv',header'false',
filename'/home/pg_book/14/testdata.csv',delimiter'|',"null"'')
![Page 475: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/475.jpg)
Youcanrunexplainonthequerytounderstandwhatisgoingonwhenyourunaqueryontheforeigntable:
postgres=#EXPLAINSELECT*FROMemployeeWHEREsalary>5000;
QUERYPLAN
---------------------------------------------------------
ForeignScanonemployee(cost=0.00..1.10rows=1width=160)
Filter:(salary>5000::numeric)
ForeignFile:/home/pgbook/14/testdata.csv
ForeignFileSize:197
(4rows)
TheALTERFOREIGNTABLEcommandcanbeusedtomodifytheoptions.
NoteMoreinformationaboutthefile_fdwisavailableathttp://www.postgresql.org/docs/current/static/file-fdw.html.
YoucantakealookattheCREATESERVERandCREATEFOREIGNTABLEcommandsinthePostgreSQLdocumentationformoreinformationonthemanyoptionsavailable.Eachoftheforeigndatawrapperscomeswithitsowndocumentationabouthowtousethewrapper.Makesurethatanextensionisstableenoughbeforeitisusedinproduction.ThePostgreSQLcoredevelopmentgroupdoesnotsupportmostoftheFDWextensions.
Ifyouwanttocreateyourowndatawrappers,youcanfindthedocumentationathttp://www.postgresql.org/docs/current/static/fdwhandler.htmlasanexcellentstartingpoint.Thebestwaytolearn,however,istoreadthecodeofotheravailableextensions.
![Page 476: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/476.jpg)
![Page 477: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/477.jpg)
SummaryPostgreSQLcanbeextendedinmanymorewaysthanwhatwehavediscussedsofarinthebook.Thisincludestheabilitytoaddnewoperators,newindexaccessmethods,andcreateyourownaggregates.Youcanaccessforeigndatasources,suchasotherdatabases,files,andwebservicesusingPostgreSQLforeigndatawrappers.Thesewrappersareprovidedasextensionsandshouldbeusedwithcaution,asmostofthemarenotofficiallysupported.
EventhoughPostgreSQLisveryextensible,youcan’tpluginanewstorageengineorchangetheparser/plannerandexecutorinterfaces.Thesecomponentsareverytightlycoupledwitheachotherandare,therefore,highlyoptimizedandmature.
![Page 478: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/478.jpg)
IndexA
acquisitioncost/Costofacquisition
add(int,int)functionality,adding/Addingfunctionalitytoadd(int,int)NULLarguments,handling/SmarthandlingofNULLargumentsanynumberofarguments,workingwith/Workingwithanynumberofarguments
add_func.c/add_func.cadd_func.sql.in/add_func.sql.inAFTERtrigger/DisallowingDELETEALTEREXTENSIONADDcommand
URL/WhentocreateanextensionANYparameter/Otherparametersapplicationdesign
about/Applicationdesigndatabases,drawbacks/Databasesareconsideredharmfuldatabases/Databasesareconsideredharmfulencapsulation/EncapsulationPostgreSQL/WhatdoesPostgreSQLoffer?datalocality/Datalocality
argumentsabout/Workingwithanynumberofargumentsrecords,handlingas/Handlingrecordsasargumentsorreturnedvalues
argumenttuplefields,extractingfrom/Extractingfieldsfromanargumenttuple
arrayslooping/LoopingThroughArrays
assert,PL/Pythonusing/Usingassert
audittrailcreating/Creatinganaudittrail
audittrigger/Theaudittrigger
![Page 479: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/479.jpg)
Bbackends
synchronizingbetween/SynchronizingbetweenbackendsBEFOREtrigger/DisallowingDELETEBIRT/Third-partytools
![Page 480: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/480.jpg)
C.controlfile,extension
about/The.controlfileC
additionalresources/AdditionalresourcesforCC++
functions,writingin/WritingfunctionsinC++caching
about/Cachingcanceltrigger/DisallowingDELETECcode,writing
about/BasicguidelinesforwritingCcodememory,allocating/Memoryallocationpalloc(),using/Usepalloc()andpfree()pfree(),using/Usepalloc()andpfree()structures,zerofilling/Zero-fillthestructuresfiles,including/Includefilessymbolnames,public/Publicsymbolnames
Cfunctionabout/ThesimplestCfunction–return(a+b)return(a+b)/ThesimplestCfunction–return(a+b)add_func.c/add_func.cMakefilefunction/MakefileCREATEFUNCTIONadd(int,int)/CREATEFUNCTIONadd(int,int)add_func.sql.infunction/add_func.sql.inwriting/SummaryforwritingaCfunction
Cfunctionserror,reporting/ErrorreportingfromCfunctionserror,states/“Error”statesthatarenoterrorsmessages,senttoclient/Whenaremessagessenttotheclient?
changesauditing/Auditingchanges
CLUSTERstatement/CONNECT,CLUSTER,andRUNONcode
examples/Aboutthisbook’scodeexamplescommit/Doingsomethingatcommit/rollbackCommonLanguageRuntime(CLR)/Procedurallanguagescommunity
about/CommunityCOMMUTATORclause/COMMUTATORcomposite-typearguments,PL/Tcl
passing/Passingcomposite-typeargumentsconditionalexpressions
![Page 481: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/481.jpg)
about/ConditionalexpressionsURL/Conditionalexpressionsloops,withcounters/Loopswithcountersqueryresults,looping/LoopingthroughqueryresultsPERFORMcommandversusSELECTcommand/PERFORMversusSELECTlooping,througharrays/LoopingThroughArrays
conditionaltriggers/ConditionaltriggersCONNECTstatement/CONNECT,CLUSTER,andRUNONcontextmanager
URL/Handlingexceptionscontrib
URL/AdditionalresourcesforCCoordinatedUniversalTime(UTC)/Theaudittriggercost
about/MorecontrolCREATEFUNCTIONadd(int,int)/CREATEFUNCTIONadd(int,int)ctags
URL/AdditionalresourcesforCcursors
returning/Returningcursorsreturnedfromanotherfunction,iteratingover/Iteratingovercursorsreturnedfromanotherfunctionpros/Wrappingupoffunctionsreturningcursorscons/WrappingupoffunctionsreturningcursorsURL/Wrappingupoffunctionsreturningcursors
![Page 482: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/482.jpg)
Ddata
cleaning/Datacleaningpartitioning,acrossmultipleservers/Datapartitioningacrossmultipleserverssplitting/Splittingthedatadistributing/Thedistributionofdatamoving,fromsingletopartitioneddatabase/Movingdatafromthesingletothepartitioneddatabase
databasechanges,fastcapturing/Fastcapturingofdatabasechanges
database,scalingsingle-serverchat,creating/Creatingasimplesingle-serverchattables,splittingovermultipledatabases/Dealingwithsuccess–splittingtablesovermultipledatabasesdata,movingfromsingletopartitioneddatabase/Movingdatafromthesingletothepartitioneddatabase
database-backedsystems,growingways/Whatexpansionplansworkandwhen?biggerserver,movingto/MovingtoabiggerserverMaster-slavereplication/Master-slavereplication–movingreadstoslaveMulti-masterreplication/Multimasterreplication
databaseabstractionlayer/Databasesareconsideredharmfuldatabases,PL/Tcl
accessing/Accessingdatabasesdatachanges
visibility/Visibilityofdatachangesdatacomparisons
operatorsused/Datacomparisonsusingoperatorsdatadefinitionlanguage(DDL)/AuditingchangesDataManipulationLanguage(DML)operation/Workingonasimple“Hey,I’mcalled”triggerdatawrappers
URL/UsingforeigndatawrappersDatum/Interlude–whatisDatum?DBAPI2/Runningqueriesinthedatabaseddl_command_endevent/Creatingeventtriggersddl_command_startevent/Creatingeventtriggersdebugging
manualdebugging,withRAISENOTICE/ManualdebuggingwithRAISENOTICEvisualdebugging/Visualdebugging
debugging,manualexceptions,throwing/Throwingexceptions
![Page 483: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/483.jpg)
URL/Throwingexceptionsfile,loggingto/LoggingtoafileRAISENOTICE,advantages/TheadvantagesofRAISENOTICERAISENOTICE,disadvantages/ThedisadvantagesofRAISENOTICE
DELETEtriggerdisallowing/DisallowingDELETE
developersavailability/Availabilityofdevelopers
don’trepeatyourself(DIY)/DRY–don’trepeatyourselfdynamiclinklibrary(DLL)/Procedurallanguages
![Page 484: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/484.jpg)
EEnterpriseDB
URL/Installingthedebuggerfromthesourceerror
reporting,fromCfunctions/ErrorreportingfromCfunctionsstates/“Error”statesthatarenoterrorsNOTICE/“Error”statesthatarenoterrorsINFO/“Error”statesthatarenoterrorsLOG/“Error”statesthatarenoterrorsreporting,URL/Whenaremessagessenttotheclient?
errorhandling/Generalerrorreportinganderrorhandlingerrorreporting/GeneralerrorreportinganderrorhandlingERRORtrigger/DisallowingDELETEeventtriggers
usecases/Usecasesforcreatingeventtriggerscreating/Creatingeventtriggersddl_command_startevent/Creatingeventtriggersddl_command_endevent/Creatingeventtriggerssql_dropevent/CreatingeventtriggersURL/Creatingeventtriggers,Aroadmapofeventtriggersaudittrail,creating/Creatinganaudittrailroadmap/Aroadmapofeventtriggers
eventtriggers,PL/pgSQLfunctionsTG_TAG/CreatingeventtriggersTG_EVENT/Creatingeventtriggers
exceptions,PL/Pythonhandling/Handlingexceptions
exceptions,RAISENOTICEthrowing/Throwingexceptions
expandeddisplayswitchingto/Switchingtotheexpandeddisplay
extensibility/Whatcan’tbeextended?extension
creating/WhentocreateanextensionURL/Whentocreateanextension,The.controlfileunpackaged/Unpackagedextensionsversions/Extensionversions.controlfile/The.controlfilebuilding/Buildinganextensioninstalling/Installinganextensionviewing/Viewingextensionspublishing/Publishingyourextensioninstalling,fromPGXN/InstallinganextensionfromPGXN
![Page 485: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/485.jpg)
extension,publishingPostgreSQLExtensionNetwork/IntroductiontoPostgreSQLExtensionNetworksigningup/Signinguptopublishyourextensionextensionproject,creating/Creatinganextensionprojecttheeasywaymetadata,providing/Providingthemetadataabouttheextensionextensioncode,writing/Writingyourextensioncodepackage,creating/Creatingthepackage
extensions/add_func.sql.in
![Page 486: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/486.jpg)
Ffile_fdw
URL/Usingforeigndatawrappersfillfactor
URL/Creatingasimplesingle-serverchatforeigndatawrappers(FDW)
using/Usingforeigndatawrappersfunction
used,forconfiguringPL/Proxycluster/ConfiguringthePL/Proxyclusterusingfunctions
functionoverloading/User-definedfunctions
![Page 487: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/487.jpg)
GGeneralInvertedIndex(GIN)/TypeextensibilityGitrepository
URL/Installingthedebuggerfromthesource
![Page 488: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/488.jpg)
Iimmutablefieldstrigger/Theimmutablefieldstriggerindexaccessmethods
creating/CreatingindexaccessmethodsURL/Creatingindexaccessmethods
integersetreturning/Returningasetofintegers
![Page 489: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/489.jpg)
Kkeepitsimplestupid(KISS)/KISS–keepitsimplestupidknearestneighbor(KNN)/Typeextensibility
![Page 490: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/490.jpg)
Llicensing
about/Licensinglight-weightlocks(LWLocks)/Synchronizingbetweenbackendslogtrigger/Alogtriggerloopingsyntax
URL/Loopswithcountersloops
withcounters/Loopswithcountersstatement,terminating/Statementtermination
![Page 491: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/491.jpg)
MMakefilefunction/MakefileMaster-slavereplication/Master-slavereplication–movingreadstoslavemetadata
providing,forextension/ProvidingthemetadataabouttheextensionMulti-masterreplication
about/MultimasterreplicationMultiversionConcurrencyControl(MVCC)/Visibility
![Page 492: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/492.jpg)
NNEGATORclause/NEGATORNEWrecord
modifying/ModifyingtheNEWrecordNULLarguments
handling/SmarthandlingofNULLarguments
![Page 493: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/493.jpg)
Ooperator
newoperator,creating/Creatinganewoperatoroverloading/Overloadinganoperatoroptimizing/Optimizingoperators
operator,optimizingCOMMUTATOR/COMMUTATORNEGATOR/NEGATOR
operatorsused,fordatacomparisons/DatacomparisonsusingoperatorsPostgreSQLdocumentation,URL/Overloadinganoperator
optionalclausesURL/Overloadinganoperator
os.walk()URL/Listingdirectorycontents
OUTparametersandrecords/OUTparametersandrecordsabout/OUTparametersrecords,returning/ReturningrecordsRETURNSTABLE,using/UsingRETURNSTABLEnopredefinedstructure,returningwith/ReturningwithnopredefinedstructureSETOFANY,returning/ReturningSETOFANYvariadicargumentlists/Variadicargumentlists
![Page 494: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/494.jpg)
Ppackage
creating/Creatingthepackagesubmitting,toPGXN/SubmittingthepackagetoPGXN
palloc()using/Usepalloc()andpfree()
parametersabout/Otherparameters
Pentahodataintegration(kettle)/Third-partytoolsPentahoReportServer/Third-partytoolsPERFORMcommand
versusSELECTcommand/PERFORMversusSELECTpfree()
using/Usepalloc()andpfree()pgAdmin3/Third-partytools
installing/InstallingpgAdmin3pgfoundry
URL/AdditionalresourcesforCPGXN
package,submitting/SubmittingthepackagetoPGXNURL/SubmittingthepackagetoPGXNextension,installingfrom/InstallinganextensionfromPGXNFDWsURL/Usingforeigndatawrappers
php5-postgresql/Third-partytoolspl/lolcode
URL/SummaryPL/Perl
using/WhentousePL/Perlinstalling/InstallingPL/Perlfunction/AsimplePL/Perlfunctionfunction,URL/AsimplePL/Perlfunction,Passingandreturningnon-scalartypes,WritingPL/Perltriggersnon-scalartypes,passing/Passingandreturningnon-scalartypesnon-scalartypes,returning/Passingandreturningnon-scalartypestriggers,writing/WritingPL/PerltriggersuntrustedPerl/UntrustedPerl
PL/pgSQLused,forintegritychecks/UsingPL/pgSQLforintegritychecksabout/WhyPL/pgSQL?disadvantages/WhyPL/pgSQL?URL/WhyPL/pgSQL?advantages/WhyPL/pgSQL?
PL/pgSQLdebugger
![Page 495: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/495.jpg)
about/VisualdebuggingURL/Visualdebugginginstalling/InstallingthedebuggerPostgreSQLWindowsinstaller,URL/Installingthedebuggerinstalling,fromsource/InstallingthedebuggerfromthesourcepgAdmin3,installing/InstallingpgAdmin3using/Usingthedebuggeradvantages/Theadvantagesofthedebuggerdisadvantages/Thedisadvantagesofthedebugger
PL/pgSQLfunctionstructure/ThestructureofaPL/pgSQLfunctionarguments,accessing/Accessingfunctionargumentsresults/Actingonthefunction’sresults
PL/pgSQLTRIGGERfunctionOLD,NEW/VariablespassedtothePL/pgSQLTRIGGERfunctionTG_NAME/VariablespassedtothePL/pgSQLTRIGGERfunctionTG_WHEN/VariablespassedtothePL/pgSQLTRIGGERfunctionTG_LEVEL/VariablespassedtothePL/pgSQLTRIGGERfunctionTG_OP/VariablespassedtothePL/pgSQLTRIGGERfunctionTG_RELID/VariablespassedtothePL/pgSQLTRIGGERfunctionTG_TABLE_NAME/VariablespassedtothePL/pgSQLTRIGGERfunctionTG_TABLE_SCHEMA/VariablespassedtothePL/pgSQLTRIGGERfunctionTG_NARGS,TG_ARGV[]/VariablespassedtothePL/pgSQLTRIGGERfunctionTG_TAG/VariablespassedtothePL/pgSQLTRIGGERfunction
PL/Proxyabout/PL/Proxy–thepartitioninglanguageinstalling/InstallingPL/ProxyURL/InstallingPL/Proxysyntax/ThePL/ProxylanguagesyntaxCONNECTstatement/CONNECT,CLUSTER,andRUNONCLUSTERstatement/CONNECT,CLUSTER,andRUNONRUNONstatement/CONNECT,CLUSTER,andRUNONSELECTstatement/SELECTandTARGETTARGETstatement/SELECTandTARGETSPLITstatement/SPLIT–distributingarrayelementsoverseveralpartitionsdata,distributing/Thedistributionofdataconnectionpooling/ConnectionPooling
PL/Proxyclusterconfiguring,functionsused/ConfiguringthePL/Proxyclusterusingfunctionsconfiguring,SQL/MEDused/ConfiguringthePL/ProxyclusterusingSQL/MED
PL/Pythonabout/WhyPL/Python?,QuickintroductiontoPL/Python
![Page 496: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/496.jpg)
function/AminimalPL/Pythonfunctiondatatypeconversions/Datatypeconversionsdocumentation,URL/Datatypeconversionssimplefunctions,writing/WritingsimplefunctionsinPL/Python,Asimplefunctionrecord,returningfromPythonfunction/Functionsreturningarecordtablefunctions/Tablefunctionsqueries,runningindatabase/Runningqueriesinthedatabasetriggerfunctions,writing/WritingtriggerfunctionsinPL/Pythonexceptions,handling/Handlingexceptionsatomicity/AtomicityinPythondebugging/DebuggingPL/Python
PL/Python,debuggingabout/DebuggingPL/Pythonfunctionprogresstracking,plpy.notice()used/Usingplpy.notice()totrackthefunction’sprogressassertused/Usingassertsys.stdout,redirecting/Redirectingsys.stdoutandsys.stderrsys.stderr,redirecting/Redirectingsys.stdoutandsys.stderr
PL/Tclinstalling/InstallingPL/Tclfunction/AsimplePL/TclfunctionStrictfunctions,nullcheckingwith/NullcheckingwithStrictfunctionsparameters/Theparameterformatarrays,passing/Passingandreturningarraysarrays,returning/Passingandreturningarrayscomposite-typearguments,passing/Passingcomposite-typeargumentsdatabase,accessing/Accessingdatabasesfunction,URL/Accessingdatabases,WritingPL/Tcltriggerstriggers,writing/WritingPL/TcltriggersuntrustedTcl/UntrustedTcl
PlpgGetNames()function/Returningarecordplpy.notice()
used,fortrackingfunctionsprogress/Usingplpy.notice()totrackthefunction’sprogress
plugins/Procedurallanguagespolymorphictypes/OtherparametersPostgreSQL
acquisitioncost/Costofacquisitiondevelopers,availability/Availabilityofdeveloperslicensing/Licensingpredictability/Predictabilitycommunity/Communityprocedurallanguages/Procedurallanguages
![Page 497: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/497.jpg)
controls/MorecontrolURL/Morecontroldocumentation,URL/Returningcursorsmanual,URL/AdditionalresourcesforCinternals,URL/AdditionalresourcesforC
postgresql.conffileURL/AdditionalresourcesforC
PostgreSQLdocumentationURL/WritingfunctionsinC++
PostgreSQLExtensionNetworkabout/IntroductiontoPostgreSQLExtensionNetwork
PostgreSQLfunctionscalling/RunningqueriesandcallingPostgreSQLfunctions
PostgreSQLlicenseURL/Publishingyourextension
PostgreSQLVersion9.3functionsURL/MoreinfoonSPI_*functions
predictabilityabout/Predictability
procedurallanguagesabout/Procedurallanguagesthird-partytools/Third-partytoolsplatformcompatibility/Platformcompatibilityapplicationdesign/Applicationdesign
pseudotypesURL/Otherparameters
psycopg2/Third-partytoolsPythonDatabaseAPISpecificationv2.0/RunningqueriesinthedatabasePythonDatabaseAPISpecificationv2.0(DBAPI2)/RunningqueriesinthedatabasePythonImagingLibrary(PIL)module/Generatingthumbnailswhensavingimages
![Page 498: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/498.jpg)
QQCubed/Third-partytoolsqueries,PL/Python
running,indatabase/Runningqueriesinthedatabasesimplequeries,running/Runningsimplequeriespreparedqueries,using/Usingpreparedqueriespreparedqueries,caching/Cachingpreparedqueriesconstructing/Constructingqueries
queryresultslooping/Loopingthroughqueryresults
![Page 499: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/499.jpg)
RRAISENOTICE
manualdebuggingwith/ManualdebuggingwithRAISENOTICEadvantages/TheadvantagesofRAISENOTICEURL/TheadvantagesofRAISENOTICEdisadvantages/ThedisadvantagesofRAISENOTICE
ReadCommitted/Transactionsrecord
returning/Returningarecordreturning,fromPythonfunction/Functionsreturningarecord
recordsandOUTparameters/OUTparametersandrecordsreturning/Returningrecordshandling,asarguments/Handlingrecordsasargumentsorreturnedvaluescomplextypesingletuple,returning/Returningasingletupleofacomplextypefields,extractingfromargumenttype/Extractingfieldsfromanargumenttuplereturntuple,constructing/ConstructingareturntupleDatum/Interlude–whatisDatum?set,returning/Returningasetofrecords
replicationMaster-slavereplication/Master-slavereplication–movingreadstoslaveMulti-masterreplication/Multimasterreplication
return(a+b)/ThesimplestCfunction–return(a+b)RETURNSETOFvariants
about/AsummaryoftheRETURNSETOFvariantsRETURNSTABLE
using/UsingRETURNSTABLEreturntuple
constructing/Constructingareturntuplerollback/Doingsomethingatcommit/rollbackrows
returning,fromfunction/Usingasetreturningfunctionrowsets/SetsandarraysRUNONstatement/CONNECT,CLUSTER,andRUNON
![Page 500: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/500.jpg)
Sschemachanges
preventing/PreventingschemachangesSELECTcommand
versusPERFORMcommand/PERFORMversusSELECTSELECTstatement/SELECTandTARGETserver
data,partitioningacrossmultipleservers/Datapartitioningacrossmultipleservers
serverprogrammingabout/Movingbeyondsimplefunctionsbestpractices/Programmingbestpracticeskeepitsimplestupid(KISS)/KISS–keepitsimplestupiddon’trepeatyourself(DRY)/DRY–don’trepeatyourselfyouain’tgonnaneedit(YAGNI)/YAGNI–youain’tgonnaneeditservice-orientedarchitecture(SOA)/SOA–service-orientedarchitecture
service-orientedarchitecture(SOA)/SOA–service-orientedarchitectureset-returningfunction(tablefunction)
using/Usingasetreturningfunctionset-returningfunctions(SRF)/ReturningarecordSETOFANY
returning/ReturningSETOFANYsets
about/Setsandarraysreturning/Returningsetsintegersets,returning/Returningasetofintegersset-returningfunction,using/Usingasetreturningfunctionrows,returningfromfunction/Usingasetreturningfunction
severprogrammingabout/Whyprogramintheserver?advantages/Wrappingup–whyprogramintheserver?,Easeofmaintenance
single-serverchatspecifications/Creatingasimplesingle-serverchatimplementing/Creatingasimplesingle-serverchat
skytoolsURL/Fastcapturingofdatabasechanges
smtplibURL/Sendingane-mail
sortorderscustom/Customsortorders
SPIused,forsampleCfunction/AsampleCfunctionusingSPI
SPI_*functions/MoreinfoonSPI_*functions
![Page 501: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/501.jpg)
SPI_exec()function/AsampleCfunctionusingSPISPLITstatement
about/SPLIT–distributingarrayelementsoverseveralpartitionsSQL/MED
URL/Thedistributionofdataused,forconfiguringPL/Proxycluster/ConfiguringthePL/ProxyclusterusingSQL/MED
/UsingforeigndatawrappersSQLdatabaseserver
about/Thinkingoutofthe“SQLdatabaseserver”boxthumbnails,creating/Generatingthumbnailswhensavingimagese-mail,sending/Sendingane-maildirectorycontents,listing/Listingdirectorycontents
SQLqueriesrunning,insidedatabase/RunningqueriesandcallingPostgreSQLfunctionssampleCfunction,SPIused/AsampleCfunctionusingSPIdatachanges,visibility/VisibilityofdatachangesSPI_*functions/MoreinfoonSPI_*functions
sql_dropevent/CreatingeventtriggersStrictfunctions
nullcheckingwith/NullcheckingwithStrictfunctionsstructureddata
about/Otherwaystoworkwithstructureddatadatatypes,complex/Complexdatatypesforthemodernworld–XMLandJSONXMLdatatype/XMLdatatypeandreturningdataasXMLfromfunctionsdata,returningasXMLfromfunctions/XMLdatatypeandreturningdataasXMLfromfunctionsdata,returninginJSONformat/ReturningdataintheJSONformat
sys.stderr,PL/Pythonredirecting/Redirectingsys.stdoutandsys.stderr
sys.stdout,PL/Pythonredirecting/Redirectingsys.stdoutandsys.stderr
![Page 502: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/502.jpg)
Ttablefunctions/Tablefunctionstables
splitting,overmultipledatabases/Dealingwithsuccess–splittingtablesovermultipledatabases
Talend/Third-partytoolsTARGETstatement/SELECTandTARGETTcl
URL/Passingcomposite-typeargumentstransactions
about/Transactionsisolationmethods,URL/Transactions
triggerfunction,creating/Creatingthetriggerfunctioncreating/Creatingthetriggersimpletrigger,creating/Workingonasimple“Hey,I’mcalled”triggerauditing/TheaudittriggerDELETEtrigger,disallowing/DisallowingDELETEcanceltrigger/DisallowingDELETEBEFOREtrigger/DisallowingDELETEAFTERtrigger/DisallowingDELETEERRORtrigger/DisallowingDELETETRUNCATEtrigger,disallowing/DisallowingTRUNCATENEWrecord,modifying/ModifyingtheNEWrecordtimestamping/Thetimestampingtriggerimmutablefieldstrigger/Theimmutablefieldstriggerfire,controlling/Controllingwhenatriggeriscalledconditionaltriggers/Conditionaltriggersonspecificfieldchanges/Triggersonspecificfieldchangesfunction,visibility/Visibilityrules,forusing/Mostimportantly–usetriggerscautiously!PL/pgSQLTRIGGERfunction/VariablespassedtothePL/pgSQLTRIGGERfunction
triggerfunctions,PL/Pythonwriting/WritingtriggerfunctionsinPL/Pythoninputs,exploring/Exploringtheinputsofatriggerlogtrigger/Alogtrigger
triggersused,formanagingrelateddata/Managingrelateddatawithtriggers
triggers,PL/Perlwriting/WritingPL/Perltriggers
triggers,PL/Tclwriting/WritingPL/Tcltriggers
![Page 503: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/503.jpg)
OKvalue/WritingPL/TcltriggersSKIPvalue/WritingPL/TcltriggersLISTvalue/WritingPL/TcltriggersOLDvalue/WritingPL/TcltriggersnEWvalue/WritingPL/Tcltriggers$TG_name/WritingPL/Tcltriggers$TG_level/WritingPL/Tcltriggers$TG_when/WritingPL/Tcltriggers$TG_op/WritingPL/Tcltriggers$TG_table_name/WritingPL/Tcltriggers$OLD(i)/WritingPL/Tcltriggers$NEW(i)/WritingPL/Tcltriggers
TRUNCATEtriggerdisallowing/DisallowingTRUNCATE
typeextensibility/Typeextensibility
![Page 504: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/504.jpg)
Uuntrustedlanguages
about/Areuntrustedlanguagesinferiortotrustedones?,Canyouuseuntrustedlanguagesforimportantfunctions?,Willuntrustedlanguagescorruptthedatabase?features/Whyuntrusted?
untrustedPerl/UntrustedPerluntrustedTcl/UntrustedTcluser-definedaggregates
creating/Creatinguser-definedaggregatesexample,URL/Creatinguser-definedaggregatesURL/Creatinguser-definedaggregates
User-definedfunctions(UDF)about/User-definedfunctions
![Page 505: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/505.jpg)
Vvariableparameters
URL/User-definedfunctionsvariables
URL/VariablespassedtothePL/pgSQLTRIGGERfunctionvariadicargumentlists/Variadicargumentlistsversion0callconventions
about/Version0callconventionsURL/Version0callconventions
viewsfunctionsbased/Functionsbasedonviews
visibilityURL/Visibility
visibilityrulesURL/Visibilityofdatachanges
VOLATILEfunction/Visibility
![Page 506: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/506.jpg)
Wwrappers
URL/Usingforeigndatawrappers
![Page 507: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/507.jpg)
XXMLdatatype
about/XMLdatatypeandreturningdataasXMLfromfunctionsURL/XMLdatatypeandreturningdataasXMLfromfunctions
![Page 508: PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the](https://reader036.vdocuments.mx/reader036/viewer/2022081507/5ebfa0b27028f030f57f0b21/html5/thumbnails/508.jpg)
YYii/Third-partytoolsyouain’tgonnaneedit(YAGNI)/YAGNI–youain’tgonnaneedit