508

PostgreSQL Server Programming - Second Editionindex-of.co.uk/Database/SQL Database/PostgreSQL... · PostgreSQL Server Programming Second Edition Credits About the Authors About the

  • Upload
    others

  • View
    90

  • Download
    5

Embed Size (px)

Citation preview

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
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
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

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

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

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

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

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

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

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

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

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

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
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

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
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

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
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

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

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
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

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

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
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

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

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
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

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

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

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

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
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

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

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

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
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

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
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

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
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

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
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
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

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
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

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

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

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

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

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
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

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

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

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

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

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

-------+---------

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
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

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

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
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

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

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

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
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

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

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

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
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

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

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

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

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

-[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
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

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

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
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

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
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

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

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

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

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

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

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
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

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
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

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

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

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

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

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
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

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
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

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

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
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

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
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

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
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

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
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

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
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

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

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

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

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

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

$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

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

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

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

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
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

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
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

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

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
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

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

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

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
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

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

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

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

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

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

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

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

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

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
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

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

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

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

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
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

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
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

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
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

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

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
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

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

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

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
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

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

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

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
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

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

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

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

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
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

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

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

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

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

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

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

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

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

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

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
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

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
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

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

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

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

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

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
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

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

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

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

|

|<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

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

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

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
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

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
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

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

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

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
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

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

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

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
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

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

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

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
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

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

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
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

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
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

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

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
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

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

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
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

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

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

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
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

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

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
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

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
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

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
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

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

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
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

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
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

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

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
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

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
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

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
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

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
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

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

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

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

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

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

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

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

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
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

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

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

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

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

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

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

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
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

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
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

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

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
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

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
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

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
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

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

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
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

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

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

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

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

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

$$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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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
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

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

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

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

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

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
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

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
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

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

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

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

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

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

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

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

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
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

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

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

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

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

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

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

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

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

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
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

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

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

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
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

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

“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

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
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

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

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

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

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

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
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

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

-[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

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

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

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

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

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

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

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
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

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
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

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
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

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
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

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
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

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
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

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
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

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

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

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

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

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

(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

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
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

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

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

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

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

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

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

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

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

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

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

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

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

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
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

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
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

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
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

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

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
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

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
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

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
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

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

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

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
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

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

----

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
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

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

(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
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

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
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

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

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
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

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

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

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
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

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
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

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

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
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

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

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
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

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

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
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

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

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
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

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
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

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

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
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

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
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

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
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

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
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

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
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

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
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

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
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

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

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

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

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

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

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

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

"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

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

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

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

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

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

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

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
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

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
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

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
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

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

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
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

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

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

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

(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
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

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

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
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

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

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
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

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

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

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
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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

YYii/Third-partytoolsyouain’tgonnaneedit(YAGNI)/YAGNI–youain’tgonnaneedit