File loading please wait...
Citation preview
THE EXPERT’S VOICE ® IN OPEN SOURCE ailable The Definitive Guide to mobilephonesandGPSdevicestoset-topboxesandwebbrowsers.Youalmost SQLite •You’lllearnaboutSQLiteextensionsforC,Java,Perl,PHP,Python,Ruby,andTcl. •You’llgetsolidcoverageofSQLiteinternals. •You’llexploredevelopingiOS(iPhone)andAndroidapplicationswithSQLite. SQLite Take control of this compact and powerful tool to embed sophisticated SQL databases within your applications SECOND EDITION Grant Allen and Mike Owens The Definitive Guide to SQLite Second Edition ■■■ GrantAllen MikeOwens TheDefinitiveGuidetoSQLite,SecondEdition Copyright©2010byGrantAllenandMikeOwens Allrightsreserved.Nopartofthisworkmaybereproducedortransmittedinanyformorbyanymeans, electronicormechanical,includingphotocopying,recording,orbyanyinformationstorageorretrieval system,withoutthepriorwrittenpermissionofthecopyrightownerandthepublisher. ISBN-13(pbk):978-1-4302-3225-4 ISBN-13(electronic):978-1-4302-3226-1 PrintedandboundintheUnitedStatesofAmerica987654321 Trademarkednames,logos,andimagesmayappearinthisbook.Ratherthanuseatrademarksymbol witheveryoccurrenceofatrademarkedname,logo,orimageweusethenames,logos,andimagesonly inaneditorialfashionandtothebenefitofthetrademarkowner,withnointentionofinfringementof thetrademark. Theuseinthispublicationoftradenames,trademarks,servicemarks,andsimilarterms,eveniftheyare notidentifiedassuch,isnottobetakenasanexpressionofopinionastowhetherornottheyaresubject toproprietaryrights. PresidentandPublisher:PaulManning LeadEditor:JonathanGennick TechnicalReviewer:RichardHipp EditorialBoard:SteveAnglin,MarkBeckner,EwanBuckingham,GaryCornell,JonathanGennick, JonathanHassell,MichelleLowman,MatthewMoodie,DuncanParkes,JeffreyPepper, FrankPohlmann,DouglasPundick,BenRenow-Clarke,DominicShakeshaft,MattWade, TomWelsh CoordinatingEditor:JenniferL.Blackwell CopyEditor:KimWimpsett ProductionSupport:PatrickCunningham Indexer:JulieGrady Artist:AprilMilne CoverDesigner:AnnaIshchenko DistributedtothebooktradeworldwidebySpringerScience+BusinessMedia,LLC., 233SpringStreet,6thFloor,NewYork,NY10013.Phone1-800-SPRINGER,fax(201)348-4505, e-mail[email protected] ,orvisitwww.springeronline.com. Forinformationontranslations,pleasee-mail[email protected] ,orvisitwww.apress.com. ApressandfriendsofEDbooksmaybepurchasedinbulkforacademic,corporate,orpromotionaluse. eBookversionsandlicensesarealsoavailableformosttitles.Formoreinformation,referenceour SpecialBulkSales–eBookLicensingwebpageatwww.apress.com/info/bulksales. Theinformationinthisbookisdistributedonan“asis”basis,withoutwarranty.Althoughevery precautionhasbeentakeninthepreparationofthiswork,neithertheauthor(s)norApressshallhave anyliabilitytoanypersonorentitywithrespecttoanylossordamagecausedorallegedtobecaused directlyorindirectlybytheinformationcontainedinthiswork. Thesourcecodeforthisbookisavailabletoreadersatwww.apress.com. To my mother for her endless support of all my crazy ideas Contents at a Glance AbouttheAuthors....................................................................................................xvi AbouttheTechnicalReviewer................................................................................xvii Acknowledgments.................................................................................................xviii Introduction.............................................................................................................xix ■Chapter1:IntroducingSQLite..................................................................................1 ■Chapter2:GettingStarted.....................................................................................17 ■Chapter3:SQLforSQLite......................................................................................47 ■Chapter4:AdvancedSQLforSQLite......................................................................87 ■Chapter5:SQLiteDesignandConcepts...............................................................125 ■Chapter6:TheCoreCAPI....................................................................................153 ■Chapter7:TheExtensionCAPI...........................................................................195 ■Chapter8:LanguageExtensions.........................................................................219 ■Chapter9:iOSDevelopmentwithSQLite.............................................................253 ■Chapter10:AndroidDevelopmentwithSQLite....................................................279 ■Chapter11:SQLiteInternalsandNewFeatures..................................................303 Index.......................................................................................................................323 iv Contents AbouttheAuthors....................................................................................................xvi AbouttheTechnicalReviewer................................................................................xvii Acknowledgments.................................................................................................xviii Introduction.............................................................................................................xix ■Chapter1:IntroducingSQLite..................................................................................1 An Embedded Database..................................................................................................... 1 A Developer’s Database ..................................................................................................... 2 An Administrator’s Database ............................................................................................. 3 SQLite History .................................................................................................................... 3 Who Uses SQLite................................................................................................................ 4 Architecture ....................................................................................................................... 5 The Interface ............................................................................................................................................ 6 The Compiler ............................................................................................................................................ 6 The Virtual Machine .................................................................................................................................. 6 The Back End ............................................................................................................................................ 7 Utilities and Test Code .............................................................................................................................. 8 SQLite’s Features and Philosophy ..................................................................................... 8 Zero Configuration .................................................................................................................................... 8 Portability ................................................................................................................................................. 8 Compactness ............................................................................................................................................ 9 v ■ CONTENTS Simplicity .................................................................................................................................................. 9 Flexibility .................................................................................................................................................. 9 Liberal Licensing ...................................................................................................................................... 9 Reliability ................................................................................................................................................ 10 Convenience ........................................................................................................................................... 10 Performance and Limitations........................................................................................... 11 Who Should Read This Book ............................................................................................ 13 How This Book Is Organized ............................................................................................ 14 Additional Information ..................................................................................................... 15 Summary ......................................................................................................................... 15 ■Chapter2:GettingStarted.....................................................................................17 Where to Get SQLite ......................................................................................................... 17 SQLite on Windows .......................................................................................................... 18 Getting the Command-Line Program ...................................................................................................... 18 Getting the SQLite DLL ............................................................................................................................ 21 Compiling the SQLite Source Code on Windows .................................................................................... 22 Building the SQLite DLL with Microsoft Visual C++ ............................................................................... 25 Building a Dynamically Linked SQLite Client with Visual C++ ............................................................... 27 Building SQLite with MinGW ................................................................................................................... 28 SQLite on Linux, Mac OS X, and Other POSIX Systems.................................................... 30 Binaries and Packages ........................................................................................................................... 30 Compiling SQLite from Source................................................................................................................ 31 The Command-Line Program ........................................................................................... 32 The CLP in Shell Mode ............................................................................................................................ 33 The CLP in Command-Line Mode ........................................................................................................... 34 vi ■ CONTENTS Database Administration ................................................................................................. 35 Creating a Database ............................................................................................................................... 35 Getting Database Schema Information ................................................................................................... 37 Exporting Data ........................................................................................................................................ 39 Importing Data ........................................................................................................................................ 40 Formatting .............................................................................................................................................. 40 Exporting Delimited Data ........................................................................................................................ 41 Performing Unattended Maintenance ..................................................................................................... 41 Backing Up a Database .......................................................................................................................... 42 Getting Database File Information .......................................................................................................... 44 Other SQLite Tools ........................................................................................................... 45 Summary ......................................................................................................................... 46 ■Chapter3:SQLforSQLite......................................................................................47 The Example Database .................................................................................................... 47 Installation .............................................................................................................................................. 48 Running the Examples ............................................................................................................................ 49 Syntax .............................................................................................................................. 50 Commands.............................................................................................................................................. 51 Literals .................................................................................................................................................... 52 Keywords and Identifiers ........................................................................................................................ 53 Comments .............................................................................................................................................. 53 Creating a Database ........................................................................................................ 53 Creating Tables....................................................................................................................................... 53 Altering Tables........................................................................................................................................ 54 Querying the Database .................................................................................................... 55 Relational Operations ............................................................................................................................. 55 select and the Operational Pipeline ........................................................................................................ 57 Filtering .................................................................................................................................................. 59 vii ■ CONTENTS Limiting and Ordering ............................................................................................................................. 64 Functions and Aggregates ...................................................................................................................... 66 Grouping ................................................................................................................................................. 67 Removing Duplicates .............................................................................................................................. 72 Joining Tables ........................................................................................................................................ 72 Names and Aliases ................................................................................................................................. 77 Subqueries ............................................................................................................................................. 79 Compound Queries ................................................................................................................................. 81 Conditional Results ................................................................................................................................. 83 Handling Null in SQLite ........................................................................................................................... 84 Summary ................................................................................................................................................ 86 ■Chapter4:AdvancedSQLforSQLite......................................................................87 Modifying Data................................................................................................................. 87 Inserting Records ................................................................................................................................... 87 Updating Records ................................................................................................................................... 91 Deleting Records .................................................................................................................................... 92 Data Integrity ................................................................................................................... 92 Entity Integrity ........................................................................................................................................ 93 Domain Integrity ..................................................................................................................................... 97 Storage Classes .................................................................................................................................... 101 Views .................................................................................................................................................... 104 Indexes ................................................................................................................................................. 106 Triggers ................................................................................................................................................ 108 Transactions .................................................................................................................. 111 Transaction Scopes .............................................................................................................................. 111 Conflict Resolution................................................................................................................................ 112 Database Locks .................................................................................................................................... 115 Deadlocks ............................................................................................................................................. 116 Transaction Types ................................................................................................................................ 117 viii ■ CONTENTS Database Administration ............................................................................................... 118 Attaching Databases............................................................................................................................. 118 Cleaning Databases .............................................................................................................................. 119 Database Configuration ........................................................................................................................ 120 The System Catalog .............................................................................................................................. 123 Viewing Query Plans ............................................................................................................................. 123 Summary ....................................................................................................................... 124 ■Chapter5:SQLiteDesignandConcepts...............................................................125 The API ........................................................................................................................... 125 The Principal Data Structures ............................................................................................................... 126 The Core API ......................................................................................................................................... 127 Operational Control ............................................................................................................................... 135 Using Threads ....................................................................................................................................... 136 The Extension API .......................................................................................................... 136 Creating User-Defined Functions.......................................................................................................... 136 Creating User-Defined Aggregates ....................................................................................................... 137 Creating User-Defined Collations ......................................................................................................... 138 Transactions .................................................................................................................. 138 Transaction Life Cycles ........................................................................................................................ 138 Lock States ........................................................................................................................................... 139 Read Transactions ................................................................................................................................ 141 Write Transactions................................................................................................................................ 141 Tuning the Page Cache .................................................................................................. 145 Transitioning to Exclusive ..................................................................................................................... 145 Sizing the Page Cache .......................................................................................................................... 145 Waiting for Locks ........................................................................................................... 146 Using a Busy Handler ........................................................................................................................... 146 Using the Right Transaction ................................................................................................................. 147 ix ■ CONTENTS Code . ............................................................................................................................. 149 Using Multiple Connections . ................................................................................................................ 149 The Importance of Finalizing . .............................................................................................................. 150 Shared Cache Mode . ........................................................................................................................... 151 Summary ....................................................................................................................... 151 ■Chapter6:TheCoreCAPI...................................................................................153 Wrapped Queries . ......................................................................................................... 153 Connecting and Disconnecting . ........................................................................................................... 153 The exec Query . ................................................................................................................................... 155 The Get Table Query . ........................................................................................................................... 159 Prepared Queries . ......................................................................................................... 161 Compilation. ......................................................................................................................................... 161 Execution . ............................................................................................................................................ 162 Finalization and Reset . ........................................................................................................................ 163 Fetching Records . ......................................................................................................... 164 Getting Column Information. ................................................................................................................ 165 Getting Column Values . ....................................................................................................................... 166 A Practical Example . ............................................................................................................................ 168 Parameterized Queries . ................................................................................................ 169 Numbered Parameters . ....................................................................................................................... 172 Named Parameters . ............................................................................................................................. 173 Tcl Parameters . ................................................................................................................................... 173 Errors and the Unexpected . .......................................................................................... 174 Handling Errors . ................................................................................................................................... 174 Handling Busy Conditions . ................................................................................................................... 176 Handling Schema Changes. ................................................................................................................. 177 x ■ CONTENTS Operational Control ........................................................................................................ 178 Commit Hooks ...................................................................................................................................... 178 Rollback Hooks ..................................................................................................................................... 179 Update Hooks ....................................................................................................................................... 179 Authorizer Functions ............................................................................................................................ 180 Threads .......................................................................................................................... 190 Shared Cache Mode ............................................................................................................................. 190 Threads and Memory Management ...................................................................................................... 193 Summary ....................................................................................................................... 193 ■Chapter7:TheExtensionCAPI...........................................................................195 The API ........................................................................................................................... 196 Registering Functions ........................................................................................................................... 196 The Step Function................................................................................................................................. 198 Return Values ....................................................................................................................................... 198 Functions ....................................................................................................................... 200 Return Values ....................................................................................................................................... 202 Arrays and Cleanup Handlers ............................................................................................................... 202 Error Conditions .................................................................................................................................... 203 Returning Input Values ......................................................................................................................... 203 Aggregates .................................................................................................................... 204 Registration Function ........................................................................................................................... 205 A Practical Example .............................................................................................................................. 206 Collations ....................................................................................................................... 209 Collation Defined .................................................................................................................................. 210 A Simple Example ................................................................................................................................. 212 Collation on Demand ............................................................................................................................ 216 Summary ....................................................................................................................... 217 xi ■ CONTENTS ■Chapter8:LanguageExtensions.........................................................................219 Selecting an Extension .................................................................................................. 220 Perl ................................................................................................................................ 221 Installation ............................................................................................................................................ 221 Connecting............................................................................................................................................ 222 Query Processing.................................................................................................................................. 222 Parameter Binding ................................................................................................................................ 224 User-Defined Functions ........................................................................................................................ 224 Aggregates ........................................................................................................................................... 225 Python ............................................................................................................................ 226 Installation ............................................................................................................................................ 226 Connecting............................................................................................................................................ 227 Query Processing.................................................................................................................................. 227 Parameter Binding ................................................................................................................................ 229 User-Defined Functions ........................................................................................................................ 230 Aggregates ........................................................................................................................................... 231 APSW as an Alternative Python Interface ............................................................................................. 232 Ruby ............................................................................................................................... 232 Installation ............................................................................................................................................ 232 Connecting............................................................................................................................................ 233 Query Processing.................................................................................................................................. 233 Parameter Binding ................................................................................................................................ 234 User-Defined Functions ........................................................................................................................ 236 Java ............................................................................................................................... 236 Installation ............................................................................................................................................ 237 Connecting............................................................................................................................................ 238 Query Processing.................................................................................................................................. 238 User-Defined Functions and Aggregates .............................................................................................. 240 JDBC ..................................................................................................................................................... 241 xii ■ CONTENTS Tcl .................................................................................................................................. 243 Installation ............................................................................................................................................ 243 Connecting............................................................................................................................................ 244 Query Processing.................................................................................................................................. 244 User-Defined Functions ........................................................................................................................ 247 PHP ................................................................................................................................ 247 Installation ............................................................................................................................................ 248 Connections .......................................................................................................................................... 248 Queries ................................................................................................................................................. 248 User-Defined Functions and Aggregates .............................................................................................. 251 Summary ....................................................................................................................... 252 ■Chapter9:iOSDevelopmentwithSQLite.............................................................253 Prerequisites for SQLite iOS Development .................................................................... 253 Signing Up for Apple Developer ............................................................................................................ 254 Downloading and Installing Xcode and the iOS SDK ............................................................................ 254 Alternatives to Xcode............................................................................................................................ 258 Building the iSeinfeld iOS SQLite Application ................................................................ 259 Step 1: Creating a New Xcode Project .................................................................................................. 259 Step 2: Adding the SQLite Framework to Your Project ......................................................................... 261 Step 3: Preparing the Foods Database ................................................................................................. 263 Step 4: Creating Classes for the Food Data .......................................................................................... 264 Step 5: Accessing and Querying the SQLite DB .................................................................................... 269 Step 6: Final Polish and Wiring for iSeinfeld ........................................................................................ 272 iSeinfeld in Action!......................................................................................................... 272 Working with Large SQLite Databases Under iOS.......................................................... 276 Summary ....................................................................................................................... 277 xiii ■ CONTENTS ■Chapter10:AndroidDevelopmentwithSQLite....................................................279 Prerequisites for SQLite Android Development.............................................................. 279 Check Prerequisites and the JDK ......................................................................................................... 280 Downloading and Installing the Android SDK Starter Package............................................................. 280 Downloading and Installing the Android Developer Tools .................................................................... 280 Adding Android Platforms and Components ......................................................................................... 281 The Android SQLite Classes and Interfaces ................................................................... 285 Using the Basic Helper Class, SQLiteOpenHelper ................................................................................. 285 Working with the SQLiteDatabase Class .............................................................................................. 286 Applying SQLiteOpenHelper and SQLiteDatabase in Practice .............................................................. 290 Querying SQLite with SQLiteQueryBuilder ............................................................................................ 293 Building the Seinfeld Android SQLite Application .......................................................... 294 Creating a New Android Project ........................................................................................................... 295 Adding the Seinfeld SQLite Database to Your Project .......................................................................... 296 Querying the Foods Table ..................................................................................................................... 296 Defining the User Interface ................................................................................................................... 297 Linking the Data and User Interface ..................................................................................................... 298 Viewing the Finished Seinfeld Application ........................................................................................... 299 Care and Feeding for SQLite Android Applications ........................................................ 300 Database Backup for Android ............................................................................................................... 300 Working with Large SQLite Databases Under Android ......................................................................... 300 Summary ....................................................................................................................... 301 ■Chapter11:SQLiteInternalsandNewFeatures..................................................303 The B-Tree and Pager Modules ..................................................................................... 303 Database File Format............................................................................................................................ 303 The B-Tree API ...................................................................................................................................... 308 xiv ■ CONTENTS Manifest Typing, Storage Classes, and Affinity ............................................................. 311 Manifest Typing .................................................................................................................................... 311 Type Affinity.......................................................................................................................................... 313 Affinities and Storage ........................................................................................................................... 314 Write Ahead Logging...................................................................................................... 318 How WAL Works ................................................................................................................................... 318 Activation and Configuration WAL ........................................................................................................ 319 WAL Advantages and Disadvantages ................................................................................................... 320 Operational Issues with WAL-Enabled SQLite Databases..................................................................... 321 Summary ....................................................................................................................... 322 Index.......................................................................................................................323 xv About the Authors ■GrantAllenhasworkedintheITfieldformorethan20years,including inrolessuchaschieftechnologyofficeratvariousleadingsoftware developmentcompaniesandsuchasdataarchitectatGoogle.Hehas workedacrosstheindustry,aswellasingovernmentandacademia aroundtheworld,consultingonlarge-scalesystemsdesign,development, performance,innovation,anddisruptivechange.Grantisafrequent speakeratconferencesandindustryeventsontopicssuchasdatamining, collaborationtechnologies,relationaldatabases,andthebusinessof technology.Inhissparetime,GrantiscompletingaPhDinleading disruptiveinnovationinhigh-technologycompanies. ■MikeOwensistheITdirectorforamajorrealestatefirminFortWorth, Texas,wherehe’schargedwiththedevelopmentandmanagementofthe company’scoresystems.HispriorexperienceincludestimespentatOak RidgeNationalLaboratoryasaprocessdesignengineer,andatNova InformationSystemsasaC++programmer.Heistheoriginalcreatorof PySQLite,thePythonextensionforSQLite.Michaelearnedhisbachelor’s degreeinchemicalengineeringfromtheUniversityofTennesseein Knoxville. Mikeenjoysjogging,playingguitar,snowskiing,andhuntingwithhis buddiesintheTexaspanhandle.Heliveswithhiswife,twodaughters, andtworatterriersinFortWorth,Texas. xvi About the Technical Reviewer ■D.RichardHippisthecreatorandprojectleaderforbothSQLiteand theFossilDVCS.Richardandhissmallyetselectstaffworkfull-time maintainingandenhancingtheseproductsforaninternational clientele. RichardwasborninCharlotte,NorthCarolina,wherehecurrently liveswithhiswife,Ginger.RichardholdsdegreesfromGeorgiaTech (MSEE,1984)andDukeUniversity(PhD,1992). xvii 3 Acknowledgments I'dliketoexpressmygratitudetotheentireteamatApress,especiallyJonathanGennick,myfabulous editor,andJenniferBlackwell,mywonderfulprojectmanager.Theymadeitfeellikethebookwas almostwritingitself!OK,that’salie,butreally,theymadetheexperienceofproducingTheDefinitive GuidetoSQLiteanenjoyableandrewardingone. I’dalsoliketopassonahugethankyoutoD.RichardHipp.NotonlydowehaveRichardtothank forthewonderfulcreationthatisSQLite,buthealsograciouslyofferedtobemytechnicalreviewerand wasgentlewithhiscommentsandcriticisms.Hetaughtmeagreatdealaboutthelatestandgreatest featuresofSQLite,andIhopeI’vedonehimjusticeinbringingthosetopicstolifeinthisbook. Lastly,abigthankstoallmyfriendsandfamily,whoputupwithmewritingyetanotherbook,as wellasthecrazyanticsthatgowithit. xviii Introduction TheDefinitiveGuidetoSQLitecoversSQLiteinacomprehensivefashion,givingyoutheknowledgeand experiencetouseitinawiderangeofsituations.Whetheryouareahard-coreCdeveloper,areamobile deviceaficionado,orarejustseekingmoreknow-howonthebestembeddedandsmall-footprint databaseengineeverinvented,thisbookitforyou. Prerequisites ThisbookassumesnopriorknowledgeofSQLite,thoughnaturallypeopleofallexperiencelevelswill benefitfromthematerial.SQLiteiswritteninCwithanextensiveCAPIandalsosupportsmanyother languagessuchasPython,Tcl,Ruby,andJava.Asadatabaseengine,italsomakesextensiveuseofSQL. Althoughtheexamplesinthisbookwillbenefitareaderofanyskilllevel,wedon’thavespacetoalso teachthoselanguages. How This Book Is Organized Thebookcontains11chapters,whichcoverthefollowingbroadareas: • SQLiteintroduction,acquisition,andinstallation • UsingSQLwithSQLite • TheCAPIforSQLite • UsinglanguagessuchasPython,Tcl,Ruby,andJavawithSQLite • MobiledevicedevelopmentwithSQLite • InternalsandnewfeaturesofSQLite There’snorealimpedimenttojumpingintowhateverareatakesyourfancy,thoughyoumayfind thatChapters5,6,and7,whichdealwiththeCAPI,arebestapproachedinorder. Obtaining the Source Code of the Examples Thesourcecodeofalltheexamplesinthebookisavailablefromthebook’scatalogpageontheApress website,athttp://apress.com/book/view/1430232250.Lookforthe“SourceCode”linkinthe“Book Resources”sidebar. xix CHAPTER 1 ■■■ Introducing SQLite SQLiteisanopensource,embeddedrelationaldatabase.Originallyreleasedin2000,itisdesignedto provideaconvenientwayforapplicationstomanagedatawithouttheoverheadthatoftencomeswith dedicatedrelationaldatabasemanagementsystems.SQLitehasawell-deservedreputationforbeing highlyportable,easytouse,compact,efficient,andreliable. An Embedded Database SQLiteisanembeddeddatabase.Ratherthanrunningindependentlyasastand-aloneprocess,it symbioticallycoexistsinsidetheapplicationitserves—withinitsprocessspace.Itscodeisintertwined, orembedded,aspartoftheprogramthathostsit.Toanoutsideobserver,itwouldneverbeapparent thatsuchaprogramhadarelationaldatabasemanagementsystem(RDBMS)onboard.Theprogram wouldjustdoitsjobandmanageitsdatasomehow,makingnofanfareabouthowitwentaboutdoing so.Butinside,thereisacomplete,self-containeddatabaseengineatwork. Oneadvantageofhavingadatabaseserverinsideyourprogramisthatnonetworkconfigurationor administrationisrequired.Takeamomenttothinkabouthowliberatingthatis:nofirewallsoraddress resolutiontoworryabout,andnotimewastedonmanagingintricatepermissionsandprivileges.Both clientandserverruntogetherinthesameprocess.Thisreducesoverheadrelatedtonetworkcalls, simplifiesdatabaseadministration,andmakesiteasiertodeployyourapplication.Everythingyouneed iscompiledrightintoyourprogram. ConsidertheprocessesfoundinFigure1-1.OneisaPerlscript,anotherisastandardC/C++ program,andthelastisanApache-hostedPHPscript,allusingSQLite.ThePerlscriptimportsthe DBI::SQLitemodule,whichinturnislinkedtotheSQLiteCAPI,pullingintheSQLitelibrary.ThePHP libraryworkssimilarly,asdoestheC++program.Ultimately,allthreeprocessesinterfacewiththe SQLiteCAPI.AllthreethereforehaveSQLiteembeddedintheirprocessspaces.Bydoingso,notonly doeseachofthoseprocessesruntheirownrespectivecode,butthey’vealsobecomeindependent databaseserversinandofthemselves.Furthermore,eventhougheachprocessrepresentsan independentserver,theycanstilloperateonthesamedatabasefile(s),benefittingfromSQLite’suseof theoperatingsystemtomanagesynchronizationandlocking. Todaythereisawidevarietyofrelationaldatabaseproductsonthemarketspecificallydesignedfor embeddeduse—productssuchasSybaseSQLAnywhere,OracleTimesTenandBerkleyDB,Pervasive PSQL,andMicrosoft’sJetEngine.Someofthedominantcommercialvendorshavepareddowntheir large-scaledatabasestocreateembeddedvariants.ExamplesoftheseincludeIBM’sDB2Everyplace, Oracle’sDatabaseLite,andMicrosoft’sSQLServerExpress.TheopensourcedatabasesMySQLand Firebirdbothofferembeddedversionsaswell.Ofalltheseproducts,onlyoneisopensource, unencumberedbylicensingfees,anddesignedexclusivelyforuseasanembeddeddatabase:SQLite. 1 CHAPTER1■INTRODUCINGSQLITE Apache Process Perl Process PHP Code Perl Code Perl DBI::SQLite PHP C/C++ App Process PHP Data Objects C/C++ SQLite C API SQLite C API SQLite SQLite SQLite C API SQLite Operating System DB Figure1-1.SQLiteembeddedinhostprocesses A Developer’s Database SQLiteisquiteversatile.Itisadatabase,aprogramminglibrary,andacommand-linetool,aswellan excellentlearningtoolthatprovidesagoodintroductiontorelationaldatabases.Therearemanywaysto useit—inembeddedenvironments,websites,operatingsystemservices,scripts,andapplications.For programmers,SQLiteislike“dataducttape,”providinganeasywaytobindapplicationsandtheirdata. Likeducttape,thereisnoendtoitspotentialuses.Inawebenvironment,SQLitecanhelpwith managingcomplexsessioninformation.Ratherthanserializingsessiondataintoonebigblob, individualpiecescanbeselectivelywrittentoandreadfromindividualsessiondatabases.SQLitealso servesasagoodstand-inrelationaldatabasefordevelopmentandtesting:therearenoexternalRDBMSs ornetworkingtoconfigureorusernamesandpasswordstohindertheprogrammer’sfocus.SQLitecan alsoserveasacache,holdconfigurationdata,or,byleveragingitsbinarycompatibilityacrossplatforms, evenworkasanapplicationfileformat. Besidesbeingjustastoragereceptacle,SQLitecanserveasapurelyfunctionaltoolforgeneraldata processing.Dependingonsizeandcomplexity,itmaybeeasiertorepresentsomeapplicationdata structuresasatableortablesinanin-memorydatabase.Withsomanydevelopers,analysts,andothers familiarwithrelationaldatabasesandSQL,youcanbenefitfrom“assumedknowledge”—operatingon thedatarelationallybyusingSQLitetodotheheavyliftingratherthanhavingtowriteyourown algorithmstomanipulateandsortdatastructures.Ifyouareaprogrammer,imaginehowmuchcodeit wouldtaketoimplementthefollowingSQLstatementinyourprogram: 2 CHAPTER1■INTRODUCINGSQLITE SELECT x, STDDEV(w) FROM table GROUP BY x HAVING x > MIN(z) OR x < MAX(y) ORDER BY y DESC LIMIT 10 OFFSET 3; IfyouarealreadyfamiliarwithSQL,imaginecodingtheequivalentofasubquery,compoundquery, GROUP BYclause,ormultiwayjoininyourfavorite(ornotsofavorite)programminglanguage.SQLite embedsallofthisfunctionalityintoyourapplicationwithminimalcost.Withadatabaseengine integrateddirectlyintoyourcode,youcanbegintothinkofSQLasanoffloadengineinwhichto implementcomplexsortingalgorithmsinyourprogram.Thisapproachbecomesmoreappealingasthe sizeofyourdatasetgrowsorasyouralgorithmsbecomemorecomplex.What’smore,SQLitecanbe configuredtouseafixedamountofRAMandthenoffloaddatatodiskifitexceedsthespecifiedlimit. Thisisevenhardertodoifyouwriteyourownalgorithms.WithSQLite,thisfeatureisavailablewitha simplecalltoasingleSQLcommand. SQLiteisalsoagreatlearningtoolforprogrammers—acornucopiaforstudyingcomputerscience topics.Fromparsergeneratorstotokenizers,virtualmachines,B-treealgorithms,caching,program architecture,andmore,itisafantasticvehicleforexploringmanywell-establishedcomputerscience concepts.Itsmodularity,smallsize,andsimplicitymakeiteasytopresenteachtopicasanisolatedcase studythatanyindividualcouldeasilyfollow. An Administrator’s Database SQLiteisnotjustaprogrammer’sdatabase.Itisausefultoolforsystemadministratorsaswell.Itis small,compact,andelegantlikefinelyhonedversatileutilitiessuchasfind,rsync,andgrep.SQLitehas acommand-lineutilitythatcanbeusedfromtheshellorcommandlineandwithinshellscripts. However,itworksevenbetterwithalargevarietyofscriptinglanguagessuchasPerl,Python,TCL,and Ruby.Togetherthetwocanhelpwithprettymuchanytaskyoucanimagine,suchasaggregatinglogfile data,monitoringdiskquotas,orperformingbandwidthaccountinginsharednetworks.Furthermore, sinceSQLitedatabasesareordinarydiskfiles,theyareeasytoworkwith,transport,andbackup. SQLiteisaconvenientlearningtoolforadministratorslookingtolearnmoreaboutrelational databases.Itisanidealbeginner’sdatabasewithwhichtolearnaboutrelationalconceptsandpractice theirimplementation.Itcanbeinstalledquicklyandeasilyonanyplatformyou’relikelytoencounter, anditsdatabasefilessharefreelybetweenthemwithouttheneedforconversion.Itisfullfeaturedbut notdaunting.AndSQLite—boththeprogramandthedatabase—canbecarriedaroundonaUSBstickor memorychip. SQLite History SQLitewasconceivedonabattleship...well,sortof.SQLite’sauthor,D.RichardHipp,wasworkingfor GeneralDynamicsonaprogramfortheU.S.Navydevelopingsoftwareforuseonboardguidedmissile destroyers.TheprogramoriginallyranonHewlett-PackardUnix(HP-UX)andusedanInformix databaseasthebackend.Fortheirparticularapplication,Informixwassomewhatoverkill.Foran experienceddatabaseadministrator(DBA)atthetime,itcouldtakealmostanentiredaytoinstallor upgrade.Totheuninitiatedapplicationprogrammer,itmighttakeforever.Whatwasreallyneededwas aself-containeddatabasethatwaseasytouseandthatcouldtravelwiththeprogramandrunanywhere regardlessofwhatothersoftwarewasorwasn’tinstalledonthesystem. 3 CHAPTER1■INTRODUCINGSQLITE InJanuary2000,HippandacolleaguediscussedtheideaofcreatingasimpleembeddedSQL databasethatwouldusetheGNUDBMhashlibrary(gdbm)asabackend,onethatwouldrequireno installationoradministrativesupportwhatsoever.Later,whensomefreetimeopenedup,Hippstarted workontheproject,andinAugust2000,SQLite1.0wasreleased. Asplanned,SQLite1.0usedgdbmasitsstoragemanager.However,Hippsoonreplaceditwithhis ownB-treeimplementationthatsupportedtransactionsandstoredrecordsinkeyorder.Withthefirst majorupgradeinhand,SQLitebeganasteadyevolution,growinginbothfeaturesandusers.Bymid2001,manyprojects—bothopensourceandcommercialalike—startedtouseit.Intheyearsthat followed,othermembersoftheopensourcecommunitystartedtowriteSQLiteextensionsfortheir favoritescriptinglanguagesandlibraries.Onebyone,newextensionsforpopularlanguagesandAPIs suchasOpenDatabaseConnectivity(ODBC),Perl,Python,Ruby,Java,andothersfellintoplaceand testifiedtoSQLite’swideapplicationandutility. SQLitebeganamajorupgradefromversion2to3in2004.Itsprimarygoalwasenhanced internationalizationsupportingUTF-8andUTF-16textaswellasuser-definedtext-collatingsequences. Althoughversion3.0wasoriginallyslatedforreleaseinsummer2005,AmericaOnlineprovidedthe necessaryfundingtoseethatitwascompletedbyJuly2004.Besidesinternationalization,version3 broughtmanyothernewfeaturessuchasarevampedCAPI,amorecompactformatfordatabasefiles(a 25percentsizereduction),manifesttyping,binarylargeobject(BLOB)support,64-bitROWIDs, autovacuum,andimprovedconcurrency.Evenwithmanynewfeatures,theoveralllibraryfootprintwas stilllessthan240KB,atatimewhenmosthomePCsbeganmeasuringtheirmemoryingigabytes! Anotherimprovementinversion3wasagoodcodecleanup—revisiting,refactoringandrewriting,or otherwisethrowingoutthedetritusaccumulatedinthe2.xseries. SQLitecontinuestogrowfeature-wisewhilestillremainingtruetoitsinitialdesigngoals:simplicity, flexibility,compactness,speed,andoveralleaseofuse.Atthetimeofthisbook’slatestedition,SQLite hasleaptaheadtoincludesuchadvancedfeaturesasrecursivetriggers,distributionhistogramstohelp theoptimizerproduceevenfasterqueries,andasynchronousI/Oonoperatingsystemscapableof supportingsuchworkloads.What’snextafterthat?Well,italldepends.Perhapsyouoryourcompany willsponsorthenextbigfeaturethatmakesthissuper-efficientdatabaseevenbetter. Who Uses SQLite Today,SQLiteisusedinawidevarietyofsoftwareandproducts.ItisusedinApple’sMacOSXoperating system,Safariwebbrowser,Mail.appemailprogram,andRSSmanager,aswellasApple’sAperture photographysoftware.PerhapsApple’sbiggestuseforSQLitehascomeintheiPhoneage.You’llfind manyappsontheiPhone,suchastheContactsdatabase,Notes,andmore,allrelyonSQLite.This relianceonSQLitealsoextendstotheiPad.We’llreturntothistopicinChapter9,wherewe’lldiscuss workingwithSQLiteonApple’smobileplatformsindetail. SQLitecanbefoundinSun’sSolarisoperatingenvironment,specificallythedatabasebackingthe ServiceManagementFacilitythatdebutedwithSolaris10,acorecomponentofitspredictiveselfhealingtechnology.SQLiteisintheMozillaProject’smozStorageC++/JavaScriptAPIlayer,whichwillbe thebackboneofpersonalinformationstorageforFirefox,Thunderbird,andSunbird.SQLitehasbeen addedaspartofthePHP5standardlibrary.ItalsoshipsaspartofTrolltech’scross-platformQtC++ applicationframework,whichisthefoundationofthepopularKDEwindowmanager,andmanyother softwareapplications.SQLiteisespeciallypopularinembeddedplatforms.MuchofRichardHipp’s SQLite-relatedbusinesshasbeenportingSQLitetovariousproprietaryembeddedplatforms.Symbian usesSQLitetoprovideSQLsupportinthenativeSymbianOSplatform.Googlehasmadeextensiveuse ofSQLiteintheAndroidmobilephoneoperatingsystemanduser-spaceapplications.SQLiteisso pervasivewithinAndroidthatChapter10isdedicatedtoshowingyouallaboutitsuseonAndroid devices.SQLiteisalsoincludedincommercialdevelopmentproductsforcellphoneapplications. 4 CHAPTER1■INTRODUCINGSQLITE Althoughitisrarelyadvertised,SQLiteisalsousedinavarietyofconsumerproducts,assometechsavvyconsumershavediscoveredinthecourseofpokingaroundunderthehood.Examplesincludethe D-LinkMediaLounge,theSlimDevicesSqueezeboxmusicplayer,andthePhilipsGoGearpersonal musicplayer.SomecleverconsumershaveevenfoundaSQLitedatabaseembeddedintheComplete NewYorkerDVDset—adigitallibraryofeveryissueoftheNewYorkermagazine—apparentlyusedbyits accompanyingsearchsoftware. YoucanfindSQLiteasanalternativeback-endstoragefacilityforawidearrayofopensource projectssuchasYum(thepackagemanagerforFedoraCore),MovableType,DSPAM,andEdgewall Software’sexcellentTracSCMandprojectmanagementsystem;possiblymostfamously,it’susedasthe built-indatabaseforFirefox,thewebbrowserfromMozilla.EvenpartsofSQLite’scoreutilitiescanbe foundinotheropensourceprojects.OnesuchexampleisitsLemonparsergenerator,whichthelighttpd webserverprojectusesforgeneratingtheparsercodeforreadingitsconfigurationfile.Indeed,there seemstobesuchavarietyofusesforSQLitethatGoogletooknoticeandawardedRichardHippwith “BestIntegrator”atO’Reilly’s2005OpenSourceConvention—longbeforeGoogleenteredthemobile spacewithAndroid.Seealsowww.sqlite.org/famous.htmlforotherideasofimportantSQLiteusers. Architecture SQLitehasanelegant,modulararchitecturethattakessomeuniqueapproachestorelationaldatabase management.Itconsistsofeightseparatemodulesgroupedwithinthreemajorsubsystems(asshownin Figure1-2).Thesemodulesdividequeryprocessingintodiscretetasksthatworklikeanassemblyline. Thetopofthestackcompilesthequery,themiddleexecutesit,andthebottomhandlesstorageand interfacingwiththeoperatingsystem. Interface B-Tree Compiler Tokenizer Pager Backend Core Parser OS Interface Code Generator Database Virtual Machine Figure1-2.SQLite’sarchitecture 5 CHAPTER1■INTRODUCINGSQLITE TheInterface TheinterfaceisthetopofthestackandconsistsoftheSQLiteCAPI.Itisthemeansthroughwhich programs,scriptinglanguages,andlibrariesalikeinteractwithSQLite.Literally,thisiswhereyouas developer,administrator,student,ormadscientisttalktoSQLite. TheCompiler Thecompilationprocessstartswiththetokenizerandparser.TheyworktogethertotakeaStructured QueryLanguage(SQL)statementintextform,validateitssyntax,andthenconvertittoahierarchical datastructurethatthelowerlayerscanmoreeasilymanipulate.SQLite’stokenizerishand-coded.Its parserisgeneratedbySQLite’scustomparsergenerator,whichiscalledLemon.TheLemonparser generatorisdesignedforhighperformanceandtakesspecialprecautionstoguardagainstmemory leaks.Oncethestatementhasbeenbrokenintotokens,evaluated,andrecastintheformofaparsetree, theparserpassesthetreedowntothecodegenerator. ThecodegeneratortranslatestheparsetreeintoakindofassemblylanguagespecifictoSQLite. Thisassemblylanguageconsistsofinstructionsthatareexecutablebyitsvirtualmachine.Thecode generator’ssolejobistoconverttheparsetreeintoacompletemini-programwritteninthisassembly languageandtohanditofftothevirtualmachineforprocessing. TheVirtualMachine Atthecenterofthestackisthevirtualmachine,alsocalledthevirtualdatabaseengine(VDBE).The VDBEisaregister-basedvirtualmachinethatworksonbytecode,makingitindependentofthe underlyingoperatingsystem,CPU,orsystemarchitecture.TheVDBE’sbytecode(orvirtualmachine language)consistsofmorethan100possibletasksknownasopcodes,whichareallcenteredondatabase operations.TheVDBEisdesignedspecificallyfordataprocessing.Everyinstructioninitsinstructionset eitheraccomplishesaspecificdatabaseoperation(suchasopeningacursoronatable,makingarecord, extractingacolumn,orbeginningatransaction)orperformsmanipulationstoprepareforsuchan operation.Altogetherandintherightorder,theVDBE’sinstructionsetcansatisfyanySQLcommand, howevercomplex.EverySQLstatementinSQLite—fromselectingandupdatingrowstocreatingtables, views,andindexes—isfirstcompiledintothisvirtualmachinelanguage,formingastand-alone instructionsetthatdefineshowtoperformthegivencommand.Forexample,takethefollowing statement: SELECT name FROM episodes LIMIT 10; ThiscompilesintotheVDBEprogramshowninListing1-1. 6 CHAPTER1■INTRODUCINGSQLITE Listing1-1.VDBEAssembly addr 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 opcode Trace Integer Goto OpenRead Rewind Column ResultRow IfZero Next Close Halt Transactio VerifyCook TableLock Goto p1 0 10 0 0 0 0 2 1 0 0 0 0 0 0 0 p2 0 1 11 2 9 2 1 9 5 0 0 0 4 2 3 p3 0 0 0 0 0 2 0 -1 0 0 0 0 0 0 0 p4 3 episodes p5 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 comment Theprogramconsistsof15instructions.Theseinstructions,performedinthisparticularorderwith thegivenoperands,willreturnthenamefieldofthefirsttenrecordsintheepisodestable(whichispartof theexampledatabaseincludedwiththisbook). Inmanyways,theVDBEistheheartofSQLite.AllofthemodulesbeforeitworktocreateaVDBE program,whileallmodulesafteritexisttoexecutethatprogram,oneinstructionatatime. TheBackEnd ThebackendconsistsoftheB-tree,pagecache,andOSinterface.TheB-treeandpagecache(pager) worktogetherasinformationbrokers.Theircurrencyisdatabasepages,whichareuniformlysized blocksofdatathat,likeshippingcontainers,aremadefortransportation.Insidethepagesarethegoods: moreinterestingbitsofinformationsuchasrecordsandcolumnsandindexentries.NeithertheB-tree northepagerhasanyknowledgeofthecontents.Theyonlymoveandorderpages;theydon’tcare what’sinside. TheB-tree’sjobisorder.Itmaintainsmanycomplexandintricaterelationshipsbetweenpages, whichkeepseverythingconnectedandeasytolocate.Itorganizespagesintotree-likestructures(which isthereasonforthename),whicharehighlyoptimizedforsearching.ThepagerservestheB-tree, feedingitpages.Itsjobistransportationandefficiency.Thepagertransferspagestoandfromdiskatthe B-tree’sbehest.Diskoperationsarestillsomeoftheslowestthingsacomputerhastodo,evenwith today’ssolid-statedisks.Therefore,thepagertriestospeedthisupbykeepingfrequentlyusedpages cachedinmemoryandthusminimizesthenumberoftimesithastodealdirectlywiththeharddrive.It usesspecialtechniquestopredictwhichpageswillbeneededinthefutureandthusanticipatetheneeds oftheB-tree,keepingpagesflyingasfastaspossible.Alsointhepager’sjobdescriptionaretransaction management,databaselocking,andcrashrecovery.ManyofthesejobsaremediatedbytheOS interface. Thingssuchasfilelockingareoftenimplementeddifferentlyindifferentoperatingsystems.TheOS interfaceprovidesanabstractionlayerthathidesthesedifferencesfromtheotherSQLitemodules.The endresultisthattheothermodulesseeasingleconsistentinterfacewithwhichtodothingslikefile locking.So,thepager,forexample,doesn’thavetoworryaboutdoingfilelockingonewayonWindows anddoingitanotherwayondifferentoperatingsystemssuchasUnix.ItletstheOSinterfaceworry aboutthis.ItjustsaystotheOSinterface,“Lockthisfile,”andtheOSinterfacefiguresouthowtodothat 7 CHAPTER1■INTRODUCINGSQLITE basedontheoperatingsystemonwhichithappenstoberunning.NotonlydoestheOSinterfacekeep codesimpleandtidyintheothermodules,butitalsokeepsthemessyissuescleanlyorganizedandat arm’slengthinoneplace.ThismakesiteasiertoportSQLitetodifferentoperatingsystems—allofthe OSissuesthatmustbeaddressedareclearlyidentifiedanddocumentedintheOSinterface’sAPI. UtilitiesandTestCode Miscellaneousutilitiesandcommonservicessuchasmemoryallocation,stringcomparison,and Unicodeconversionroutinesarekeptintheutilitiesmodule.Thisisbasicallyacatchallmodulefor servicesthatmultiplemodulesneedtouseorshare.Thetestingmodulecontainsamyriadofregression testsdesignedtoexamineeverylittlecornerofthedatabasecode.Thismoduleisoneofthereasons SQLiteissoreliable:itperformsalotofregressiontestingandmakesthosetestsavailableforanyoneto runandimprove. SQLite’s Features and Philosophy SQLiteoffersasurprisinglycomprehensiverangeoffeaturesandcapabilitiesdespiteitssmallsize.It supportsalargesubsetoftheANSISQL92standardforSQLfeatures(transactions,views,check constraints,foreignkeys,correlatedsubqueries,compoundqueries,andmore)alongwithmanyother featuresfoundinrelationaldatabases,suchastriggers,indexes,autoincrementcolumns,and LIMIT/OFFSETfeatures.Italsohasmanyrareoruniquefeatures,suchasin-memorydatabases,dynamic typing,andconflictresolution—otherwisereferredtoasmergeorupsertinotherRDBMSs—whichwill beexplainedinamoment. Asmentionedearlierinthischapter,SQLitehasanumberofgoverningprinciplesorcharacteristics thatservetomoreorlessdefineitsphilosophyandimplementation.I’llexpandontheseissuesnext. ZeroConfiguration Fromitsinitialconception,SQLitehasbeendesignedsothatitcanbeincorporatedandusedwithout theneedofaDBA.ConfiguringandadministeringSQLiteisassimpleasitgets.SQLitecontainsjust enoughfeaturestofitinasingleprogrammer’sbrain,andlikeitslibrary,itrequiresassmallafootprint inthegraymatterasitdoesinRAM. Portability SQLitewasdesignedspecificallywithportabilityinmind.ItcompilesandrunsonWindows,Linux,BSD, MacOSX,andcommercialUnixsystemssuchasSolaris,HP-UX,andAIX,aswellasmanyembedded platformssuchasQNX,VxWorks,Symbian,PalmOS,andWindowsCE.Itworksseamlesslyon32-and 64-bitarchitectureswithbothbig-andlittle-endianbyteorders.Portabilitydoesn’tstopwiththe softwareeither:SQLite’sdatabasefilesareasportableasitscode.Thedatabasefileformatisbinary compatibleacrossallsupportedoperatingsystems,hardwarearchitectures,andbyteorders.Youcan createaSQLitedatabaseonaLinuxworkstationanduseitonaMacorWindowsmachine,aniPhone,or otherdevice,withoutanyconversionormodification.Furthermore,SQLitedatabasescanholdupto2 terabytesofdata(limitedonlybytheoperatingsystem’smaximumfilesize)andnativelysupportboth UTF-8andUTF-16encoding. 8 CHAPTER1■INTRODUCINGSQLITE Compactness SQLitewasdesignedtobelightweightandself-contained;oneheaderfile,onelibrary,andyou’re relational—noexternaldatabaseserverrequired.Everythingpacksintolessthanhalfamegabyte,which issmallerthanmanyofthewebpagesyou’llvisitonanygivenday. SQLitedatabasesareordinaryoperatingsystemfiles.Regardlessofyoursystem,allobjectsinyour SQLitedatabase—tables,triggers,schema,indexes,andviews—arecontainedinasingleoperating systemfile.SQLiteusesvariable-lengthrecordswhereverpossible,allocatingonlytheminimumamount ofdataneededtoholdeachfield.A2-bytefieldsittinginavarchar(100)columntakesuponly3bytesof space,not100(theextrabyteisusedtorecorditstypeinformation). Simplicity Asaprogramminglibrary,SQLite’sAPIisoneofthesimplestandeasiesttouse.TheAPIisbothwell documentedandintuitive.ItisdesignedtohelpyoucustomizeSQLiteinmanyways,suchas implementingyourowncustomSQLfunctionsinC.Theopensourcecommunityalsohasacreateda vastnumberoflanguageandlibraryinterfaceswithwhichtouseSQLite.ThereareextensionsforPerl, Python,Ruby,Tcl/Tk,Java,PHP,VisualBasic,ODBC,Delphi,C#,VB.NET,Smalltalk,Ada,ObjectiveC, Eiffel,Rexx,Lisp,Scheme,Lua,Pike,ObjectiveCamel,Qt,WxWindows,REALBASIC,andothers.Youcan findanexhaustivelistontheSQLitewiki:www.sqlite.org/cvstrac/wiki?p=SqliteWrappers. SQLite’smodulardesignincludesmanyinnovativeideasthatenableittobefullfeaturedand extensiblewhileatthesametimeretainingagreatdegreeofsimplicitythroughoutitscodebase.Each moduleisaspecialized,independentsystemthatperformsaspecifictask.Thismodularitymakesit mucheasiertodevelopeachsystemindependentlyandtodebugqueriesastheypassfromonemodule tothenext—fromcompilationandplanningtoexecutionandmaterialization.Theendresultisthat thereisacrisp,well-definedseparationbetweenthefrontend(SQLcompiler)andbackend(storage system),allowingthetwotobecodedindependentlyofeachother.Thisdesignmakesiteasiertoadd newfeaturestothedatabaseengine,isfastertodebug,andresultsinbetteroverallreliability. Flexibility SeveralfactorsworktogethertomakeSQLiteaveryflexibledatabase.Asanembeddeddatabase,itoffers thebestofbothworlds:thepowerandflexibilityofarelationaldatabasefrontend,withthesimplicity andcompactnessofaB-treebackend.Withit,therearenolargedatabaseserverstoconfigure,no networkingorconnectivityproblemstoworryabout,noplatformlimitations,andnolicensefeesor royaltiestopay.Rather,yougetsimpleSQLsupportdroppedrightintoyourapplication. LiberalLicensing AllofSQLite’scodeisinthepublicdomain.Thereisnolicense.Noclaimofcopyrightismadeonany partofthecoresourcecode.Allcontributorstothiscodearerequiredtosignaffidavitsspecifically disavowinganycopyrightinterestincontributedcode.Thus,therearenolegalrestrictionsonhowyou mayusethesourcecodeinanyform.Youcanmodify,incorporate,distribute,sell,andusethecodefor anypurpose—commercialorotherwise—withoutanyroyaltyfeesorrestrictions. 9 CHAPTER1■INTRODUCINGSQLITE Reliability TheSQLitesourcecodeismorethanjustfree;italsohappenstobewellwritten.SQLite’scodebase consistsofabout70,000linesofstandardANSICthatareclean,modular,andwellcommented.The codebaseisdesignedtobeapproachable,easytounderstand,easytocustomize,andgenerallyvery accessible.ItiseasilywithintheabilityofacompetentCprogrammertofollowanypartofSQLiteorthe wholeofitwithsufficienttimeandstudy. Additionally,SQLite’scodeoffersafull-featuredAPIspecificallyforcustomizingandextending SQLitethroughtheadditionofuser-definedfunctions,aggregates,andcollatingsequencesalongwith supportforoperationalsecurity. WhileSQLite’smodulardesignsignificantlycontributestoitsoverallreliability,itssourcecodeis alsowelltested.Whereasthecoresoftware(libraryandutilities)consistsofabout70,000linesofcode, thedistributionincludesanextensivetestsuiteconsistingofmorethan45millionlinesoftestcode, whichasofJuly2009covers100percentofthecorecode.Askanydeveloperhowharditistobethat comprehensivewhentestinganontrivialamountofcode,andyoucanseewhypeoplehaverock-solid confidenceinthereliabilityofSQLite. Convenience SQLitealsohasanumberofuniquefeaturesthatprovideagreatdegreeofconvenience.Theseinclude dynamictyping,conflictresolution,andtheabilityto“attach”multipledatabasestoasinglesession. SQLite’sdynamictypingissomewhatakintothatfoundinscriptinglanguages(e.g.,ducktypingin Ruby).Specifically,thetypeofavariableisdeterminedbyitsvalue,notbyadeclarationasemployedin staticallytypedlanguages.Mostdatabasesystemsrestrictafield’svaluetothetypedeclaredinits respectivecolumn.Forexample,eachfieldinanintegercolumncanholdonlyintegersorpossibly NULL.InSQLite,whileacolumncanhaveadeclaredtype,fieldsarefreetodeviatefromthem,justasa variableinascriptinglanguagecanbereassignedavaluewithadifferenttype.Thiscanbeespecially helpfulforprototyping,sinceSQLitedoesnotforceyoutoexplicitlychangeacolumn’stype.Youneed onlychangehowyourprogramstoresinformationinthatcolumnratherthancontinuallyhavingto updatetheschemaandreloadyourdata. Conflictresolutionisanothergreatfeature.ItcanmakewritingSQL,aseasyasitis,eveneasier.This featureisbuiltintomanySQLoperationsandcanbemadetoperformwhatcanbecalledlazyupdates. Sayyouhavearecordyouneedtoinsert,butyouarenotsurewhetheronejustlikeitalreadyexistsin thedatabase.RatherthanwriteaSELECTstatementtolookforamatchandthenrecastyourINSERT toan UPDATE ifitdoes,conflictresolutionletsyousaytoSQLite,“Here,trytoinsertthisrecord,andifyoufind onewiththesamekey,justupdateitwiththesevaluesinstead.”Nowyou’vegonefromhavingtocode threedifferentSQLstatementstocoverallthebases(i.e.,SELECT,INSERT,andpossiblyUPDATE)tojust one:INSERT OR REPLACE(...).Otherrelationaldatabasesystemsmimicthisaspectofconflictresolution withUPSERTorMERGEstatements,butSQLitegoesonestepfurther.Youcanbuildconflictresolutioninto thetabledefinitionitselfanddispensewiththeneedtoeverspecifyitagainonfutureINSERTstatements. Infact,youcandispensewitheverhavingtowriteUPDATEstatementstothistableagain—justwrite INSERTstatementsandletSQLitedothedirtyworkoffiguringoutwhattodousingtheconflict resolutionrulesdefinedintheschema. Finally,SQLiteletsyou“attach”externaldatabasestoyourcurrentsession.Sayyouareconnected toonedatabase(foo.db)andneedtoworkonanother(bar.db).Ratherthanopeningaseparate connectionandjugglingmultipleconnectionhandlesinyourcode,youcansimplyattachthedatabase ofinteresttoyourcurrentconnectionwithasingleSQLcommand: ATTACH database bar.db as bar; 10 7 CHAPTER1■INTRODUCINGSQLITE Allofthetablesinbar.dbarenowaccessibleasiftheyexistedinfoo.db.Youcandetachitjustas easilywhenyou’redone.Thismakesallsortsofthingslikecopyingtablesbetweendatabasesveryeasy. Performance and Limitations SQLiteisaspeedydatabase.Butthewordsspeedy,fast,peppy,orquickarerathersubjectiveterms.Tobe perfectlyhonest,therearethingsSQLitecandofasterthanotherdatabases,andtherearethingsthatit cannot.Sufficeittosay,withintheparametersforwhichithasbeendesigned,SQLitecanbesaidtobe consistentlyfastandefficientacrosstheboard.SQLiteusesB-treesforindexesandB+-treesfortables, thesameasmostotherdatabasesystems.Forsearchingasingletable,itisasfastifnotfasterthanany otherdatabaseonaverage.SimpleSELECT,INSERT,andUPDATEstatementsareextremelyquick—virtually atthespeedofRAM(forin-memorydatabases)ordisk.HereSQLiteisoftenfasterthanotherdatabases, becauseithaslessoverheadtodealwithinstartingatransactionorgeneratingaqueryplanandbecause itdoesn’tincurtheoverheadofmakinganetworkcallstotheserverornegotiatingauthenticationand privileges.Itssimplicityheremakesitfast. Asqueriesbecomelargerandmorecomplex,however,querytimeovershadowsthenetworkcallor transactionoverhead,andthegamegoestothedatabasewiththebestoptimizer.Thisiswherelarger, moresophisticateddatabasesbegintoshine.WhileSQLitecancertainlydocomplexqueries,itdoesnot haveasophisticatedoptimizerorqueryplanner.YoucanalwaystrustSQLitetogiveyoutheresult,but whatitwon’tdoistrytodetermineoptimalpathsbycomputingmillionsofalternativequeryplansand selectingthefastestcandidate,asyoumightexpectfromOracleorPostgreSQL.Thus,ifyouarerunning complexqueriesonlargedatasets,oddsarethatSQLiteisnotgoingtobeasfastasdatabaseswith sophisticatedoptimizers. So,therearesituationswhereSQLiteisnotasfastaslargerdatabases.Butmanyifnotallofthese conditionsaretobeexpected.SQLiteisanembeddeddatabasedesignedforsmalltomedium-sized applications.Theselimitationsareinlinewithitsintendedpurpose.Manynewusersmakethemistake ofassumingthattheycanuseSQLiteasadrop-inreplacementforlargerrelationaldatabases. Sometimesyoucan;sometimesyoucan’t.Italldependsonwhatyouaretryingtodo. Ingeneral,therearetwomajorvariablesthatdefineSQLite’smainlimitations: • Concurrency.SQLitehascoarse-grainedlocking,whichallowsmultiplereaders butonlyonewriteratatime.Writersexclusivelylockthedatabaseduringwrites, andnooneelsehasaccessduringthattime.SQLitedoestakestepstominimize theamountoftimeinwhichexclusivelocksareheld.Generally,locksinSQLite arekeptforonlyafewmilliseconds.Butasageneralruleofthumb,ifyour applicationhashighwriteconcurrency(manyconnectionscompetingtowriteto thesamedatabase)anditistimecritical,youprobablyneedanotherdatabase.It isreallyamatteroftestingyourapplicationtoknowwhatkindofperformance youcanget.WehaveseenSQLitehandlemorethan500transactionspersecond for100concurrentconnectionsinsimplewebapplications.Butyourtransactions maydifferinthenumberofrecordsbeingmodifiedorthenumberandcomplexity ofthequeriesinvolved.Acceptableconcurrencyalldependsonyourparticular applicationandcanbedeterminedempiricallyonlybydirecttesting.Ingeneral, thisistruewithanydatabase:youdon’tknowwhatkindofperformanceyour applicationwillgetuntilyoudoreal-worldtests. 11 CHAPTER1■INTRODUCINGSQLITE • Networking.AlthoughSQLitedatabasescanbesharedovernetworkfilesystems, thelatencyassociatedwithsuchfilesystemscancauseperformancetosuffer. Worse,bugsinnetworkfilesystemimplementationscanalsomakeopeningand modifyingremotefiles—SQLiteorotherwise—errorprone.Ifthefilesystem’s lockingdoesnotworkproperly,twoclientsmaybeallowedtosimultaneously modifythesamedatabasefile,whichwillalmostcertainlyresultindatabase corruption.ItisnotthatSQLiteisincapableofworkingoveranetworkfilesystem becauseofanythinginitsimplementation.Rather,SQLiteisatthemercyofthe underlyingfilesystemandwireprotocol,andthosetechnologiesarenotalways perfect.Forinstance,manyversionsofNFShaveaflawedfcntl() implementation,meaningthatlockingdoesnotbehaveasintended.NewerNFS versions,suchareSolarisNFSv4,workjustfineandreliablyimplementthe requisitelockingmechanismsneededbySQLite.However,theSQLitedevelopers haveneitherthetimenortheresourcestocertifythatanygivennetworkfile systemworksflawlesslyinallcases. Again,mostoftheselimitationsareintentional,resultingfromSQLite’sdesign.Supportinghigh writeconcurrency,forexample,bringswithitgreatdealofcomplexity,andthisrunscountertoSQLite’s simplicityindesign.Similarly,beinganembeddeddatabase,SQLiteintentionallydoesnotsupport networking.Thisshouldcomeasnosurprise.Inshort,whatSQLitecan’tdoisadirectresultofwhatit can.Itwasdesignedtooperateasamodular,simple,compact,andeasy-to-useembeddedrelational databasewhosecodebaseiswithinthereachoftheprogrammersusingit.Andinmanyrespects,itcan dowhatmanyotherdatabasescannot,suchasruninembeddedenvironmentswhereactualpower consumptionisalimitingfactor. WhileSQLite’sSQLimplementationisquitegood,therearesomethingsitcurrentlydoesnot implement.Theseareasfollows: 12 • Completetriggersupport.SQLitesupportsalmostallthestandardfeaturesfor triggers,includingrecursivetriggersandINSTEAD OFtriggers.However,forall triggertypes,SQLitecurrentlyrequiresFOR EACH ROWbehavior,wherethetriggered actionisevaluatedforeveryrowaffectedbythetriggeringquery.ANSISQL92also describesaFOR EACHSTATEMENTtriggerstyle,whichisnotcurrentlysupported. • CompleteALTERTABLEsupport.OnlytheRENAMETABLEandADD COLUMNvariants oftheALTER TABLEcommandaresupported.OtherkindsofALTER TABLE operationssuchasDROP COLUMN,ALTER COLUMN,andADD CONSTRAINTarenot implemented. • RIGHTandFULLOUTERJOIN.LEFT OUTER JOINisimplemented,butRIGHT OUTER JOINandFULL OUTER JOINarenot.EveryRIGHT OUTER JOINhasaprovably semanticallyidenticalLEFT OUTER JOIN,andviceversa.AnyRIGHT OUT JOINcanbe implementedasaLEFT OUTER JOINbysimplyreversingtheorderofthetablesand modifyingthejoinconstraint.AFULL OUTER JOINcanbeimplementedasa combinationoftwoLEFT OUTER JOINstatements,aUNION,andappropriateNULL filteringintheWHEREclause. • Updatableviews.ViewsinSQLiteareread-only.YoumaynotexecuteaDELETE, INSERT,orUPDATEstatementonaview.Butyoucancreateatriggerthatfiresonan attempttoDELETE,INSERT,orUPDATEaviewanddowhatyouneedinthebodyof thetrigger. CHAPTER1■INTRODUCINGSQLITE • Windowingfunctions.OneofthenewfeaturesetsspecifiedinANSISQL99are thewindowingfunctions.Theseprovidepost-processinganalyticfunctionsfor results,sucharanking,rollingaverages,lagandleadcalculation,andsoon. SQLitecurrentlyonlytargetsANSISQL92compliance,soitdoesn’tsupport windowingfunctionslikeRANK(),ROW_NUMBER(),andsoon. • GRANTandREVOKE.SinceSQLitereadsandwritesanordinarydiskfile,theonly accesspermissionsthatcanbeappliedarethenormalfileaccesspermissionsof theunderlyingoperatingsystem.GRANTandREVOKEcommandsingeneralare aimedatmuchhigher-endsystemswheretherearemultipleuserswhohave varyingaccesslevelstodatainthedatabase.IntheSQLitemodel,theapplication isthemainuserandhasaccesstotheentiredatabase.Accessinthismodelis definedattheapplicationlevel—specifically,whatapplicationshaveaccesstothe databasefile. Inadditiontowhatislistedhere,thereisapageontheSQLitewikidevotedtoreporting unsupportedSQL.Itislocatedatwww.sqlite.org/cvstrac/wiki?p=UnsupportedSql. Who Should Read This Book SQLitehasmanyusesandthereforedrawsawideanddiverseaudience.Whetheryouareaprogrammer, webdeveloper,systemsadministrator,orjustcasualuserlookingtolearnaboutrelationaldatabases, thisbookaimstohelpyouunderstandandgetthemostoutofyourparticularuseforSQLite. SQLiteisaterrificdatabasetostartonifyouarenewtorelationaldatabases.Thisbookwillhelpyou notonlygetstartedwithSQLitebutalsobecomeacompetentuserofSQL.Itwillalsoprovideyouwitha goodfoundationwithwhichtomoveontolargerrelationalsystemsandexploremoreadvancedfeatures andtopics. Forprogrammers,thisbookassumesonlythatyouknowtheprogramminglanguageinwhichyou intendtouseSQLiteandthebasicsofrelationaltheory.Furthermore,itdoesmorethandocumentAPIs. Ifanything,thatistheleastofwhatitdoes,becauseAPIdocumentationonlyillustrateshowaninterface works.Aswithanydatabase,youhavetohavesomeideaofhowthatdatabaseworksinternallytogetthe mostoutofit.Everydatabasehasuniquearchitecturalaspects,specificrelationalfeatures,and importantlimitations,allofwhichgoodprogrammerslearnaboutandtakeintoconsiderationwhen writingtheircode.SQLite,thoughsimpleandstraightforward,isnoexception.Asaprogrammer,you needtoknowsomethingabouthowitprocessesdatainternallytogetittoworkwellwithyour application.Thisbookshowsyouhow.ItcoverstheAPIandexploreshowitworksinrelationtoSQLite’s architecture,allowingCprogrammers,webdevelopers,andscriptwritersaliketowritemoreinformed code.ThishelpsyoubetterunderstandnotonlywhatSQLitecandobutalsowhatitcan’t.Your knowledgeofthearchitecturewilltellyoubetterthananylistofruleswhenSQLiteisorisn’tagoodfit forwhatyouaretryingtoaccomplish.You’llknowif,when,andwhereyouneedtoconsideranother approach. Oneofthemostimportantaimsinthisbookistoteachconceptsoverrecipes—toadequately addressbothhowandwhy.Bythetimeyou’redone,youwillhavebothaconceptualandpractical understandingofhowsomethingworks.Tothatend,thisbookincludesboththeoreticalmaterial intermixedwithmanyfiguresandexamplesdesignedspecificallytoillustratethetopicsathandand providereal-worldvalue. 13 CHAPTER1■INTRODUCINGSQLITE How This Book Is Organized Thisbookisdividedintothreeparts:SQLitethedatabase,SQLitetheprogramminglibrary,and referencematerial.ThedatabaseaspectsofSQLitearecoveredinChapters2,3,and4.Theprogramming aspectsofSQLitearecoveredinChapters5–8.Abriefchapteroutlineisasfollows: Chapter1,“IntroducingSQLite,”introducesthemainfeaturesofSQLite,its originandhistory,andthescopeandobjectivesofthisbook(youarereading thisnow!) Chapter2,“GettingStarted,”covershowtoobtainanduseSQLite.Itillustrates howtogetSQLiteinbinaryandsourceform,aswellashowtocompileand builditonavarietyofplatforms.ItexplainshowtousetheSQLitecommandlineutilitytocreateandworkwithdatabases. Chapter3,“SQLforSQLite,”providessomebackgroundbehindSQL.It introducesmanyofthebasicSQLcommands,suchasthoseforcreatingtables andselectingandworkingwithdata.Thischapteractsasbothanoverviewfor SQLite’sownapproachtoSQLandaquickintroductionforthoseneedinga refresheronSQLitself. Chapter4,“AdvancedSQLinSQLite,”continuesfromChapter3withcoverage ofmorecomplexqueriesandexploreseveryaspectoftheremaining commandsinSQLite’sSQLimplementation. Chapter5,“SQLiteDesignandConcepts,”laysthegroundworkfor programmingwithSQLite.ItillustratestheSQLiteAPI,itsarchitecture,and howthetwoworkinrelationtooneanother.Itaddressestopicssuchas transactionsandlocking.Itprovidesprogrammersofalllanguageswithaclear understandingofhowSQLiteworksinternallyandwhattokeepinmindwhen writingprogramsthatuseit. Chapter6,“TheCoreCAPI,”coversthepartoftheSQLiteCAPIrelatedto executingqueries.Withsectionsonconnectingtodatabases,executingqueries, obtainingdata,managingtransactions,andtracingyourcode,thischapter coversallpartsoftheAPIrelatedtoqueryanddataprocessing. Chapter7,“TheExtensionCAPI,”coverstheremainingpartoftheCAPI devotedtocustomizingandextendingSQLite.SQLiteprovidesfacilitiesfor implementinguser-definedSQLfunctions,aggregates,andcollations.This chapterillustratesexampleimplementationsofthesefeaturesandprovides practicalexamplesoftheiruse. Chapter8,“LanguageBindingsforSQLite,”providesaconciseintroductionto SQLiteprogramminginarangeofpopularlanguagessuchasPerl,Python, Ruby,Java,andPHP. Chapter9,“SQLiteforAppleiPhoneandiPad,”focusesonhowtouseSQLite whendevelopingforApple’smobileplatforms. 14 CHAPTER1■INTRODUCINGSQLITE Chapter10,“SQLiteforGoogleAndroiddevices,”covershowSQLiteisbaked intotheAndroidplatformandhowtodevelopwithSQLitefortheexplosionof devicesthatnowrunAndroid. Chapter11,“SQLiteInternals,”explorestheinnerworkingsofSQLite.Itisa high-leveloverviewofthesourcecodeandprovidesaglimpseintohowthe majorsubsystemsareimplemented.Thisprovidesprogrammerswithadeeper understandingofSQLite’sdesigndecisions,assumptions,andtrade-offs,as wellasapointofdeparturefordeveloperswhowanttoworkonSQLite. DATABASE EXAMPLES Theexampledatabasesaccompanyingthisbookareavailableonlineandcanbedownloadedfromthe Apresswebsite(www.apress.com).EachdatabaseisinSQLformat,andyoucansimplyfollowthe procedurescoveredinChapter2tocreatethemusingtheSQLitecommand-lineprogram.Theexample databasesarefurtherexplainedandillustratedastheyareintroducedinthisbook. Thesourcecodeforallexamplesisalsoavailableonline.AllexamplescompileandrunonWindows,Linux, andUnix.Foreachexample,makefilesareincludedforLinuxandUnixenvironments,andVisualC++ projectshavebeencreatedforWindowsusers. Additional Information TheSQLitewebsitehasawealthofinformation,includingtheofficialdocumentation,mailinglists,wiki, andothergeneralinformation.Itislocatedatwww.sqlite.org.TheSQLitecommunityisveryhelpful, andyoumayfindeverythingyouneedonSQLite’smailinglist.Additionally,SQLite’sauthoroffers professionaltrainingandsupportforSQLite,whichincludescustomprogramming(portingto embeddedplatforms,etc.),andenhancedversionsofSQLite,whichincludenativeencryptionand extremelysmallversionsoptimizedforembeddedapplications.Youcanfindmoreinformationat www.hwaci.com/sw/sqlite/prosupport.html. Summary SQLiteisnottobeconfusedwithotherlargerdatabaseslikeOracleorPostgreSQL.Whereasdedicated relationaldatabasessuchastheseareelectronicjuggernauts,SQLiteisadigitalSwissArmyknife. Whereaslarge-scalededicatedrelationaldatabasesaredesignedforthousandsofusers,SQLiteis designedforthousandsofuses.Itismorethanadatabase.Althoughatoolinitsownright,itisatoolfor makingtoolsaswell.Itisatrueutility,engineeredtoenableyou—thedeveloper,user,or administrator—toquicklyandeasilyshapethosedisparatepilesofdataintoorder,andmanipulate themtoyourlikingwithminimaleffort. 15 CHAPTER1■INTRODUCINGSQLITE SQLiteispublicdomainsoftware.Free.Youcandoanythingwithitoritssourcecodeyoulike.No licenses,noinstallprograms,norestrictions.Justcopyandrun.Itisalsoportable,welltested,and reliable.Ithasaclean,modulardesignthathelpskeepthesystemsimple,easytodevelop,andeasyto debug.Inadditiontogooddesign,ithasgoodtesting.ThereismorecodewrittentotestSQLitethan thereisSQLitecodetotest.Itshouldnotbetoosurprising,then,thatSQLitehasprovenitselftobea solid,reliabledatabaseoveritsfive-yearhistory. Finally,SQLiteisfun.Atleastwethinkso,andwehopethatyouwillfinditequallyusefuland enjoyable. Ifyouhaveanycommentsorsuggestionsonthisbookoritsexamples,pleasefeelfreetocontact theauthorsat[email protected] (Michael)or[email protected] (Grant). 16 CHAPTER 2 ■■■ Getting Started It’sveryeasytobeginusingSQLitenomatterwhatoperatingsystemyouareusing.Forthevastmajority ofusers,youcanbeupandrunningwithSQLiteinlessthanfiveminutes,regardlessofexperience.This chaptercoverseverythingyouneedtoknowinordertoinstallSQLiteandworkwithdatabases.Bythe timewearedone,youwillhaveaworkingknowledgeofwheretoobtainSQLitesoftwareorsourcecode andhowtoinstallorcompileitonmultipleplatforms.You’llbeworkingwithnewSQLitedatabasesand creatingtables,views,andindexesthatyoucanquery,backup,andrestore. YouwilllearneverythingyouneedtoknowaboutmanagingSQLitedatabases,includinghowto create,view,andexaminetheircontents.Finally,youwillbeintroducedtoseveraltoolswithwhichto workwithSQLiteinvariousenvironments.ThischapterdoesincludesomeexamplesthatuseSQLto introducetheSQLitecommand-lineprogram.IfyouarenotyetfamiliarwithSQL,theexampleswillbe easyenoughthatyoushouldstillbeabletofollowthemwithoutmuchtrouble.Wetakeanin-depthlook atSQLindetailinChapters3and4. Where to Get SQLite TheSQLitewebsite(www.sqlite.org)providesbothprecompiledbinariesofSQLiteaswellassource code.BinariesareavailableforpopularplatformsincludingMacOSX,Windows,andLinux. Thereareseveralbinarypackagestochoosefrom,eachofwhichisspecifictoaparticularwayof usingSQLite.Thebinarypackagesareasfollows: sqlite3command-lineprogram(CLP):ThisversionoftheSQLitecommandlineprogramhasthedatabaseenginecompiledinwithstaticallylinked dependencies,actingasaself-contained,stand-aloneprogram.Thisprovidesa convenientwaytoworkwithSQLitedatabasesfromthecommandlinewithout havingtoworryaboutwhethertheSQLitesharedlibraryisinstalledonyour systemorlocatedintherightplace.IfyourunonofthecontemporaryLinux distributionsorOSX,youalmostcertainlyalreadyhavethisinstalled. SQLitesharedlibrary(DLLor“so”):ThisistheSQLitedatabaseengine packagedintoasharedobject(so)orWindowsdynamiclinklibrary(DDL).Use thiswithprogramsthatdynamicallylinktoSQLite.Thisformmakesiteasierto upgradeSQLitewithouthavingtorecompilethesoftwarethatdependsonit. Notethatthereiscurrentlynoprecompiled.dylibsharedlibraryforMacOSX. 17 CHAPTER2■GETTINGSTARTED SQLiteAnalyzer:TheAnalyzertoolisusefulforinspectingmanyqualitiesand statisticsaboutagivenSQLitedatabasefile,includingthingssuchasphysical datadistributionandlayoutwithinthefile,relativefragmentation,internaldata sizeandfreespace,andothermeasures.Thisinformationisveryusefulfor performanceoptimizationwork. Tclextension:ThisbinaryincorporatestheTcllanguageextensionswiththe SQLitecore.ThisallowsyoutoconnecttoSQLitefromwithintheTcllanguage. TclandCarethetwolanguagebindingsprovidedbytheSQLiteteam themselves.OtherlanguagebindingsarecoveredinChapter8. SQLite’ssourcecodeisprovidedinavarietyofformsforconvenienceandtotargetdifferent platforms.Themaindifferencesinthesourcedistributionsconcernwhetherthecodeisamalgamated intoasinglesourcefileandheaderorleftinconstituentfiles.Thereisalsoasourcepackage incorporatingtheTclExtensionArchitecture(TEA)forthosewhowanttocompileSQLitewithTcl bindings. TheSQLiteamalgamatedsourceappearstwiceonthewebsite—onceasazipfileandagainasa gzippedtarball.Thesourcecodeitselfdoesnotdifferbetweenthesesourcedistributions.Thezipfileis generallyrecommendedandinparticularistheonlysourcereadilysuitableforcompilationonWindows (unlessyouprefergoingtolaboriouseffortonthatplatform).Thezipfilesourcedistributionbenefits fromalreadyhavingcertainpreprocessingandcodegenerationperformedonthecodebybuildtools likeGNUautoconf.ThismeansWindowsusersdon’tneedtohuntdownWindows-specificequivalents forthesetools.ThegzippedtarballistargetedtousersofLinux,Unixflavors,MacOSX,BSDvariants, andsoon.Theseplatformsincludeintheirnormaldistributionstheexpectedtoolchaintodomuchof thepreprocessingwork,aswellasnormalcompilation,sousersofthoseplatformscanadoptthissource packageintheknowledgetheyneednothuntdownadditionaltoolstocompileSQLite. SQLite on Windows WhetheryouareusingSQLiteasanenduser,writingprogramsthatuseSQLite,orusingitasalearning platformforrelationaltheoryandSQL,SQLitecanbeinstalledonWindowswithaminimumoffuss.In thissection,wewillcoveralltheoptions,frominstallingtheavailablebinarypackagestobuilding everythingfromsourceusingthemostpopularcompilers.Westartwiththeeasythingsfirstand progresstothingsmoretechnicallychallenging. GettingtheCommand-LineProgram TheSQLitecommand-lineprogram(hereafterreferredtoastheCLP)isbyfartheeasiestwaytoget startedusingSQLite.FollowthesestepstoobtaintheCLP: 18 1. Openyourfavoritebrowser,andnavigatetotheSQLitehomepageat www.sqlite.org. 2. Clickthedownloadlinkatthetopofthepage.Thiswilltakeyoutothe downloadpage. CHAPTER2■GETTINGSTARTED 3. ScrolldowntothesectionPrecompiledBinariesForWindows,whereyouwill findfilenamesalongthelinesofsqlite-3_x_y_z.zip,wherex,y,andzarethe minor-versionnumbers.Thereshouldbeacommentbesideitthatreads“A command-lineprogramforaccessingandmodifyingSQLitedatabases.” DownloadthisfiletoyourWindowsenvironment. 4. Unzipthefile,eitherusingWindowsbuilt-insupportforzipfilesorusingyour favoritethird-partycompressiontoolsuchasWinZipor7-Zip.Thezipfile shouldcontainasinglefilenamedsqlite3.exe.Youcanstartusingthefile fromthelocationinwhichyouunzippedit,orifyouwouldliketoruntheCLP fromanydirectoryintheWindowsshell,youneedtocopyittoafolderthatis inyourWindowssystempath.Asuitabledefaultthatshouldworkonall versionsofWindowsisthe\windows\system32folderonyourrootpartition (C:\ for most systems). ■NoteIfyoudon’tknowyourWindowssystempathvalue,youcanfinditinseveralways.Fromacommand prompt,youcanexecutethiscommand: echo %PATH% Thiswillreturnastringofdirectoriesseparatedbysemicolons—thisisyourpathvalue.Forthegraphically inclined,youcanobtainthesameinformationfromtheControlPanel.ClickStartControlPanel.Choosethe Systemicon.Intheresultingdialogbox,selecttheAdvancedtab,andclicktheEnvironmentalVariablesbutton.In theSystemVariableslistinthelowerhalfofthedialogbox,double-clickthePathentry.ThiswillopentheEdit SystemVariablesdialogbox,inwhichtheValuestextboxcontainsyourpathlist.Youcanaddadditional directoriestothispathifyoulikebysimplyappendingasemicolontotheendofthelineandtypingthenewpath. 5. Openacommandshell.Youcandothisindifferentways.UsingtheWindows Startmenu,selectStartRun.TypecmdintheOpendrop-downbox,andclick OK(Figure2-1).ThiswillopenaWindowscommandshell.Ifthisdoesn’twork, tryselectingStartAllProgramsAccessoriesCommandPrompt. Figure2-1.OpeningaWindowscommandshell 19 CHAPTER2■GETTINGSTARTED 6. Withintheshell,typesqlite3onthecommandline,andpressEnter.This shouldbringupaSQLitecommandprompt.(Ifyougetanerror,thenthe sqlite3.exeexecutablehasnotbeencopiedtoafolderinyoursystempath. Recheckyourpath,andplaceacopyoftheprogramsomewherewithinit.) WhentheSQLiteshellappears,type .helponthecommandline.Thiswill displayalistofcommandswiththeirassociateddescriptionssimilartotheone inFigure2-2.Type.exittoexittheprogram.Younowhaveaworkingcopyof theSQLiteCLPinstalledonyoursystem. Figure2-2.TheSQLiteshellonWindows 20 CHAPTER2■GETTINGSTARTED IfyouareespeciallyeagertoworkwithSQLiteatthispoint,youmaywanttoskipaheadtothe section“TheCLPinShellMode.”Thenextfewsectionsaregearedtodeveloperswhowanttowrite programsthatuseSQLite. GettingtheSQLiteDLL TheSQLiteDLLisusedforsoftwarecompiledtolinkdynamicallytoSQLite.Thismeansthatthe applicationwillloadtheDLLatruntimewhenSQLitefeaturesarerequired,insteadofembeddingthe SQLitecodeintheapplicationitself.SoftwarethatusesSQLiteinthisfashiontypicallyincludesitsown copyoftheSQLiteDLLandinstallsitautomaticallywiththesoftware. IfyouplantodevelopwithSQLite,usingtheDLLisprobablytheeasiestwaytostart.Youcanobtain theSQLiteDLLasfollows: 1. GototheSQLitehomepage,www.sqlite.com,andchoosethedownloadlinkatthetopofthe page.Thiswilltakeyoutothedownloadpage. 2. Onthedownloadpage,findthesectionPrecompiledBinariesForWindows. 3. LocatetheDLLzipfile.Thisfilewillhavethedescription“ThisisaDLLofthe SQLitelibrarywithouttheTCLbindings.”Thefilenamewillhavetheform sqlitedll-3_x_y_z.zip,wherex,y,andzaretheminorversions.Ifyouwant Tclsupportincluded,selectthefilewiththenameoftheformtclsqlitedll3_x_y_z.zip. 4. Downloadandunzipthefile.Theextractedcontentsshouldincludetwofiles: theactualDLLfile(sqlite3.dll)togetherwithanotherfilecalledsqlite3.def. TheSQLiteDLLprovidedhereisthreadsafe,becauseitwascompiledwiththe THREADSAFEpreprocessorflagdefined.ThisallowsyoutouseSQLitefeaturesin multithreadedapplications;youcanthereforeusethisDLLinmultithreaded programs,performingsimultaneousactionsinmultiplethreadssafely. TousetheDLL,itneedstoeitherbeinthesamefolderwithprogramsthatuseit,beplaced somewhereinthesystem’spath(seethenoteontheWindowsSystempathintheprevioussection),or followWindow’sdynamiclibraryloadingrulesforlocationssearchedforDLLs. IfyouwanttowriteprogramsthatusetheSQLiteDLL,youwillneedtocreateanimportlibrarywith whichtolinkyourprograms.Thisisquitesimpletodousingthesqlite3.deffilementionedearlier.If youareusingC++inMicrosoftVisualStudio,openthecommandprompt,changethedirectorytothe SQLitedistribution,andsimplyrunthefollowingcommand: LIB /DEF:sqlite3.def Youshouldseenormallibrarygenerationoutputsimilartothefollowingexample: C:\sqlite>lib /DEF:sqlite3.def Microsoft (R) Library Manager Version 10.00.30319.01 Copyright (C) Microsoft Corporation. All rights reserved. LINK : warning LNK4068: /MACHINE not specified; defaulting to X86 Creating library sqlite3.lib and object sqlite3.exp Thiswillgenerateanimportlibrarynamedsqlite3.libandanexportsfilenamed.exp.Ifyouare usingMinGW(seethesection“BuildingSQLitewithMinGW”laterinthischapter),runthiscommand: 21 CHAPTER2■GETTINGSTARTED dlltool --def sqlite3.def --dllname sqlite3.dll --output-lib sqlite3.lib ThedlltoolforMinGWwillalsocreateanimportlibrarycalledsqlite3.libwithwhichyoucanlink yourprograms.Bylinkingyourprogramstothisimportlibrary,theywillloadandusetheSQLiteDLL uponexecution. CompilingtheSQLiteSourceCodeonWindows BuildingSQLitefromsourcewithinWindowsisstraightforward.Dependingonthecompileryouare usingandwhatyouaretryingtoachieve,thereareseveralapproachestocompilingSQLite.Themost commonscenariosonWindowsincludeusingMicrosoftVisualC++,MinGW,orEclipse(whichoften usesMinGWforC++work).We’llcovereachofthesehere.Youcanfindinformationabouthowto compileSQLitewithothercompilersontheSQLitewiki(www.sqlite.org/cvstrac/ wiki?p=HowToCompile). The Stable Source Distribution YoucanobtainstableversionsofSQLite’ssourcecodeinzipfilesfromtheSQLitewebsite.BleedingedgeversionscanbeobtainedfromtheFossildistributedsourcecontrolsystemmaintainedbythe SQLiteteam.UnlessyouarefamiliarwithFossil,usingthesourcedistributionistheeasiestwaytogo.To downloadastablesourcedistribution,followthesesteps: 1. GototheSQLitewebsite, www.sqlite.org.Followthedownloadlink,whichwilltakeyouto thedownloadpage. 2. Onthedownloadpage,findtheSourceCodesection. 3. Thefirstfilelistedistherecommendedzipfilecontainingthesourcecodeand suitableforcompilationforWindows.Thefilewillbenamed sqliteamalgamation-3-x_y_z.zip,wherex,y,andz(andpossiblyfurtherminor digits)aretheminor-versionnumbers. ■NoteTheziparchiveandtheothertarballsonthedownloadpagedifferslightlyintheircontents.Althoughthey containidenticalsourcecode,theSQLitedistributionusessomePOSIXbuildtools(sed,awk,andsoon)to dynamicallygeneratesomeCsourcecodeinthebuildprocess.Thesebuildtoolsarenotavailablebydefaulton Windowssystems.Therefore,thezipsourcearchiveincludesallthepreprocessingandgeneratedcodeasa matterofconveniencetoWindowsuserswholackthebuildsupportinfrastructureofLinux,Unix,MacOSX,and soon.ThisiswhyWindowsusersshouldusetheziparchivesratherthanthetarballsonthedownloadpage.Itis stillpossibletobuildthetarballsonWindows,butyouneedtherequisitebuildtoolsfromasourcesuchasCygwin, MinGW,GnuWin32,orsimilar. 4. 22 Extract/unzipthefiletoadirectoryofyourchoosing.Theextractedcontents willbethecompleteSQLiteversion3sourcecode,suitableforWindows. CHAPTER2■GETTINGSTARTED Anonymous Fossil Source Control IfyouwanttoplaywiththelatestfeaturesorparticipateinSQLitedevelopment,thenretrievingSQLite fromtheproject’sFossilsourcecontrolsystemmakesthemostsense.Fossilprovidesthesamekindof anonymousaccessyou’lllikelyhaveseeninothersourcecontrolsystems,likeCVS,Subversion, Perforce,Git,andsoon.FossilallowsyoutomaintaintheabsolutelylatestversionoftheSQLitesource codebyaccessingthesourcestraightfromyourbrowser!Ifyouwant,youcankeepyourcopyofthe codesynceduptotheday,hour,orminutetostaycurrentwithchangesastheyarecommitted.Thus,if youseeanimportantbugfixorfeaturepostedthatyouwanttotakeadvantageof,youcanhaveFossil syncandrecompileyourcopyofthecode.Fossilevenincludesanautosyncfeaturetoguaranteeyou stayattheforefrontofanysourcechanges. ObtainingSQLitefromFossilonWindowscouldn’tbeeasier.LikeSQLitebinaries,Fossilis distributedasasinglestaticallylinkedfile.YoucandownloadFossilfromtheproject’shomepage, www.fossil-scm.org.Thedownloadpageincludesup-to-the-minutereleasesforWindows,aswellas MacOSXandLinux.UnziptheFossilarchivetoalocationonyourpath(seeourpreviousdiscussionon determiningyourPATHenvironmentvariable).Next,makeanewdirectorytohouseyourFossilsource extracts,orchooseanexistingdirectoryifyouprefer. YoucandomostofyoursourcecontrolworkwithFossilinabrowser—FossilactsasitsownHTTP servertohandlealltheserver-sidetasks.Thefastestwaytogetyourinitialcheck-outoftheSQLite sourcecodeistouseyournewlydownloadedfossil.exebinarytocloneoneoftheSQLiteonline repositories.Openacommandprompt,andchangedirectoriestotheneworexistingdirectoryyou’ve chosenforyourSQLiteFossilsourcecontrolrepository.Thenatthecommandprompt,issuetheFossil clonecommand,asshownhere: C:\sqlite\fossil.exe clone http://www.sqlite.org/src sqlite.fossil Bytes Cards Artifacts Deltas Send: 49 1 0 0 Received: 1499917 32606 0 0 Send: 10025 225 0 0 Received: 132364 239 7 193 ... Send: 4655 99 0 0 Received: 1698453 125 29 69 Total network traffic: 1379539 bytes sent, 17512520 bytes received Rebuilding repository meta-data... 32605 (100%)... project-id: 2ab58778c2967968b94284e989e43dc11791f548 server-id: 38f0c0987054889a5d2c0b4f27b370e9e8632a16 admin-user: fuzz (password is "******") Theformatofthecommandisfossil . Inthiscase,theactionwasclone,meaningtotakeacompletecopyoftheSQLiterepository.Weprovide oneoftheSQLiteFossilrepositoriesdescribedontheSQLitewebsite,inthiscasewww.sqlite.org/src. Lastly,weprovideanameofourchoosing,whichwillbethenameofthefileFossilcreatestocontain andmanageourcopyofthesource.ThiscanbeanynameyoulikethatsatisfiesWindowsfile-naming conventions.Wechoosesqlite.fossiltobeausefulnameremindinguswhatthefilecontainsand whatusesit. 23 CHAPTER2■GETTINGSTARTED ■NoteWearetargetingthecurrent“head”ofthesourcecontroltreeforSQLitewiththeexamplegiven.This meansyouwouldbecompilingfromthelatestandgreatestsource.That’satwo-edgedswordofcourse,giving youtheabsolutelatestdevelopmentsbutnotthebenefitofa“stable”release.Feelfreetochooseastablebranch ifyouprefer. YouarenowreadytolaunchandusetheFossilwebinterface.Fromyourcommandline,justrun thenextcommand(substituteyourowndirectoryandlocalrepositoryfilenameasappropriate). C:\sqlite\fossil.exe ui sqlite.fossil YoushouldseeoutputfromFossilindicatingithassuccessfullylauncheditsHTTPserverandis listeningforconnections.Thisshouldveryquicklydisappearbehindyourfavoritebrowser,whichFossil willhaveautomaticallyopenedatthehomeofyourlocalSQLiterepository,asshowninFigure2-3. Figure2-3.YourlocalSQLiteFossilsourcecontrolsystem,completewithup-to-datesource 24 CHAPTER2■GETTINGSTARTED YouarenowupandrunningwithFossil.Fromhere,you’llobviouslywanttostartwithcheckingout thecodesothatyoucanstartwork.That’sjustaseasyasmostotherFossilactions.First,fromyourshell, createadirectoryforthesource,andthenchangeintothatdirectory. mkdir c:\sqlite\src cd c:\sqlite\src NowyoucantellFossiltocheckoutthecurrentincarnationofthesource,usingtheopencommand: c:\sqlite\fossil.exe open c:\sqlite\sqlite.fossil You’llseeallthesourcefilesfortheSQLiteprojectflybyonthescreen.Whencompleted,around 15MBoffilesaredownloaded,andyouhavethesourcereadywithwhichtowork. BuildingtheSQLiteDLLwithMicrosoftVisualC++ TobuildtheSQLiteDLLfromsourceusingVisualC++,followthesesteps: 1. StartVisualStudio.CreateanewDLLprojectwithintheunpackedSQLitesourcedirectory. DothisbyselectingFileNewProject.UnderProjectTypes(Figure2-4),selectVisualC++ Projects,andthenselectWin32.ChoosetheWin32Projecttemplate.IntheLocationtextbox, enterthefoldernamethatcontainsyourSQLitesourcefolder.Inthisexample,itwouldbe C:\sqlite.IntheNametextbox,enterthenameofthefoldercontainingtheSQLitesource code—srcinthisexample.ThiswillcreatetheVisualC++projectinsidetheexistingSQLite sourcefolder(C:\sqlite\src).ClickOK. Figure2-4.CreatinganewVisualC++project 25 CHAPTER2■GETTINGSTARTED 2. Next,theWin32ApplicationWizardwillautomaticallyopen(Figure2-5). ChooseApplicationSettings,andsettheapplicationtypetoDLL.Besureto selecttheEmptyProjectbox.ClickFinish,andthiswillcreateablankDLL project. Figure2-5.TheWin32ApplicationWizard 26 3. AddSQLitesourcefilesandheaderstotheproject.SelectProjectAdd ExistingItem.Addall.cand.hfilesinthedirectoryexceptfortwofiles: tclsqlite.candshell.c.(ThefirstisforTclsupport;thesecondisforcreating theSQLiteCLP,neitherofwhichwewantinthiscase.) 4. Specifyanexportoramoduledefinition(.def)file.Thisfiledefineswhat symbols(orfunctions)toexport(makevisible)toprogramsthatlinktothe library.SQLite’ssourcedistributioniskindenoughtoincludesuchafile (sqlite3.def)forthisverypurpose.AlsowithinthePropertyPagesdialogbox, selectAllConfigurationsintheConfigurationdrop-downbox(Figure2-6). ThenclicktheLinkerfolder,andclicktheInputsubmenu.IntheModule DefinitionFilepropertypage,typesqlite3.def.Youarenowreadytobuild theDLL. CHAPTER2■GETTINGSTARTED Figure2-6.Projectproperties 5. Fromthemainmenu,selectBuildBuildsqlitetobuildtheDLL. 6. OnceyouhavebuilttheDLL,besuretocreatetheimportlibrary,asdescribed inthesection“GettingtheSQLiteDLL.” BuildingaDynamicallyLinkedSQLiteClientwithVisualC++ ThebinaryforastaticCLPisavailableontheSQLitewebsite,butwhatifyouwantaversionthatusesthe SQLiteDLL?TobuildsuchaversioninVisualC++,dothefollowing: ■NoteManyofthestepsareverysimilartotheprocessofbuildingaDLL,mentionedearlier—youmaywantto usesomeofthefigureslistedthereforreference. 1. Fromthemainmenu,selectFileNewProject.UnderProjectTypes,selectVisualC++ Projects,andthenselectWin32.ChoosetheWin32Projecttemplate.Nametheproject (shell,forexample),andclickOK. 27 CHAPTER2■GETTINGSTARTED 2. Afterthis,theWin32ApplicationWizardwillautomaticallyopen.Choose ApplicationSettings,settheapplicationtypetoConsoleApplication,andbe suretochecktheEmptyProjectbox.ClickFinishtocreateablankexecutable project. 3. NextyouwanttoaddtheSQLiteCLPsourcefile.SelectProjectAddExisting Item.Inthedialogboxthatappears,addthesourcefileshell.c. 4. TellVisualC++tolinkagainsttheSQLiteDLL.SelectProjectProperties.In thedialogboxthatappears,selectAllConfigurationsintheConfiguration drop-downbox.NextselecttheLinkerfolder.SelecttheInputsubmenu,and withintheAdditionalDependenciespropertypage,addsqlite3.lib.Youare nowreadytobuildtheprogram.NotethattheSQLiteDLLneedstobeeitherin thesamedirectoryasthecommand-lineprogramorintheWindowssystem path. ■NoteIfyoubuildtheSQLiteDLLwiththreadingenabledoryouobtaintheDLLfromtheSQLitewebsite,you needtousethemultithreadedMicrosoftCruntimelibraryDLLwhenbuildingtheCLP.Todothis,refertothe secondhalfofstep4in“BuildingtheSQLiteDLLwithMicrosoftVisualC++.”Itcontainstwoinformativefigures thatmakeiteasytosetthisoption. BuildingSQLitewithMinGW MinGW(www.mingw.org)isaforkoftheCygwinproject,anditprovidesanicedistributionoftheGNU CompilerCollection(GCC)forWindows.ItalsoincludesfreelyavailableWindows-specificheaderfiles andlibrariesthatyoucanusetocreatenativeWindowsprogramsthatdonotrelyonanythird-partyC runtimeDLLs.Putsimply,itisafreeC/C++compilerforWindows,andit’saverygoodoneatthat.Itis usuallyusedinconjunctionwithMSYS,whichoffersabash-likeshellandPOSIXenvironmentthat makesUnixusersfeelathomeonWindows.Together,thetwoprovideapowerfulenvironmentwith whichtocompileandbuildsoftwareonWindows.Thetwoarepopularbutalsocanbedifficulttostick togetherbyhand.Thankfully,severalverygoodbundlesexisttotakeallthehardworkoutofdeploying them,allowingyoutogetonwiththefunofcompilingyourownSQLitefromsource.Werecommend theTakeOffGWpackage,freelyavailablefromSourceForge. TobuildtheSQLiteDLLfromsourcewiththeTakeOffGWdistributionofMinGWandMSYS,dothe following: 28 1. Openyourfavoritebrowser,andnavigatetotheSourceForgewebsite:sourceforge.net. 2. SearchfortheTakeOffGWproject,ornavigatestraighttotheprojectpageat sourceforge.net/projects/takeoffgw/. 3. DownloadthelatestreleaseoftheTakeOffGWnetworkinstaller,usuallyjust calledsetup.exe. CHAPTER2■GETTINGSTARTED 4. AfterdownloadingtheTakeOffGWnetworkinstaller,runthesetup.exefile, andchoosethedefaultsforinstallationlocation,packagedirectory,andlinks totheInternet(rememberinganyproxyserveryoumayuse).Whenyougetto thepackageselectionpage,showninFigure2-7,besuretoselectallthe packagesavailableundertheMSYSheading.DothisbytogglingtheMSYS headingitselfuntilthephrase“install”appears. Figure2-7.TakeOffGWinstallationcomponents,withMSYSselectedforinstall 5. ClickNexttocontinue,andTakeOffGWwilldownloadandinstallallthe componentsrequired. 29 CHAPTER2■GETTINGSTARTED 6. DownloadtheLinux/UnixSQLitesourcecodedistribution.Navigateto www.sqlite.org,andclickthedownloadlink.Onthedownloadpage,findthe SourceCodesection.Thefileyouarelookingforisthesourcedistributionin tarballsform,whichshouldhaveanameoftheformsqlite-amalgamation3.x.y.z.tar.gz,wherex,y,andz(andpossiblyfurthernumbers)arethe minor-versionnumbers(atthetimeofthiswriting,thecurrentfilenameis sqlite-amalgamation-3.6.23.1.tar.gz).Downloadthetarball,andplaceitina temporarydirectory(e.g.,C:\Temp). 7. TakeOffGWwillhaveplacedanicononyourdesktop.Double-clickthaticonto opentheenvironment. 8. NavigatetoyourtemporarydirectoryinwhichyoudownloadedtheSQLite sourcedistribution.SincethisisaUnix-likeenvironment,youwillneedtouse Unixfilesystemconventions.Forexample,togettoc:\Temp,youwouldtype cd /c/Temp. 9. UnpacktheSQLitetarball.Issuethiscommand:tar-xzvfsqliteamalgamation-3.6.23.1.tar.gz. 10. Moveintotheunpackeddirectory: cd sqlite-3.6.32.1 11. Createthemakefile.FortheSQLitebinary,runthis: ./configure 12. Buildthesource: make Youwillseeconfigureandmakescrollmanylinesofstatusoutputtothescreen.Whenmake completes,younowhaveafunctionalSQLitebinary.Touseiteasily,addtheTakeOffGWbindirectoryto yourpath.IfyoufollowedthedefaultspromptedbytheTakeOffGWnetworkinstaller,thiswillbethe c:\cygwin\bindirectory.YoucannowuseWindowsExplorerorthecommandprompt,navigatetothe temporarydirectory,andrunsqlite3.exe.YounowhaveaworkingSQLiteCLP. SQLite on Linux, Mac OS X, and Other POSIX Systems SQLitecompilesandbuildsidenticallyonsystemssuchasLinux,MacOSX,FreeBSD,NetBSD, OpenBSD,Solaris,andothers—knownhistoricallyasPOSIXsystems(thoughthisisnowalessuseful term,becausesystemsasdiverseasmainframesandMicrosoftWindowshavebeenPOSIXcompliantfor morethanadecade).SQLitebinariescanbeobtainedinavarietyofwaysdependingontheparticular operatingsystem. BinariesandPackages IfyouareusingMacOS10.4(Tiger)orgreater,youalreadyhaveSQLiteinstalledonyoursystem.Ifnot, thereareseveralroutesyoucantaketoinstallit.TheeasiestwayistouseoneofthefollowingMacspecificpackagemanagementsystems,allofwhichincludepackagesorportsforSQLite: 30 CHAPTER2■GETTINGSTARTED MacPorts:MacPortsisprobablythemostpopularsourceofopensource software,tools,andencompassingpackagemanagementfeatureswithMac userstoday.ItincludestheabsolutelatestSQLitedistributions,including additionalpackagessuchastheTclbindings,andsoon. Fink:FinkisaDebian-basedpackagemanagementsystemthatusesDebian utilitiessuchasdpkg,dselect,andapt-get,inadditiontoitsownutility—fink. YoucandownloadFinkfromhttp://fink.sourceforge.net.WithFink,itis possibletoinstallstraightfromprecompiledbinaries.Nocompilationstepis needed. BSDuserswillhavenotroubleinstallingSQLiteeither.FreeBSD,OpenBSD,andNetBSDallhave packagesand/orportsforSQLite,allofwhichareveryeasytoinstall.Eachdistributionhasportsforvery recentversionsofSQLite3.6.x. Solaris10usesSQLiteaspartoftheOS,originallyshippingwithversion2,butifyoursystemis patchedregularly,contemporarySolaris10platformsarepatchedtoversion3.6.20. Asmentionedearlier,binariesforLinuxareavailabledirectlyfromtheSQLitewebsite.The downloadpageonSQLite’swebsiteprovidesthefollowingbinaries: Staticallylinkedcommand-lineprogram:Thefilenameisoftheform sqlite3-3.x.y.z.bin.gz,wherex,y,andz(andpossiblymoredigits)arethe minor-versionnumbers. Sharedlibrary:Twoformsofthesharedlibraryexist.OneformincludestheTcl bindings;theotherdoesnot.Thedescriptionnexttoeachhighlightswhich sharedlibrarysourceiswhich.Notethatthesharedlibrariesprovidedarenot threadsafe.Ifyouneedathread-safeversion,youwillhavetocompilethe libraryfromsource.Seethesection“CompilingSQLitefromSource”formore details. SQLiteAnalyzer:Thisisacommand-lineprogramthatprovidesdetailed informationaboutthecontentsofaSQLitedatabase.You’llfindinformationon thisprograminthesection“GettingDatabaseFileInformation.” ProbablythebestwaytogetnewversionsofSQLiteand/oritssourceforyourLinuxplatformis fromtherelevantpackagerepositoriesforyourdistribution.RedHat,CentOS,Fedora,andotherRed HatderivativescanuseyumtosearchandfindvariousSQLitepackages.Debian-baseddistributions (includingUbuntu)willhavenotroublegettingup-to-dateversionsofSQLite.SQLite3packagesare availableonlineinbothUbuntuandDebianrepositories,amongothers.UseaptorSynaptictosearch andretrievethepackagesofyourchoice. CompilingSQLitefromSource CompilingSQLitefromsourceonLinux,MacOSX,theBSDflavors,orotherUnixsystemsfollowsvery closelytheMinGW/TakeOffGWinstructionsgivenearlierfortheWindowsplatform(actually,itismore theotherwayaround;MinGWinstallationapesLinuxsourceinstallation!).TobuildSQLiteonthese systems,youneedtoensurethatyouhavetheGNUCompilerCollection(GCC)installed,including Autoconf,Automake,andLibtool.Mostofthesystemsalreadydiscussedincludeallofthesebydefault. Withthissoftwareinplace,youcanbuildSQLitebydoingthefollowing: 31 CHAPTER2■GETTINGSTARTED 1. DownloadtheLinux/UnixSQLitetarball(sourcecode)fromtheSQLitewebsite.Atthetime ofthiswriting,thecurrentversionissqlite-amalgamation-3.6.23.1.tar.gz.Placeitina directory(e.g.,/tmp). 2. Navigatetoyourbuilddirectory: cd /tmp 3. UnpacktheSQLitetarball: tar -xzvf sqlite-amalgamation-3.6.23.1.tar.gz 4. Moveintotheunpackeddirectory: cd sqlite-3.6.23.1 5. Createthemakefile: ./configure 6. Otheroptions,suchastheinstallationdirectory,arealsoavailable.Fora completelistofconfigureoptions,runthis: ./configure --help 7. Buildthesource: make 8. Asroot,install: make install YounowhaveafunctionalSQLiteinstallationonyoursystem.IfyouhaveGNUReadlineinstalled onyousystem,theCLPshouldbecompiledwithReadlinesupport.Testitbyrunningitfromthe commandline: root@linux # sqlite3 ThiswillinvoketheCLPusinganin-memorydatabase.Type.helpforalistofshellcommands. Type.exittoclosetheapplication,orpressCtrl+D. The Command-Line Program TheSQLiteCLPisthemostcommonmeansyoucanusetoworkwithandmanageSQLitedatabases.It operatesthesamewayonallplatforms,solearninghowtouseitensuresyouwillalwayshavea commonandfamiliarwaytomanageyourdatabases.TheCLPisreallytwoprogramsinone.Itcanbe runinshellmodeactingasaninteractivequeryprocessor,oritcanrunfromthecommandlineto performvariousadministrationtasks. 32 CHAPTER2■GETTINGSTARTED TheCLPinShellMode Openashell,andchangedirectoriestosometemporaryfolder—sayC:\TempifyouareonWindowsor /tmpifyou’reinUnix.Ifyou’rehappyworkingfromamorepermanentlocation,youcancreateasqlite directory—e.g.,c:\sqliteunderWindowsor/sqliteforLinuxorUnix.Thiswillbeyourcurrent workingdirectory.Allfilesyoucreateinthecourseofworkingwiththeshellwillbecreatedinthis directory. ■NoteIfyouneedarefresheronhowtogettotheWindowscommandprompt,refertostep5inthe“Gettingthe Command-LineProgram”sectionearlierinthischapter. ToinvoketheCLPasinshellmode,typesqlite3fromacommandline,followedbyanoptional databasename.Ifyoudonotspecifyadatabasename,SQLitewilluseanin-memorydatabase(the contentsofwhichwillbelostwhentheCLPexits). UsingtheCLPasaninteractiveshell,youcanissuequeries,obtainschemainformation,importand exportdata,andperformmanyotherdatabasetasks.TheCLPwillconsideranystatementissuedasa query,exceptforcommandsthatbeginwithaperiod(.).ThesecommandsarereservedforspecificCLP operations,acompletelistofwhichcanbeobtainedbytyping.help,asshownhere: fuzzy@linux:/tmp$ sqlite3 SQLite version 3.6.22 Enter ".help" for instructions Enter SQL statements terminated with a ";" sqlite> .help .backup ?DB? FILE .bail ON|OFF .databases .dump ?TABLE? ... .echo ON|OFF .exit .explain ?ON|OFF? .genfkey ?OPTIONS? .header(s) ON|OFF .help .import FILE TABLE Backup DB (default "main") to FILE Stop after hitting an error. Default OFF List names and files of attached databases Dump the database in an SQL text format If TABLE specified, only dump tables matching LIKE pattern TABLE. Turn command echo on or off Exit this program Turn output mode suitable for EXPLAIN on or off. With no args, it turns EXPLAIN on. Options are: --no-drop: Do not drop old fkey triggers. --ignore-errors: Ignore tables with fkey errors --exec: Execute generated SQL immediately See file tool/genfkey.README in the source distribution for further information. Turn display of headers on or off Show this message Import data from FILE into TABLE 33 CHAPTER2■GETTINGSTARTED .indices ?TABLE? .load FILE ?ENTRY? .mode MODE ?TABLE? .nullvalue STRING .output FILENAME .output stdout .prompt MAIN CONTINUE .quit .read FILENAME .restore ?DB? FILE .schema ?TABLE? .separator STRING .show .tables ?TABLE? .timeout MS .width NUM1 NUM2 ... .timer ON|OFF .width NUM NUM ... Show names of all indices If TABLE specified, only show indices for tables matching LIKE pattern TABLE. Load an extension library Set output mode where MODE is one of: csv Comma-separated values column Left-aligned columns. (See .width) html HTML
code insert SQL insert statements for TABLE line One value per line list Values delimited by .separator string tabs Tab-separated values tcl TCL list elements Print STRING in place of NULL values Send output to FILENAME Send output to the screen Replace the standard prompts Exit this program Execute SQL in FILENAME Restore content of DB (default "main") from FILE Show the CREATE statements If TABLE specified, only show tables matching LIKE pattern TABLE. Change separator used by output mode and .import Show the current values for various settings List names of tables If TABLE specified, only list tables matching LIKE pattern TABLE. Try opening locked tables for MS milliseconds Set column widths for "column" mode Turn the CPU timer measurement on or off Set column widths for "column" mode sqlite>.exit Youcanjustaseasilytype.hforshort.Manyofthecommandscanbesimilarlyabbreviated,suchas .e—shortfor.exit—toexittheshell. TheCLPinCommand-LineMode YoucanusetheCLPfromthecommandlinefortaskssuchasimportingandexportingdata,returning resultsets,andperforminggeneralbatchprocessing.Itisidealforuseinshellscriptsforautomated databaseadministration.ToseewhattheCLPoffersincommand-linemode,invokeitfromtheshell (WindowsorUnix)withthe–helpswitch,asshownhere: 34 CHAPTER2■GETTINGSTARTED fuzzy@linux:/tmp$ sqlite3 -help Usage: sqlite3 [OPTIONS] FILENAME [SQL] FILENAME is the name of an SQLite database. A new database is created if the file does not previously exist. OPTIONS include: -help show this message -init filename read/process named file -echo print commands before execution -[no]header turn headers on or off -bail stop after hitting an error -interactive force interactive I/O -batch force batch I/O -column set output mode to 'column' -csv set output mode to 'csv' -html set output mode to HTML -line set output mode to 'line' -list set output mode to 'list' -separator 'x' set output field separator (|) -nullvalue 'text' set text string for NULL values -version show SQLite version -init filename read/process named file TheCLPincommand-linemodetakesthefollowingarguments: • Alistofoptions(optional) • Adatabasefilename(optional) • ASQLcommandtoexecute(optional) Mostoftheoptionscontroloutputformattingexceptfortheinitswitch,whichspecifiesabatchfile ofSQLcommandstoprocess.Thedatabasefilenameisrequired.TheSQLcommandisoptionalwitha fewcaveats. Database Administration Nowyouthatyou’veseenhowtoinvoketheCLPbothinteractivelyandincommand-linemode,it’stime tolookatsomeexamplesofusingtheCLPforsomecommon,administrativetasks.We’llbeginatthe beginning,withdatabasecreation. CreatingaDatabase Let’sstartbycreatingadatabasethatwewillcalltest.db.Fromthecommandline,opentheCLPinshell modebytypingthefollowing: sqlite3 test.db Eventhoughwehaveprovidedadatabasename,SQLitedoesnotactuallycreatethedatabase(yet) ifitdoesn’talreadyexist.SQLitewilldefercreatingthedatabaseuntilyouactuallycreatesomething insideit,suchasatableorview.Thereasonforthisissothatyouhavetheopportunitytosetvarious 35 CHAPTER2■GETTINGSTARTED permanentdatabasesettings(suchaspagesize)beforethedatabasestructureiscommittedtodisk. Somesettingssuchaspagesizeandcharacterencoding(UTF-8,UTF-16,etc.)cannotbechangedeasily oncethedatabaseiscreated,sothisiswhereyouhaveachancetospecifythem.Wewillgowiththe defaultsettingshere,sotoactuallycreatethedatabaseondisk,weneedonlytocreateatable.Issuethe followingstatementfromtheshell: sqlite> create table test (id integer primary key, value text); Nowyouhaveadatabasefileondiskcalledtest.db,whichcontainsonetablecalledtest.This table,asyoucansee,hastwocolumns: • Aprimarykeycolumncalledid,whichhastheabilitytoautomaticallygenerate valuesbydefault.Whereveryoudefineacolumnoftypeintegerprimarykey, SQLitewillapplyanfunctionforthecolumntocreateandapplymonotonically increasingvalues.Thatis,ifnovalueisprovidedforthecolumninanINSERT statement,SQLitewillautomaticallygenerateonebyfindingthenextinteger valuespecifictothatcolumn. • Asimpletextfieldcalledvalue. Let’saddafewrowstothetable: sqlite> sqlite> sqlite> sqlite> insert insert insert insert into into into into test test test test (id, value) values(1, 'eenie'); (id, value) values(2, 'meenie'); (value) values('miny'); (value) values('mo'); Nowfetchthemback: sqlite> .mode column sqlite> .headers on sqlite> select * from test; id ---------1 2 3 4 36 value ---------eenie meenie miny mo CHAPTER2■GETTINGSTARTED Thetwocommandsprecedingtheselectstatement(.headersand.mode)areusedtoimprovethe formattingalittle(thesecommandsandotherslikethemarecoveredlater).Wecanseethatourexplicit IDvaluesforthefirsttworowswereused.WecanalsoseethatSQLiteprovidedsequentialintegervalues fortheidcolumnforrows3and4,whichwedidnotprovideintheinsertstatements.Whileonthe topicofautoincrementcolumns,youmightbeinterestedtoknowthatthevalueofthelastinserted autoincrementvaluecanbeobtainedusingtheSQLfunctionlast_insert_rowid(): sqlite> select last_insert_rowid(); last_insert_rowid() ------------------4 Beforewequit,let’saddanindexandaviewtothedatabase.Thesewillcomeinhandyinthe examplesthatfollow: sqlite> create index test_idx on test (value); sqlite> create view schema as select * from sqlite_master; Toexittheshell,issuethe.exitcommand: sqlite> .exit OnWindows,youcanalsoterminatetheshellbyusingthekeysequenceCtrl+C.OnUnix,youcan useCtrl+D. GettingDatabaseSchemaInformation Thereareseveralshellcommandsforobtaininginformationaboutthecontentsofadatabase.Youcan retrievealistoftables(andviews)using.tables [pattern],wheretheoptional[pattern]canbeany patternthattheSQLlikeoperatorunderstands(wecoverlikeinChapter3ifyouareunfamiliarwithit). Alltablesandviewsmatchingthegivenpatternwillbereturned.Ifnopatternissupplied,alltablesand viewsarereturned: sqlite> .tables schema test Hereweseeourtablenamedtestandourviewnamedschema.Similarly,indexesforagiventable canbeprintedusing.indices [table name]: 37 CHAPTER2■GETTINGSTARTED sqlite> .indices test test_idx Hereweseetheindexwecreatedearlierontest,calledtest_idx.TheSQLdefinitionordata definitionlanguage(DDL)foratableorviewcanbeobtainedusing.schema [table name].Ifnotable nameisprovided,theSQLdefinitionsofalldatabaseobjects(tables,indexes,views,andtriggers)are returned: sqlite> .schema test CREATE TABLE test (id integer primary key, value text); CREATE INDEX test_idx on test (value); sqlite> .schema CREATE TABLE test (id integer primary key, value text); CREATE VIEW schema as select * from sqlite_master; CREATE INDEX test_idx on test (value); MoredetailedschemainformationcanbehadfromSQLite’sprincipalsystemview,sqlite_master. Thisviewisasimplesystemcatalogofsorts.ItsschemaisdescribedinTable2-1. Table2-1.SQLiteMasterTableSchema Name Description type Theobject’stype(table,index,view,trigger) name Theobject’sname tbl_name Thetabletheobjectisassociatedwith rootpage Theobject’srootpageindexinthedatabase(whereitbegins) sql Theobject’sSQLdefinition(DDL) Querying sqlite_masterforourcurrentdatabasereturnsthefollowing(don’tforgettousethe .mode columnand.headers oncommandsfirsttomanuallysetthecolumnformatandheaders): 38 CHAPTER2■GETTINGSTARTED sqlite> .mode column sqlite> .headers on sqlite> select type, name, tbl_name, sql from sqlite_master order by type; type name tbl_name sql ---------- ---------- ---------- ------------------------------------index test_idx test CREATE INDEX test_idx on test (value) table test test CREATE TABLE test (id integer primary view schema schema CREATE VIEW schema as select * from s Weseeacompleteinventoryoftest.dbobjects:onetable,oneindex,andoneview,eachwiththeir respectiveoriginalDDLcreationstatements. TherearefewadditionalcommandsforobtainingschemainformationthroughSQLite’sPRAGMA commands,table_info,index_info,andindex_list,whicharecoveredinChapter4. ■TipDon’tforgetthatmostcommand-linetoolsliketheSQLiteCLPkeepahistoryofthecommandsthatyou execute.Torerunapreviouscommand,youcanhittheUpArrowkeytoscrollthroughyourpreviouscommands. OnWindows,youcanalsohitF7inanycommandpromptwindowtoseeascrollablelistofthecommandsyou haveentered. ExportingData YoucanexportdatabaseobjectstoSQLformatusingthe.dumpcommand.Withoutanyarguments, .dumpwillexporttheentiredatabaseasaseriesofDDLanddatamanipulationlanguage(DML) commands,suitableforre-creatingthedatabaseobjectsandthedatacontainedtherein.Ifyouprovide arguments,theshellinterpretsthemastablenamesorviews.Anytablesorviewsmatchingthegiven argumentswillbeexported.Thosethatdon’taresimplyignored.Inshellmode,theoutputfromthe .dumpcommandisdirectedtothescreenbydefault.Ifyouwanttoredirectoutputtoafile,usethe .output [filename]command.Thiscommandredirectsalloutputtothefilefilename.Torestoreoutput backtothescreen,simplyissue.output stdout.So,toexportthecurrentdatabasetoafilefile.sql,you woulddothefollowing: sqlite> .output file.sql sqlite> .dump sqlite> .output stdout Thiswillcreatethefilefile.sqlinyourcurrentworkingdirectoryifitdoesnotalreadyexist.Ifafile bythatnamedoesexist,itwillbeoverwritten. BycombiningredirectionwithSQLandthevariousshellformattingoptions(coveredlater),you haveagreatdealofcontroloverexportingdata.Youcanexportspecificsubsetsoftablesandviewsin variousformatsusingthedelimiterofyourchoice,whichcanlaterbeimportedusingthe.import commanddescribednext. 39 CHAPTER2■GETTINGSTARTED ImportingData Therearetwowaystoimportdata,dependingontheformatofthedatainthefiletoimport.Ifthefileis composedofSQL,youcanusethe.readcommandtoexecutethecommandscontainedinthefile.Ifthe filecontainscomma-separatedvalues(CSV)orotherdelimiteddata,youcanusethe.import [file][table]command.Thiscommandwillparsethespecifiedfileandattempttoinsertitintothe specifiedtable.Itdoesthisbyparsingeachlineinthefileusingthepipecharacter(|)asthedelimiter andinsertingtheparsedcolumnsintothetable.Naturally,thenumberofparsedfieldsinthefileshould matchupwiththenumberofcolumnsinthetable.Youcanspecifyadifferentdelimiterusingthe .separatorcommand.Toseethecurrentvaluesetfortheseparator,usethe.showcommand.Thiswill showalluser-definedsettingsfortheshell,amongthemthecurrentdefaultseparator: sqlite> .show echo: explain: headers: mode: nullvalue: output: separator: width: off off on column "" stdout "|" The.readcommandisthewaytoimportfilescreatedbythe.dumpcommand.Usingfile.sql createdearlierasabackup,wecandroptheexistingdatabaseobjects(thetesttableandschemaview) andre-importitasfollows: sqlite> drop table test; sqlite> drop view schema; sqlite> .read file.sql Formatting Theshelloffersanumberofformattingoptionstohelpyouandmakeyourresultsandoutputneatand tidy.Thesimplestare.echo,whichechoesthelastruncommandafterissuingacommand,and.headers, whichincludescolumnnamesforquerieswhensettoon.ThetextrepresentationofNULLcanbesetwith .nullvalue.Forinstance,ifyouwantNULLstoappearasthetextstringNULL,simplyissuethecommand .nullvalue NULL.Bydefault,thispresentationvalueisanemptystring. Theshellpromptcanbechangedusing.prompt [value]: sqlite> .prompt 'sqlite3> ' sqlite3> Resultdatacanbeformattedseveralwaysusingthe.modecommand.Thecurrentoptionsarecsv, column,html,insert,line,list,tabs,andtcl,eachofwhichishelpfulindifferentways.Thedefaultis .list.Forinstance,listmodedisplaysresultswiththecolumnsseparatedbythedefaultseparator.Thus, ifyouwantedtodumpatableinaCSVformat,youcoulddothefollowing: sqlite3> .output file.csv 40 CHAPTER2■GETTINGSTARTED sqlite3> .separator , sqlite3> select * from test; sqlite3> .output stdout Thecontentsoffile.csvnowappearasshownnext. 1,eenie 2,meenie 3,miny 4,mo Actually,sincethereisaCSVmodealreadydefinedintheshell,itisjustaseasytouseitinthis particularexampleinstead: sqlite3> sqlite3> sqlite3> sqlite3> .output file.csv .mode csv select * from test; .output stdout Theresultsobtainedarethesame.ThedifferenceisthatCSVmodewillwrapfieldvalueswith doublequotes,whereaslistmode(thedefault)doesnot. ExportingDelimitedData Combiningthepreviousthreesectionsonexporting,importing,andformattingdata,wenowhavean easywaytoexportandimportdataindelimitedform.Forexample,toexportonlytherowsofthetest tablewhosevaluefieldsstartwiththelettermtoafilecalledtest.csvincomma-separatedvalues,do thefollowing: sqlite> sqlite> sqlite> sqlite> .output text.csv .separator , select * from test where value like 'm%'; .output stdout IfyouwanttothenimportthisCSVdataintoasimilartablewiththesamestructureasthetesttable (callittest2),dothefollowing: sqlite> create table test2(id integer primary key, value text); sqlite> .import text.csv test2 TheCLP,therefore,makesiteasytobothimportandexporttext-delimiteddatatoandfromthe database. PerformingUnattendedMaintenance Sofar,you’veseentheCLPusedinteractivelytoperformtaskssuchascreatingadatabaseandexporting data.However,youdon’talwayswanttobetiedtoyourseat,executingCLPcommandsoneatatime. Instead,youcanusethecommandmodetorunCLPcommandsinbatches.Youcanthenuseyour operatingsystem’sbuilt-inschedulertoschedulethosebatchestorunwheneveryouneedthem. 41 CHAPTER2■GETTINGSTARTED ■NoteYouarefreetoinvoketheCLPfromthecommandlineinteractively.Anytimeyouhaveasequenceof commandsthatyouwanttoinvokeroutinely,it’susefultousethecommand-lineapproach. ThereareactuallytwowaystoinvoketheCLPincommand-linemode.ThefirstistoprovideaSQL command,oraSQLiteshellcommandaswell,suchas.dumpand.schema.AnyvalidSQLorSQLiteshell commandwilldo.SQLitewillexecutethespecifiedcommand,printtheresulttostandardoutput,and exit.Forexample,todumpthetest.dbdatabasefromthecommandline,issuethefollowingcommand: sqlite3 test.db .dump Tomakeituseful,weshouldredirecttheoutputtoafile: sqlite3 test.db .dump > test.sql Thefiletest.sqlnowcontainsthecompletehuman-readablesetofDDLandDMLstatementsfor thedatabasetest.db.Similarly,toselectallrecordsforthetesttable,issuethis: sqlite3 test.db "select * from test" ThesecondwaytoinvoketheCLPincommand-linemodeistoredirectafileasaninputstream. Forinstance,tocreateanewdatabasetest2.dbfromourdatabasedumptest.sql,dothefollowing: sqlite3 test2.db < test.sql TheCLPwillreadthefileasstandardinputandthenprocessandapplyallSQLcommandswithinit tothetest2.dbdatabasefile. Anotherwaytocreateadatabasefromthetest.sqlfileistousetheinitoptionandprovidethe test.sqlasanargument: sqlite3 –init test.sql test3.db TheCLPwillprocesstest.sql,createthetest3.dbdatabase,andthengointoshellmode.Why?The invocationincludednoSQLcommandorinputstream.Togetaroundthis,youneedtoprovideaSQL commandorSQLiteshellcommand.Forexample: sqlite3 –init test.sql test3.db .exit The.exitcommandpromptstheCLPtorunincommand-linemodeanddoesaslittleaspossible. Allthingsconsidered,redirectionisperhapstheeasiestmethodforprocessingfilesfromthecommand line. BackingUpaDatabase Backingupadatabasecanbedoneintwoways,dependingonthetypeofbackupyoudesire.ASQL dumpisperhapsthemostportableformforkeepingbackups.Thestandardwaytogenerateoneisusing 42 CHAPTER2■GETTINGSTARTED theCLP.dumpcommand,asshownintheprevioussection.Fromthecommandline,thisisdoneas follows: sqlite3 test.db .dump > test.sql Withintheshell,youcanredirectoutputtoanexternalfile,issuethecommand,andrestoreoutput tothescreenasfollows: sqlite> sqlite> sqlite> sqlite> .output file.sql .dump .output stdout .exit Likewise,importingadatabaseismosteasilydonebyprovidingtheSQLdumpasaninputstreamto theCLP: sqlite3 test.db < test.sql Thisassumesthattest.dbdoesnotalreadyexist.Ifitdoes,thenthingsmaystillworkifthecontents oftest.sqlaredifferentfromthoseoftest.db.Youwillofcoursegeterrorsiftest.sqlcontainsobjects thatalreadyresidewithintest.dborcontainsdatathatviolatesprimarykeyorforeignkeyconstraints (thoughseethePRAGMAdiscussioninsubsequentchaptersonhowtofinessethisbehavior). Makingabinarybackupofadatabaseislittlemorethanafilecopy.Onesmalloperationyoumay wanttoperformbeforehandisadatabasevacuum,whichwillfreeupanyunusedspacecreatedfrom deletedobjects.Thiswillprovideyouwithasmallerresultingfilefromthebinarycopy: sqlite3 test.db vacuum cp test.db test.backup Asageneralrule,binarybackupsarenotasportableasSQLbackups.Onthewhole,SQLitedoes havegoodbackwardcompatibilityandisbinarycompatibleacrossallplatformsforagivendatabase format.However,forlong-termbackups,itisalwaysagoodideatouseSQLform.Ifsizeisanissue,SQL format(rawtext)usuallyyieldsagoodcompressionratio. ■CautionNomatterhowgoodyouthinkyourchosenbackupapproachis,rememberyouareonlyasgoodas yourlastsuccessfulrestore.Testyourrestoreprocedureifyouneedtorelyonit—otherwise,you’llbe rememberedforonefailedrestore,regardlessofhowmanysuccessfulbackupsyoutook. Finally,ifyou’veworkedwithotherdatabases,“dropping”adatabaseinSQLite,likebinarybackups, isasimplefileoperation:yousimplydeletethedatabasefileyouwanttodrop. 43 CHAPTER2■GETTINGSTARTED GettingDatabaseFileInformation Theprimarymeansbywhichtoobtainlogicaldatabaseinformation,suchastablenames,DDL statements,andsoon,isusingthesqlite_masterview,whichprovidesdetailedinformationaboutall objectscontainedinagivendatabase. Ifyouwantinformationonthephysicaldatabasestructure,youcanuseatoolcalledSQLite Analyzer,whichcanbedownloadedinbinaryformfromtheSQLitewebsite.SQLiteAnalyzerprovides detailedtechnicalinformationabouttheon-diskstructureofaSQLitedatabase.Thisinformation includesadetailedbreakdownofdatabase,table,andindexstatisticsforindividualobjectsandin aggregate.Itprovideseverythingfromdatabasepropertiessuchaspagesize,numberoftables,indexes, filesize,andaveragepagedensity(utilization)todetaileddescriptionsofindividualdatabaseobjects. Followingthereportisadetailedlistofdefinitionsexplainingalltermsusedwithinthereport.Apartial outputofsqlite_analyzerisasfollows: fuzzy@linux:/tmp$ sqlite3_analyzer test.db /** Disk-Space Utilization Report For test.db *** As of 2010-May-07 20:26:23 Page size in bytes.................... Pages in the whole file (measured).... Pages in the whole file (calculated).. Pages that store data................. Pages on the freelist (per header).... Pages on the freelist (calculated).... Pages of auto-vacuum overhead......... Number of tables in the database...... Number of indices..................... Number of named indices............... Automatically generated indices....... Size of the file in bytes............. Bytes of user payload stored.......... 1024 3 3 3 0 0 0 2 1 1 0 3072 26 100.0% 0.0% 0.0% 0.0% 0.85% *** Page counts for all tables with their indices ******************** TEST.................................. 2 SQLITE_MASTER......................... 1 66.7% 33.3% *** All tables and indices ******************************************* Percentage of total database.......... Number of entries..................... Bytes of storage consumed............. Bytes of payload...................... Average payload per entry............. Average unused bytes per entry........ Maximum payload per entry............. Entries that use overflow............. Primary pages used.................... Overflow pages used................... 44 100.0% 11 3072 235 21.36 243.00 72 0 3 0 7.6% 0.0% CHAPTER2■GETTINGSTARTED Total pages used...................... Unused bytes on primary pages......... Unused bytes on overflow pages........ Unused bytes on all pages............. 3 2673 0 2673 87.0% 87.0% *** Table TEST and all its indices *********************************** Percentage of total database.......... Number of entries..................... Bytes of storage consumed............. Bytes of payload...................... Average payload per entry............. Average unused bytes per entry........ Maximum payload per entry............. Entries that use overflow............. Primary pages used.................... Overflow pages used................... Total pages used...................... Unused bytes on primary pages......... Unused bytes on overflow pages........ Unused bytes on all pages............. 66.7% 8 2048 60 7.50 243.00 10 0 2 0 2 1944 0 1944 2.9% 0.0% 94.9% 94.9% SQLiteAnalyzerisprovidedinbinaryformontheSQLitewebsiteforLinux,MacOSX,and Windows.SQLiteAnalyzercanbebuiltfromthesourceusingtheUnixmakefileprovided.Fromthe builddirectory,issuethefollowingcommand: make sqlite3_analyzer Youmust,however,haveTclsupportconfiguredinthebuildsettingsbecauseSQLiteAnalyzeruses theTclextensiontoperformmostofitswork.Referto“CompilingSQLitefromSource”formore information. Other SQLite Tools TherearemanyotheropensourceandcommercialprogramsavailablewithwhichtoworkwithSQLite. Goodgraphical,cross-platformtoolsincludethefollowing: SQLiteDatabaseBrowser(http://sqlitebrowser.sourceforge.net):Allows userstomanagedatabases,tables,andindexes,aswellasimportandexport them.UserscaninteractivelyrunSQLqueriesandinspecttheresults,aswellas examinealogofallSQLcommandsissued.Itrecentlyreceivedamajorupgrade toversion2. SQLiteman(http://www.sqliteman.com):Across-platformprogramthat’s targetedatpeoplemanagingandadministeringSQLitedatabases.Itallowsfor generalmanagementofdatabases,tables,indexes,andtriggers,aswellasother commonmanagementtasks. 45 CHAPTER2■GETTINGSTARTED SQLiteManager(www.sqlabs.net/sqlitemanager.php):Acommercialsoftware packagedesignedforworkingwithandadministeringSQLite.Userscan managedatabaseobjects,executequeries,andsaveSQL,aswellascreate reportswithflexiblereporttemplates.Itincludesitsownhigh-levelscripting languagetocomplementitsSQLcapabilities. Thesearejustthecross-platformtools.Manymoretoolsareavailablethatcanbeusedwithjust aboutanyprogramming,end-user,ormanagementenvironment.Youcanfindmoreinformationon suchpackagesontheSQLitewiki(www.sqlite.org/cvstrac/wiki?p=ManagementTools). Summary Nomatterwhatplatformyouworkon,SQLiteiseasytoinstallandbuild.Windows,MacOSX,andLinux userscanobtainbinariesdirectlyfromtheSQLitewebsite.Usersofmanyotheroperatingsystemscan alsoobtainbinariesusingtheirnative—oreventhird-party—packagesystems. ThecommonwaytoworkwithSQLiteacrossallplatformsisusingtheSQLitecommand-line program(CLP).Thisprogramoperatesasbothacommand-linetoolandaninteractiveshell.Youcan issuequeriesanddoessentialdatabaseadministrationtaskssuchascreatingtables,indexes,andviews aswellasexportingandimportingdata.SQLitedatabasesarecontainedinsingleoperatingsystemfiles, sodoingthingslikebackupsareverysimple—justcopythefile.Forlong-termbackups,however,itis alwaysbesttodumpthedatabaseinSQLformat,becausethisisportableacrossSQLiteversions. Inthenextfewchapters,youwillbeusingtheCLPtoexploreSQLandthedatabaseaspectsof SQLite.WewillstartwiththebasicsofusingSQLwithSQLiteinChapter3andmovetomoreadvanced SQLinChapter4. 46 CHAPTER 3 ■■■ SQL for SQLite ThischapterisanintroductiontousingSQLwithSQLite.SQLmakesupahugecomponentofany discussionaboutdatabases,andSQLiteisnodifferent.Whetheryou’reanoviceorprowithSQL,this chapterofferscomprehensivecoverage.Evenifyou’veneverusedSQLbefore,youshouldhaveno troublewiththematerialcoveredinthischapter.Ifyou’vealsoavoidedtherelationalmodelthat underpinsSQLiteandotherRDBMSs,don’tfret.We’llaugmentourdiscussionofSQLwithjustenough oftherelationalconceptstomakethingsclear,withoutgettingboggeddowninthetheory. SQListhesole(andalmostuniversal)meansbywhichtocommunicatewitharelationaldatabase.It istheworkhorsedevotedtoinformationprocessing.Itisdesignedforstructuring,reading,writing, sorting,filtering,protecting,calculating,generating,grouping,aggregating,andingeneralmanaging information. SQLisanintuitive,user-friendlylanguage.Itcanbefuntouseandisquitepowerful.Oneofthefun thingsaboutSQListhatregardlessofwhetheryouareanexpertoranovice,itseemsthatyoucanalways continuetolearnnewwaysofdoingthings(forbetterorworse). ThegoalofthischapteristoteachyoutouseSQLwell—toexposeyoutogoodtechniquesand perhapsafewcheaptricksalongtheway.Asyoucanalreadytellfromthetableofcontents,SQLfor SQLiteissuchalargetopicthatwe’vesplititsdiscussionintotwohalves.Wecoverthecoreselect statementfirstandthenmoveontootherSQLstatementsinChapter4.Butbythetimeyouaredone, youshouldbewellequippedtoputadentinanydatabase. ■NoteEvenwithtwochapters,wereallyonlyhavespacetofocusonSQL’suseinSQLite.Foramuchwiderand in-depthcoverageofSQLingeneral,werecommendabooklikeBeginningSQLQueriesbyClaireChurcher. The Example Database Beforedivingintosyntax,let’sgetsituatedwiththeobligatoryexampledatabase.Thedatabaseusedin thischapter(andtherestofthisbook,forthatmatter)consistsofallthefoodsineveryepisodeof Seinfeld.Ifyou’veeverwatchedSeinfeld,youcan’thelpbutnoticeaslightpreoccupationwithfood. Therearemorethan400differentfoodsmentionedinthe180episodesofitshistory(accordingtofan dataspreadfarandwideontheInternet).That’smorethantwonewfoodseveryshow.Subtract commercialtime,andthat’svirtuallyanewfoodintroducedevery10minutes. 47 CHAPTER3■SQLFORSQLITE Asitturnsout,thispreoccupationwithfoodworksoutnicelybecauseitmakesforadatabasethat illustratesalltherequisiteconceptsofSQLandofusingSQLinSQLite.Figure3-1showsthedatabase tablesforoursampledatabase. foods +id: integer +name: text foods_episodes episodes food_types +id: integer +type_id: integer +name: text +food_id: integer +episode_id: integer +id: integer +name: text Figure3-1.TheSeinfeldfooddatabase Thedatabaseschema,asdefinedinSQLite,isdefinedasfollows: create table episodes ( id integer primary key, season int, name text ); create table foods( id integer primary key, type_id integer, name text ); create table food_types( id integer primary key, name text ); create table foods_episodes( food_id integer, episode_id integer ); Themaintableisfoods.Eachrowinfoodscorrespondstoadistinctfooditem,thenameofwhichis storedinthenameattribute.Thetype_idattributereferencesthefood_typestable,whichstoresthe variousfoodclassifications(e.g.,bakedgoods,drinks,orjunkfood).Finally,thefoods_episodestable linksfoodsinfoodswiththeepisodesinepisodes. Installation Thefooddatabaseislocatedintheexampleszipfileaccompanyingthisbook.Itisavailableonthe Apresswebsite(www.apress.com)intheSourceCodesection.Tocreatethedatabase,firstlocatethe foods.sqlfileintherootdirectoryoftheunpackedzipfile.Tocreateanewdatabasefromscratchfrom thecommandline,navigatetotheexamplesdirectory,andrunthefollowingcommand: sqlite3 foods.db < foods.sql 48 CHAPTER3■SQLFORSQLITE Thiswillcreateadatabasefilecalledfoods.db.IfyouarenotfamiliarwithhowtousetheSQLite command-lineprogram,refertoChapter2. RunningtheExamples Foryourconvenience,alltheSQLexamplesinthechapterareavailableinthefilesql.sqlintheroot directoryoftheexampleszipfile.Soinsteadoftypingthembyhand,simplyopenthefileandlocatethe SQLyouwanttotry. Aconvenientwaytorunthelongerqueriesinthischapteristocopythemintoyourfavoriteeditor andsavetheminaseparatefile,whichyoucanrunfromthecommandline.Forexample,copyalong queryintest.sqltotry.Yousimplyusethesamemethodtorunitasyoudidtocreateyourdatabase earlier: sqlite3 foods.db < test.sql Theresultswillbeprintedtothescreen.Thisalsomakesiteasiertoexperimentwiththesequeries withouthavingtoretypethemoreditthemfrominsidetheSQLiteshell.Youjustmakeyourchangesin theeditor,savethefile,andrerunthecommandline. Formaximumreadabilityoftheoutput,youmaywanttoputthefollowingcommandsatthe beginningofthefile: .echo on .mode column .headers on .nullvalue NULL Thiscausesthecommand-lineprogramto1)echotheSQLasitisexecuted,2)printresultsin columnmode,3)includethecolumnheaders,and4)printnullsasNULL.Theoutputofallexamplesin thischapterisformattedwiththesespecificsettings.Anotheroptionyoumaywanttosetforvarious examplesisthe.widthoption,whichsetstherespectivecolumnwidthsoftheoutput.Thesevaryfrom exampletoexample. Forbetterreadability,theexamplesarepresentedintwodifferentformats.Forshortqueries,we’ll showtheSQLandoutputasitwouldbeshownfromwithintheSQLiteshell.Forexample: sqlite> ...> ...> ...> select * from foods where name='JujyFruit' and type_id=9; id ---------244 type_id ---------9 name ---------JujyFruit Occasionally,asinthepreviousexample,wetakethelibertyofaddinganextralinebetweenthe commandanditsoutputtoimprovereadabilityhereontheprintedpage.Forlongerqueries,weshow justtheSQLincodeformatseparatedfromtheresultsbygraylines,asinthefollowingexample: 49 CHAPTER3■SQLFORSQLITE select f.name name, types.name type from foods f inner join ( select * from food_types where id=6) types on f.type_id=types.id; name ------------------------Generic (as a meal) Good Dip Guacamole Dip Hummus type ----Dip Dip Dip Dip Syntax SQL’sdeclarativesyntaxreadsalotlikeanaturallanguage.Statementsareexpressedintheimperative mood,beginningwiththeverbdescribingtheaction.Followingitarethesubjectandpredicate,as illustratedinFigure3-2. select id from foods where name= JujyFruit ; verb subject predicate Figure3-2.GeneralSQLsyntaxstructure Asyoucansee,itreadslikeanormalsentence.SQLwasdesignedspecificallywithnontechnical peopleinmindandwasthusmeanttobeverysimpleandeasytounderstand. PartofSQL’seaseofusecomesfromitsbeing(forthemostpart)adeclarativelanguage,asopposed toanimperativelanguagesuchasCorPerl.Adeclarativelanguageisoneinwhichyoudescribewhat youwant,whereasanimperativelanguageisoneinwhichyouspecifyhowtogetit.Forexample, considertheprocessoforderingacheeseburger.Asacustomer,youuseadeclarativelanguageto articulateyourorder.Thatis,yousimplydeclaretothepersonbehindthecounterwhatyouwant: GivemeadoublemeatWhataburgerwithjalapeñosandcheese,holdthemayo. 50 CHAPTER3■SQLFORSQLITE Theorderispassedbacktothechefwhofulfillstheorderusingaprogramwritteninanimperative language—therecipe.Hefollowsaseriesofwell-definedstepsthatmustbeexecutedinaspecificorder tocreatethecheeseburgerperyour(declarative)specifications: 1. Getgroundbeeffromthethirdrefrigeratorontheleft. 2. Makeapatty. 3. Cookforthreeminutes. 4. Flip. 5. Cookthreemoreminutes. 6. Repeatsteps1–5forsecondpatty. 7. Addmustardtotopbun. 8. Addpattiestobottombun. 9. Addcheese,lettuce,tomatoes,onions,andjalapeñostoburger. 10. Combinetopandbottombuns,andwrapinyellowpaper. Asyoucansee,declarativelanguagestendtobemoresuccinctthanimperativeones.Inthis example,ittookthedeclarativeburgerlanguage(DBL)onesteptomaterializethecheeseburger,whileit tooktheimperativecheflanguage(ICL)10steps.Declarativelanguagesdomorewithless.Infact,SQL’s easeofuseisnotfarfromthisexample.AsuitableSQLequivalenttoourimaginaryDBLstatement shownearliermightbesomethingalongthelinesofthis: select burger from kitchen where patties=2 and toppings='jalopenos' and condiment != 'mayo' limit 1; Prettysimple.Aswe’vementioned,SQLwasdesignedtobeauser-friendlylanguage.Intheearly days,SQLwastargetedspecificallyforendusersfortaskssuchasadhocqueriesandreportgeneration (unliketodaywhereitisalmostexclusivelythedomainofdevelopersanddatabaseadministrators). Commands SQLismadeupofcommands.Commandsaretypicallyterminatedbyasemicolon,whichmarkstheend ofthecommand.Forexample,thefollowingarethreedistinctcommands: select id, name from foods; insert into foods values (null, 'Whataburger'); delete from foods where id=413; 51 CHAPTER3■SQLFORSQLITE ■NoteThesemicolonisusedbySQLiteasacommandterminator,signalingtheendofthecommandtobe processed.Commandterminatorsaremostcommonlyassociatedwithinteractiveprogramsdesignedforletting usersexecutequeriesagainstadatabase.ThesemicolonisacommonSQLcommandterminatoracrossmany systems,thoughsomeuse\goreventhewordgo. Commands,inturn,arecomposedofaseriesoftokens.Tokenscanbeliterals,keywords,identifiers, expressions,orspecialcharacters.Tokensareseparatedbywhitespace,suchasspaces,tabs,and newlines. Literals Literals,alsocalledconstants,denoteexplicitvalues.Therearethreekinds:stringliterals,numeric literals,andbinaryliterals.Stringliteralsareoneormorealphanumericcharacterssurroundedbysingle quotes.Herearesomeexamples: 'Jerry' 'Newman' 'JujyFruit' AlthoughSQLitesupportsdelimitingstringvalueswithsingleordoublequotes,westronglysuggest youonlyusesinglequotes.ThisistheSQLstandardandwillsaveyoumanyhoursofgriefshouldyou encounterasystemthatstrictlyenforcesthis.Ifsinglequotesarepartofthestringvalue,theymustbe representedastwosuccessivesinglequotes.Forexample,Kenny’schickenwouldbeexpressedas follows: 'Kenny''s chicken' Numericliteralsarerepresentedininteger,decimal,orscientificnotation.Herearesomeexamples: -1 3.142 6.0221415E23 Binaryvaluesarerepresentedusingthenotationx'0000',whereeachdigitisahexadecimalvalue. Binaryvaluesmustbeexpressedinmultiplesof2hexadecimalvalues(8bits).Herearesomeexamples: x'01' X'0fff' x'0F0EFF' X'0f0effab' 52 CHAPTER3■SQLFORSQLITE KeywordsandIdentifiers KeywordsarewordsthathaveaspecificmeaninginSQL.Theseincludewordssuchasselect,update, insert,create,drop,andbegin.Identifiersrefertospecificobjectswithinthedatabase,suchastablesor indexes.Keywordsarereservedwordsandmaynotbeusedasidentifiers.SQLiscaseinsensitivewith respecttokeywordsandidentifiers.Thefollowingareequivalentstatements: SELECT * from foo; SeLeCt * FrOm FOO; Bydefault,stringliteralvaluesarecasesensitiveinSQLite,sothevalue'Mike'isnotthesameasthe value'mike'. Comments CommentsinSQLitearedenotedbytwoconsecutivehyphens(--),whichcommenttheremainingline, orbythemultilineC-stylenotation(/* */),whichcanspanmultiplelines.Here’sanexample: -- This is a comment on one line /* This is a comment spanning two lines */ Again,unlessyouhaveastrongreasontouseC-stylenotation,we’drecommendstickingwiththe SQLstandardoftwoconsecutivehyphensinyourSQLscriptsforSQLite. Creating a Database TablesarethenaturalstartingpointtokickoffyourexplorationofSQLinSQLite.Thetableisthe standardunitofinformationinarelationaldatabase.Everythingrevolvesaroundtables.Tablesare composedofrowsandcolumns.Andalthoughthatsoundssimple,tablesbringalongwiththemall kindsofotherconcepts,whichcan’tbenicelysummarizedinafewtidyparagraphs.Infact,ittakes almostthewholechapter.So,whatwearegoingtodohereisthetwo-minuteoverviewoftables—just enoughforyoutocreateasimpletableandgetridofitifyouwantto.Andoncewehavethatoutofthe way,alltheotherpartsofthischapterwillhavesomethingtobuildon. CreatingTables Liketherelationalmodel,SQLconsistsofseveralparts.Ithasastructuralpart,forexample,whichis designedtocreateanddestroydatabaseobjects.Thispartofthelanguageisgenerallyreferredtoasa datadefinitionlanguage(DDL).Similarly,ithasafunctionalpartforperformingoperationsonthose objects(suchasretrievingandmanipulatingdata).Thispartofthelanguageisreferredtoasadata manipulationlanguage(DML).CreatingtablesfallsunderDDL,thestructuralpart. Youcreateatablewiththecreate tablecommand,whichisdefinedasfollows: create [temp] table table_name (column_definitions [, constraints]); 53 CHAPTER3■SQLFORSQLITE Thetemportemporarykeywordcreatesatemporarytable.Thiskindoftableis,well,temporary—it willlastonlyaslongyoursession.Assoonasyoudisconnect,itwillbedestroyed(ifyouhaven’talready destroyeditmanually).Thebracketsaroundthetempdenotethatitisanoptionalpartofthecommand. Wheneveryouseeanysyntaxinbrackets,itmeansthatthecontentswithinthemareoptional. Furthermore,thepipesymbol(|)denotesanalternative(thinkofthewordor).Take,forexample,the followingsyntax: create [temp|temporary] table … ; Thismeansthateitherthetemportemporarykeywordmaybeoptionallyused.Youcouldsaycreate temp table foo…,oryoucouldsaycreate temporary table foo….Inthiscase,theymeanthesamething. Ifyoudon’tcreateatemporarytable,thencreate tablecreatesabasetable.Thetermbasetable referstoatablethatisanamed,persistenttableinthedatabase.Thisisthemostcommonkindoftable. Ingeneral,thetermbasetableisusedtodifferentiatetablescreatedbycreate tablefromsystemtables andothertable-likeobjectssuchasviews. Theminimumrequiredinformationforcreate tableisatablenameandacolumnname.The nameofthetable,givenbytable_name,mustbeuniqueamongallotheridentifiers.Inthebody, column_definitionsconsistsofacomma-separatedlistofcolumndefinitionscomposedofaname,a domain,andacomma-separatedlistofcolumnconstraints.Atype,sometimesreferredtoasadomain, issynonymouswithadatatypeinaprogramminglanguage.Itdenotesthetypeofinformationthatis storedinthecolumn. TherearefivenativetypesinSQLite:integer,real,text,blob,andnull.Allofthesetypesare coveredinthesectioncalled“StorageClasses”laterinthischapter.Constraintsareconstructsthat controlwhatkindofvaluescanbeplacedinthetableorinindividualcolumns.Forinstance,youcan ensurethatonlyuniquevaluesareplacedinacolumnbyusingauniqueconstraint.Constraintsare coveredinthesection“DataIntegrity.” Thecreate tablecommandallowsyoutoincludealistofadditionalcolumnconstraintsattheend ofthecommand,denotedbyconstraintsinthesyntaxoutlinedearlier.Considerthefollowingexample: create table contacts ( id integer primary key, name text not null collate nocase, phone text not null default 'UNKNOWN', unique (name,phone) ); Columnidisdeclaredtohavetypeintegerandconstraintprimary key.Asitturnsout,the combinationofthistypeandconstrainthasaspecialmeaninginSQLite.Integer primary keybasically turnsthecolumnintoanautoincrementcolumn(asexplainedinthesection“PrimaryKeyConstraints” laterinthischapter).Columnnameisdeclaredtobeoftypetextandhastwoconstraints:not nulland collate nocase.Columnphoneisoftypetextandhastwoconstraintsdefinedaswell.Afterthat,thereis atable-levelconstraintofunique,whichisdefinedforcolumnsnameandphonetogether. Thisisalotofinformationtoabsorballatonce,butitwillallbeexplainedinduecourse.Youcan probablyappreciateourpreamblethatwarnedyouhowcomplextablescouldbecome.Theonly importantthinghere,however,isthatyouunderstandthegeneralformatofthecreate tablestatement. AlteringTables Youcanchangepartsofatablewiththealter tablecommand.SQLite’sversionofalter tablecan eitherrenameatableoraddcolumns.Thegeneralformofthecommandisasfollows: alter table table { rename to name | add column column_def } 54 CHAPTER3■SQLFORSQLITE Notethatthereissomenewnotationhere:{}.Bracesenclosealistofoptions,whereoneoptionis required.Inthiscase,wehavetouseeitheralter table table rename…or altertable table add column….Thatis,youcaneitherrenamethetableusingtherenameclauseoraddacolumnwiththeadd columnclause.Torenameatable,yousimplyprovidethenewnamegivenbyname. Ifyouaddacolumn,thecolumndefinition,denotedbycolumn_def,followstheforminthecreate tablestatement.Itisaname,followedbyanoptionaldomainandlistofconstraints.Here’sanexample: sqlite> alter table contacts add column email text not null default '' collate nocase; sqlite> .schema contacts create table contacts ( id integer primary key, name text not null collate nocase, phone text not null default 'UNKNOWN', email text not null default '' collate nocase, unique (name,phone) ); ToviewthetabledefinitionfromwithintheSQLitecommand-lineprogram,usethe.schemashell commandfollowedbythetablename.Itwillprintthecurrenttabledefinition.Ifyoudon’tprovidea tablename,then.schemawillprinttheentiredatabaseschema. Tablescanalsobecreatedfromtheresultsofselectstatements,allowingyoutocreatenotonlythe structurebutalsothedataatthesametime.Thisparticularuseofthecreate tablestatementiscovered laterinthesection“InsertingRecords.” Querying the Database Theeffortspentdesigningyourdatabaseandcreatingyourtablesallfocusesononepurpose:usingyour data.WorkingwithyourdataisthejobofSQL’sDML.ThecoreofDMListheselectcommand,which hastheuniquehonorofbeingthesolecommandforqueryingthedatabase.selectisbyfarthelargest andmostcomplexcommandinSQL.selectderivesmanyofitsoperationsfromrelationalalgebraand encompassesalargeportionofit.Thecapabilitiesandcomplexitiesoftheselectstatementarevast, eveninastreamlinedefficientenvironmentlikeSQLite.Don’tletthatputyouoff.SQLite’sapproachto theselectcommandisverylogical,andithasafirmgroundingintheunderlyingrelationaltheorythat underpinsallRDBMS. RelationalOperations Forthetheoreticallyminded,it’susefultothinkaboutwhatselectdoesandwhyitdoesit,framedina conceptualway.InmostSQLimplementations,includingSQLite’s,theselectstatementprovidesfor the“relationaloperations”thatsource,mix,compare,andfilterdata.Theserelationaloperationsare typicallydividedintothreecategories: • Fundamentaloperations • Restriction • Projection • Cartesianproduct 55 CHAPTER3■SQLFORSQLITE • • • Union • Difference • Rename Additionaloperations • Intersection • Naturaljoin • Assign Extendedoperations • Generalizedprojection • Leftouterjoin • Rightouterjoin • Fullouterjoin Thefundamentaloperationsarejustthat:fundamental.Theydefinethebasicrelationaloperations, andallofthem(withtheexceptionofrename)havetheirbasisinsettheory.Theadditionaloperations areforconvenience,offeringashorthandwayofperformingfrequentlyusedcombinationsofthe fundamentaloperations.Forinstance,intersectioncanbeperformedbytakingtheunionoftwosets andfromthatremovingviadifferencetheresultsoftwofurtherunionsthathaveeachhaddifference appliedforoneofthetwoinitialsets.Finally,theextendedoperationsaddfeaturestothefundamental andadditionaloperations.Forexample,thegeneralizedprojectionoperationaddsarithmetic expressions,aggregates,andgroupingfeaturestothefundamentalprojectionoperations.Theouter joinsextendthejoinoperationsandallowadditionalinformationand/orincompleteinformationtobe retrievedfromthedatabase. InstandardANSISQL,selectcanperformeveryoneoftheserelationaloperations.These operationsmaptotheoriginalrelationaloperatorsdefinedbyE.F.Coddinhisoriginalworkon relationaltheory(withtheexceptionofdivide).SQLitesupportsalltherelationaloperationsinANSI SQLwiththeexceptionofrightandfullouterjoins.Thetypesofjoinscanbeconstructedusing combinationsofotherfundamentalrelationaloperations,sodon’tfrettheirabsence. Alloftheseoperationsaredefinedintermsofrelationsor,astheyarecommonlycalled,tables!They takeoneormorerelationsastheirinputsandproducearelationastheiroutput.Thisallowsoperations tobestrungtogetherintorelationalexpressions.Relationalexpressionscanthereforebecreatedto arbitrarycomplexity.Forexample,theoutputofaselectoperation(arelation)canbefedastheinputto anotherselectstatement,asfollows: select name from (select name, type_id from (select * from foods)); Here,theoutputoftheinnermostselectisfedtothenextselect,whoseoutputisinturnfedtothe outermostselect.Itisallasinglerelationalexpression.Anyonefamiliarwithpipingcommandsin Linux,Unix,orWindowswillappreciatethisbehavior.Theoutputofanyselectstatementcanbeused asinputtoyetanotherstatement. 56 CHAPTER3■SQLFORSQLITE selectandtheOperationalPipeline Theselectcommandincorporatesmanyoftherelationaloperationsthroughaseriesofclausesinits syntax.Eachclausecorrespondstospecificrelationaloperation.InSQLite,almostalloftheclausesare optional,infact,toadegreebeyondwhatstandardSQLsuggestsisdesirable.AsauserofSQLinSQLite, thisempowersyoutoemployonlytheoperationsyouneedtoobtainthedatayouseek. AverygeneralformofselectinSQLite(withouttoomuchdistractingsyntax)canberepresentedas follows: select [distinct] heading from tables where predicate group by columns having predicate order by columns limit count,offset; Eachkeyword—from,where,having,andsoon—isaseparateclause.Eachclauseconsistsofthe keywordfollowedbyarguments(representedinitalics).Fromhereonout,wewillrefertotheseclauses simplybyname,andyou’llbeabletorecognizeourusebythefixed-widthfont.So,ratherthan“the whereclause,”wewillsimplyusewhere. InSQLite,thebestwaytothinkoftheselectcommandisasapipelinethatprocessesrelations.This pipelinehasoptionalprocessesthatyoucanplugintoitasyouneedthem.Regardlessofwhetheryou includeorexcludeaparticularoperation,therelativeoperationsarealwaysthesame.Figure3-3shows thisorder. Theselectcommandstartswithfrom,whichtakesoneormoreinputrelations;combinestheminto asinglecompositerelation;andpassesitthroughthesubsequentchainofoperations. R6 Result R4 R2 SELECT DISTINCT heading FROM tables WHERE predicate GROUP BY columns HAVING predicate ORDER BY columns LIMIT int,int; R3 R5 R7 R1 Figure3-3.ThephasesofselectinSQLite Allclausesareoptionalwiththeexceptionofselect.Youmustalwaysprovideatleastthisclauseto makeavalidselectcommand.Byfarthemostcommoninvocationoftheselectcommandconsistsof threeclauses:select,from,andwhere.Thisbasicsyntaxanditsassociatedclausesareasfollows: select heading from tables where predicate; 57 CHAPTER3■SQLFORSQLITE Thefromclauseisacomma-separatedlistofoneormoretables,views,andsoon(representedby thevariabletablesinFigure3-3).Ifmorethanonetableisspecified,theywillbecombinedtoforma singlerelation(representedbyR1inFigure3-3).Thisisdonebyoneofthejoinoperations.Theresulting relationproducedbyfromservesastheinitialmaterial.Allsubsequentoperationswilleitherwork directlyfromitorworkfromderivativesofit. ThewhereclausefiltersrowsinR1.Theargumentofwhereisapredicate,orlogicalexpression,which definestheselectioncriteriabywhichrowsinR1areincludedin(orexcludedfrom)theresult.The selectedrowsfromthewhereclauseformanewrelationR2,asshowninFigure3-3above. Inthisparticularexample,R2passesthroughtheotheroperationsunscatheduntilitreachesthe selectclause.TheselectclausefiltersthecolumnsinR2,asdepictedinFigure3-4.Itsargument consistsofacomma-separatedlistofcolumnsorexpressionsthatdefinetheresult.Thisiscalledthe projectionlist,orheadingoftheresult. 1 2 3 1 2 3 Figure3-4.Projection Here’saconcreteexampleusingourexampledatabase: sqlite> select id, name from food_types; id name ---------- ---------1 Bakery 2 Cereal 3 Chicken/Fowl 4 Condiments 5 Dairy 6 Dip 7 Drinks 8 Fruit 9 Junkfood 10 Meat 11 Rice/Pasta 12 Sandwiches 13 Seafood 14 Soup 15 Vegetables Thereisnowhereclausetofilterrows,soallrowsinthetablefood_typesarereturned.Theselect clausespecifiesallthecolumnsinfood_types,andthefromclausedoesnotjointables.Theresultisan exactcopyoffood_types.AsinmostSQLimplementations,SQLitesupportsanasterisk(*)asshorthand tomeanallcolumns.Thus,thepreviousexamplecanjustaseasilybeexpressedasfollows: select * from food_types; 58 CHAPTER3■SQLFORSQLITE Insummary,SQLite’sbasicselectprocessinggathersalldatatobeconsideredinthefromclause, filtersrows(restricts)inthewhereclause,andfilterscolumns(projects)intheselectclause.Figure3-5 showsthisprocess. a b c d a c b WHERE clause FROM clause a d c d SELECT clause Projection Restriction R2 Result R1 Figure3-5.Restrictionandprojectioninselect Withthissimpleexample,youcanbegintoseehowaquerylanguageingeneralandSQLin particularultimatelyoperateintermsofrelationaloperations.Thereisrealmathunderthehood. Filtering IftheselectcommandisthemostcomplexcommandinSQL,thenthewhereclauseisthemostcomplex clauseinselect.Butitalsodoesmostofthework.Havingasolidunderstandingofitsmechanicswill mostlikelybringthebestoverallreturnsinyourday-to-dayuseofSQLinSQLite. SQLiteappliesthewhereclausetoeachrowoftherelationproducedbythefromclause(R1).As statedearlier,where—arestriction—isafilter.Theargumentofwhereisalogicalpredicate.Apredicate, inthesimplestsense,isjustanassertionaboutsomething.Considerthefollowingstatement: Thedog(subject)ispurpleandhasatoothygrin(predicate). Thedogisthesubject,andthepredicateconsistsofthetwoassertions(colorispurpleandgrinis toothy).Thisstatementmaybetrueorfalse,dependingonthedog. Thesubjectinthewhereclauseisarow.Therowisthelogicalsubject.TheWHEREclauseisthelogical predicate.Eachrowinwhichthepropositionevaluatestotrueisincluded(orselected)aspartofthe result(R2).Eachrowinwhichitisfalseisexcluded.So,thedogpropositiontranslatedintoarelational equivalentwouldlooksomethinglikethis: select * from dogs where color='purple' and grin='toothy'; Thedatabasewilltakeeachrowintabledogs(thesubject)andapplythewhereclause(thepredicate) toformthelogicalproposition: This row has color='purple' and grin='toothy'. Ifitistrue,thentherow(ordog)isindeedpurpleandtoothy,anditisincludedintheresult.whereis apowerfulfilter.Itprovidesyouwithagreatdegreeofcontrolovertheconditionswithwhichtoinclude (orexclude)rowsin(orfrom)theresult. 59 CHAPTER3■SQLFORSQLITE Values Valuesrepresentsomekindofdataintherealworld.Valuescanbeclassifiedbytheirtype,suchasa numericalvalue(1,2,3,andsoon)orstringvalue(“JujyFruit”).Valuescanbeexpressedasliteralvalues (anexplicitquantitysuchas1,2,3or“JujyFruit”),variables(oftenintheformofcolumnnameslike foods.name),expressions(3+2/5),ortheresultsoffunctions(count(foods.name))—whicharecovered later. Operators Anoperatortakesoneormorevaluesasinputandproducesavalueasoutput.Anoperatorissonamed becauseitperformssomekindofoperation,producingsomekindofresult.Binaryoperatorsare operatorsthattaketwoinputvalues(oroperands).Ternaryoperatorstakethreeoperands,unary operatorstakejustone,andsoon. Operatorscanbestrungtogether,feedingtheoutputofoneoperatorintotheinputofanother (Figure3-6),formingvalueexpressions. unary binary ternary Figure3-6.Unary,binary,andternaryoperators,alsodisplayingpipeliningofoperations Bystringingoperatorstogether,youcancreatevalueexpressionsthatareexpressedintermsofyet othervalueexpressionstoarbitrarycomplexity.Here’sanexample: x = count(episodes.name) y = count(foods.name) z = y/x * 11 Binary Operators BinaryoperatorsarebyfarthemostcommonofalloperatorsinSQL.Table3-1liststhebinaryoperators supportedinSQLitebyprecedence,fromhighesttolowest.Operatorsineachcolorgrouphaveequal precedence. 60 CHAPTER3■SQLFORSQLITE Table3-1.BinaryOperators Operator Type Action || StringConcatenation * ArithmeticMultiply / ArithmeticDivi % ArithmeticModul + Arithmetic – ArithmeticSubtra > BitwiseLeft & Logical | LogicalOr = Relational = RelationalEqua lto == RelationalEqua lto RelationalNot equalto != RelationalNot equalto IN LogicalIn AND Logical OR LogicalOr de us Add ct shift shift And sthan Lessthanorequalto terthan Greaterthanorequalto And 61 CHAPTER3■SQLFORSQLITE Continued Operator Type Action IS LogicalEqual LIKE RelationalSt ringmatching GLOB RelationalFi lenamematching to Arithmeticoperators(forexample,addition,subtraction,division)arebinaryoperatorsthattake numericvaluesandproduceanumericvalue.Relationaloperators(forexample,>, 5 1 < 2 Alogicalexpressionisanyexpressionthatreturnsatruthvalue.InSQLite,falseisrepresentedby thenumber0,whiletrueisrepresentedbyanythingelse.Forexample: sqlite> SELECT 1 > 2; 1 > 2 ---------0 sqlite> SELECT 1 < 2; 1 < 2 ---------1 sqlite> SELECT 1 = 2; 1 = 2 ---------0 sqlite> SELECT -1 AND 1; -1 AND 1 ---------1 62 CHAPTER3■SQLFORSQLITE Logical Operators Logicaloperators(AND,OR,NOT,IN)arebinaryoperatorsthatoperateontruthvaluesorlogical expressions.Theyproduceaspecifictruthvaluedependingontheirinputs.Theyareusedtobuildmore complexlogicalexpressionsfromsimplerexpressions,suchasthefollowing: (x > 5) AND (x != 3) (y < 2) OR (y > 4) AND NOT (y = 0) (color='purple') AND (grin='toothy') ThetruthvalueproducedbyalogicaloperatorfollowsnormalBooleanlogicrules,butthereisan addedtwistwhenconsideringnulls,whichwe’lldiscusslaterinthechapter.Thisisthestuffthewhere clauseismadeof—usinglogicaloperatorstoanswerrealquestionsaboutthedatainyourSQLite database.Here’sanexample: sqlite> select * from foods where name='JujyFruit' and type_id=9; id ---------244 type_id ---------9 name ---------JujyFruit Therestrictionhereworksaccordingtotheexpression(name='JujyFruit') and (type_id=9),which consistsoftwologicalexpressionsjoinedbylogicaland.Bothoftheseconditionsmustbetrueforany recordinfoodstobeincludedintheresult. The LIKE and GLOB Operators Aparticularlyusefulrelationaloperatorislike.likeissimilartoequals(=)butisusedformatching stringvaluesagainstpatterns.Forexample,toselectallrowsinfoodswhosenamesbeginwiththeletter J,youcoulddothefollowing: sqlite> select id, name from foods where name like 'J%'; id ----156 236 243 244 245 370 name -------------------Juice box Juicy Fruit Gum Jello with Bananas JujyFruit Junior Mints Jambalaya Apercentsymbol(%)inthepatternmatchesanysequenceofzeroormorecharactersinthestring. Anunderscore(_)inthepatternmatchesanysinglecharacterinthestring.Thepercentsymbolis greedy.Itwilleateverythingbetweentwocharactersexceptthosecharacters.Ifitisontheextremeleft orrightofapattern,itwillconsumeeverythingoneachrespectiveside.Considerthefollowing examples: 63 CHAPTER3■SQLFORSQLITE sqlite> select id, name from foods where name like '%ac%P%'; id name ----- -------------------127 Guacamole Dip 168 Peach Schnapps 198 Mackinaw Peaches AnotherusefultrickistouseNOTtonegateapattern: sqlite> select id, name from foods where name like '%ac%P%' and name not like '%Sch%' id ----38 127 198 name -------------------Pie (Blackberry) Pie Guacamole Dip Mackinaw peaches Thegloboperatorisverysimilarinbehaviortothelikeoperator.Itskeydifferenceisthatitbehaves muchlikeUnixorLinuxfileglobbingsemanticsinthoseoperatingsystems.Thismeansitusesthe wildcardsassociatedwithfileglobbingsuchas*and_andthatmatchingiscasesensitive.Thefollowing exampledemonstratesglobinaction: sqlite> select id, name from foods ...> where name glob 'Pine*'; id ---------205 258 name ---------Pineapple Pineapple SQLitealsorecognizesthematchandregexppredicatesbutcurrentlydoesnotprovideanative implementation.You’llneedtodevelopyourownwiththesqlite_create_funtion()call,discussedin Chapters5through8. LimitingandOrdering Youcanlimitthesizeandparticularrangeoftheresultusingthelimitandoffsetkeywords.limit specifiesthemaximumnumberofrecordstoreturn.offsetspecifiesthenumberofrecordstoskip.For example,thefollowingstatementobtainstheCerealrecord(thesecondrecordinfood_types)using limitandoffset: select * from food_types order by id limit 1 offset 1; Theoffsetclauseskipsonerow(theBakeryrow),andthelimitclausereturnsamaximumofone row(theCerealrow). Butthereissomethingelsehereaswell:order by.Thisclausesortstheresultbyacolumnor columnsbeforeitisreturned.Thereasonitisimportantinthisexampleisbecausetherowsreturned fromselectareneverguaranteedtobeinanyspecificorder—theSQLstandarddeclaresthis.Thus,the order byclauseisessentialifyouneedtocountontheresultbeinginanyspecificorder.Thesyntaxof 64 CHAPTER3■SQLFORSQLITE theorder byclauseissimilartotheselectclause:itisacomma-separatedlistofcolumns.Eachentry maybequalifiedwithasortorder—asc(ascending,thedefault)ordesc(descending).Forexample: sqlite> select * from foods where name like 'B%' order by type_id desc, name limit 10; id ----382 383 384 385 362 328 327 326 329 274 type_id -------15 15 15 15 14 12 12 12 12 10 name -------------------Baked Beans Baked Potato w/Sour Big Salad Broccoli Bouillabaisse BLT Bacon Club (no turke Bologna Brisket Sandwich Bacon Typicallyyouonlyneedtoorderbyasecond(third,andsoon)columnwhenthereareduplicate valuesinthefirst(second,andsoon)orderedcolumn(s).Here,thereweremanyduplicatetype_ids.I wantedtogroupthemtogetherandthenarrangethefoodsalphabeticallywithinthesegroups. ■NotelimitandoffsetarenotstandardSQLkeywordsasdefinedintheANSIstandard.Mostdatabaseshave functionalequivalents,althoughtheyusedifferentsyntax. Ifyouusebothlimitandoffsettogether,youcanuseacommanotationinplaceoftheoffset keyword.Forexample,thefollowingSQL: select * from foods where name like 'B%' order by type_id desc, name limit 1 offset 2; canbeexpressedequivalentlywiththis: sqlite> select * from foods where name like 'B%' order by type_id desc, name limit 2,1; id ----384 type_id -------15 name -------------------Big Salad Thereisatrickhereforthosewhothinkthissyntaxshouldbetheotherwayaround.InSQLite,when usingthisshorthandnotation,theoffsetprecedesthelimit.Here,thevaluesfollowinglimitkeyword specifyanoffsetof2andalimitof2.Also,notethatoffsetdependsonlimit.Thatis,youcanuselimit withoutusingoffsetbutnottheotherwayaround. Noticethatlimitandoffsetaredeadlastintheoperationalpipeline.Onecommonmisconception oflimit/offsetisthatitspeedsupaquerybylimitingthenumberofrowsthatmustbecollectedbythe 65 CHAPTER3■SQLFORSQLITE whereclause.Thisisnottrue.Ifitwere,thenorderbywouldnotworkproperly.Fororderbytodoitsjob, itmusthavetheentireresultinhandtoprovidethecorrectorder.Thereisasmallperformanceboost,in thatSQLiteonlyneedstokeeptrackoftheorderofthe10biggestvaluesatanypoint.Thishassome benefitbutnotnearlyasmuchasthe“sort-freelimiting”thatsomeexpect. FunctionsandAggregates SQLitecomeswithvariousbuilt-infunctionsandaggregatesthatcanbeusedwithinvariousclauses. Functiontypesrangefrommathematicalfunctionssuchasabs(),whichcomputestheabsolutevalue,to string-formattingfunctionssuchasupper()andlower(),whichconverttexttoupper-andlowercase, respectively.Forexample: sqlite> select upper('hello newman'), length('hello newman'), abs(-12); upper('hello newman') --------------------HELLO NEWMAN length('hello newman') abs(-12) ----------------------------12 12 Noticethatthefunctionnamesarecaseinsensitive(i.e.,upper()andUPPER()refertothesame function).Functionscanacceptcolumnvaluesastheirarguments: sqlite> select id, upper(name), length(name) from foods where type_id=1 limit 10; id ----1 2 3 4 5 6 7 8 9 10 upper(name) -------------------------BAGELS BAGELS, RAISIN BAVARIAN CREAM PIE BEAR CLAWS BLACK AND WHITE COOKIES BREAD (WITH NUTS) BUTTERFINGERS CARROT CAKE CHIPS AHOY COOKIES CHOCOLATE BOBKA length(name) -----------6 14 18 10 23 17 13 11 18 15 Sincefunctionscanbepartofanyexpression,theycanalsobeusedinthewhereclause: sqlite> select id, upper(name), length(name) from foods where length(name) < 5 limit 5; id ----36 48 56 57 80 66 upper(name) -------------------PIE BRAN KIX LIFE DUCK length(name) -------------------3 4 3 4 4 CHAPTER3■SQLFORSQLITE Aggregatesareaspecialclassoffunctionsthatcalculateacomposite(oraggregate)valueovera groupofrows(orrelation).Standardaggregatefunctionsincludesum(),avg(),count(),min(),andmax(). Forexample,togetacountofthenumberoffoodsthatarebakedgoods(type_id=1),youcanusethe countaggregateasfollows: sqlite> select count(*) from foods where type_id=1; count ----47 Thecountaggregatereturnsacountofeveryrowintherelation.Wheneveryouseeanaggregate, youshouldautomaticallythink,“Foreachrowinatable,dosomething.” Aggregatescanaggregatenotonlycolumnvaluesbutanyexpression—includingfunctions.For example,togettheaveragelengthofallfoodnames,youcanapplytheavgaggregatetothelength(name) expressionasfollows: sqlite> select avg(length(name)) from foods; avg(length(name)) ----------------12.58 Aggregatesoperatewithintheselectclause.Theycomputetheirvaluesontherowsselectedbythe whereclause—notfromallrowsselectedbythefromclause.Theselectcommandfiltersfirstandthen aggregates. AlthoughSQLitecomeswithastandardsetofcommonSQLfunctionsandaggregates,itisworth notingthattheSQLiteCAPIallowsyoutocreatecustomfunctionsandaggregatesaswell.SeeChapter7 formoreinformation. Grouping Anessentialpartofaggregationisgrouping.Thatis,inadditiontocomputingaggregatesoveranentire result,youcanalsosplitthatresultintogroupsofrowswithlikevaluesandcomputeaggregatesoneach group—allinonestep.Thisisthejobofthegroup byclause.Here’sanexample: sqlite> select type_id from foods group by type_id; type_id ---------1 2 3 . . . 15 67 CHAPTER3■SQLFORSQLITE group byisabitdifferentfromtheotherpartsofselect,soyouneedtouseyourimaginationalittle towrapyourheadaroundit.Figure3-7illustratestheprocess.Operationally,group bysitsinbetween thewhereclauseandtheselectclause.group bytakestheoutputofwhereandsplitsitintogroupsof rowsthatshareacommonvalue(orvalues)foraspecificcolumn(orcolumns).Thesegroupsarethen passedtotheselectclause.Intheexample,thereare15differentfoodtypes(type_idrangesfrom1to 15),andthereforegroup byorganizesallrowsinfoodsinto15groupsvaryingbytype_id.selecttakes eachgroup,extractsitscommontype_idvalue,andputsitintoaseparaterow.Thus,thereare15rows intheresult,oneforeachgroup. tid 1 1 1 1 1 1 1 1 2 2 1 2 2 2 3 3 3 3 3 3 4 4 4 4 4 4 4 2 tid 1 2 3 15 Result 15 WHERE 15 15 GROUP BY SELECT Figure3-7.group byprocess Whengroup byisused,theselectclauseappliesaggregatestoeachgroupseparately,ratherthan theentireresultasawhole.Sinceaggregatesproduceasinglevaluefromagroupofvalues,theycollapse thesegroupsofrowsintosinglerows.Forexample,considerapplyingthecountaggregatetothe precedingexampletogetthenumberofrecordsineachtype_idgroup: sqlite> select type_id, count(*) from foods group by type_id; type_id ---------1 2 3 68 count(*) ---------47 15 23 CHAPTER3■SQLFORSQLITE 4 5 6 7 8 9 10 11 12 13 14 15 22 17 4 60 23 61 36 16 23 14 19 32 Here,count()wasapplied15times—onceforeachgroup,asillustratedinFigure3-8.Notethatin thediagram,theactualnumberofrecordsineachgroupisnotrepresentedliterally(thatis,itdoesn’t show47recordsinthegroupfortype_id=1). 1 1 COUNT() 1 tid 1 1 2 1 2 COUNT() 2 2 3 3 3 COUNT() 3 4 4 4 4 COUNT() tid 1 COUNT() 2 15 3 23 4 22 15 32 47 Result 15 COUNT() WHERE 15 COUNT() GROUP BY SELECT Figure3-8.group byandaggregation 69 CHAPTER3■SQLFORSQLITE Thenumberofrecordswithtype_id=1(BakedGoods)is47.Thenumberwithtype_id=2(Cereal)is 15.Thenumberwithtype_id=3(Chicken/Fowl)is23,andsoforth.So,togetthisinformation,youcould run15queriesasfollows: select select select . . . select count(*) from foods where type_id=1; count(*) from foods where type_id=2; count(*) from foods where type_id=3; count(*) from foods where type_id=15; Or,yougettheresultsusingthesingleselectwithagroup byasfollows: select type_id, count(*) from foods group by type_id; Butthereismore.Sincegroup byhastodoallthisworktocreategroupswithlikevalues,itseemsa pitynottoletyoufilterthesegroupsbeforehandingthemofftotheselectclause.Thatisthepurposeof having,apredicatethatyouapplytotheresultofgroup by.Itfiltersthegroupsfromgroup byinthe samewaythatthewhereclausefiltersrowsfromthefromclause.Theonlydifferenceisthatthewhere clause’spredicateisexpressedintermsofindividualrowvalues,andhaving’spredicateisexpressedin termsofaggregatevalues. Takethepreviousexample,butthistimesayyouareinterestedonlyinlookingatthefoodgroups thathavefewerthan20foodsinthem: sqlite> select type_id, count(*) from foods group by type_id having count(*) < 20; type_id ---------2 5 6 11 13 14 70 count(*) ---------15 17 4 16 14 19 CHAPTER3■SQLFORSQLITE Here,havingappliesthepredicatecount(*) 4 then 'Very High' when count(*) = 4 then 'High' when count(*) in (2,3) then 'Moderate' else 'Low' end from foods_episodes where food_id=f.id) frequency from foods f where frequency like '%High' name --------Kasha Ketchup Hot Dog Pizza frequency ---------High High Very High High Thisqueryrunsasubqueryforeachrowinfoodsthatclassifiesthefoodbythenumberofepisodes itappearsin.Theresultofthissubqueryisincludedasacolumncalledfrequency.Thewherepredicate filtersfrequencyvaluesthathavethewordHighinthem. Onlyoneconditionisexecutedinacaseexpression.Ifmorethanoneconditionissatisfied,onlythe firstofthemisexecuted.Ifnoconditionsaresatisfiedandnoelseconditionisdefined,casereturns null. HandlingNullinSQLite Mostrelationaldatabasessupporttheconceptof“unknown”or“unknowable”throughaspecial placeholdercallednull,whichisaplaceholderformissinginformationandisnotavalueperse.Rather, nullistheabsenceofavalue:nullisnotnothing,nullisnotsomething,nullisnottrue,nullisnot false,nullisnotzero,nullisnotanemptystring.Simplyput,nullisresolutelywhatitis:null.Andnot 84 CHAPTER3■SQLFORSQLITE everyonecanagreeonwhatthatmeans.Thereareafewkeyrulesandideasthatyoushouldlearnsoyou canmastertheuseofnullinSQLite. First,inordertoaccommodatenullinlogicalexpressions,SQLusessomethingcalledthree-value (ortristate)logic,wherenullisoneofthetruthvalues.Table3-2showsthetruthtableforlogicalandand logicalorwithnullthrownintothemix. Table3-2.ANDandORwithNULL x y TrueTrue TrueFalse True y OR y True True False True True NULL NULL FalseFalse False x AND y NULL NULL NULL False False False NULL NULL NULL Youcantryafewsimpleselectstatementstoseetheeffectofnullyourself. Second,detectingthepresenceorabsenceofnullisdoneusingtheis nulloris not null operator.Ifyoutrytouseanyotheroperator,suchasequals,greaterthan,andsoon,youwillreceivea shock,whichleadsustoourthirdruleregardingnull. Thirdandlast,alwaysrememberthatnullisnotequaltoanyothervalue,evennullitself.You cannotcomparenullwithavalue,andnonullisgreaterthan,smallerthan,orinanywayrelatedtoany anothernull.Thisoftencatchesouttheunwarywhenstatementslikethenextexamplefailtoreturnany rows. select * from mytable where myvalue = null; Nothingcanequalnull,sonodatawilleverbereturnedbythatstatementinSQLite.Nowthat you’vemasteredthebasics,you’llbepleasedtoknowthatSQLiteoffersseveraladditionalfunctionsfor workingwithnull.Thefirstofwhichisaworkaroundfortheverylimitationof“nothingequalsNULL” thatwe’vejustdrilledintoyou.FromSQLitev3.6.19,theisoperatorcanbeusedtoequateoneNULLto another.Inthemostbasicform,youcanrunasimplequerytoaskSQLiteifNULL is NULL: sqlite> select NULL is NULL; 1 Asalreadymentioned,anyvalueotherthanzeromeans“true,”soSQLiteishappytotellusthatin thisinstanceNULLreallyisthesameasNULL.Butplease,don’trelyonthisheavily.SQL’strivaluelogic maybeawkward,butitisastandard,andworkingarounditwiththeisoperatorwilllikelyhaveyou encounteringproblemswithothersystemsandprogramminglanguagesthatexpectthestandard behavior. 85 CHAPTER3■SQLFORSQLITE Thecoalescefunction,whichispartoftheSQL99standard,takesalistofvaluesandreturnsthefirst non-nullinthelist.Takethefollowingexample: select coalesce(null, 7, null, 4) Inthiscase,coalescewillreturn7asthefirstnon-nullvalue.Thisisalsohandywhenperforming arithmetic,soyoucandetectwhethernullhasbeenreturnedandreturnameaningfulvaluelike0 instead. Conversely,thenulliffunctiontakestwoargumentsandreturnsnulliftheyhavethesamevalues; otherwise,itreturnsthefirstargument: sqlite> select nullif(1,1); null sqlite> select nullif(1,2); 1 Ifyouusenull,youneedtotakespecialcareinqueriesthatrefertocolumnsthatmaycontainnull intheirpredicatesandaggregates.nullcandoquiteanumberonaggregatesifyouarenotcareful. Summary Congratulations,youhavelearnedtheselectcommandforSQLite’simplementationofSQL.Notonly haveyoulearnedhowthecommandworks,butyou’velearnedsomerelationaltheoryintheprocess. Youshouldnowbecomfortablewithusingselectstatementstoqueryyourdata,join,aggregate, summarize,anddissectitforvarioususes. We’llcontinuethediscussionofSQLinthenextchapter,wherewe’llbuildonyourknowledgeof selectbyintroducingtheothermembersofDML,aswellasDDLandotherhelpfulSQLconstructsin SQLite. 86 CHAPTER 4 ■■■ Advanced SQL for SQLite YoumasteredtheselectstatementinChapter3,sonowitistimetoaddtherestoftheSQLdialectto yourcapabilities.ThischaptercoverstheremainderofSQLasimplementedinSQLite,includinginsert, update,anddeletestatementstomodifydata;constraintstoprotectyourdata;andmoreadvanced topicssuchastablecreationanddatatypes. Modifying Data Comparedtoselect,thecommandsusedtomodifydataarequiteeasytouseandunderstand.There arethreeDataManipulationLanguage(DML)commandsformodifyingdata—insert,update,and delete—andtheydoprettymuchwhattheirnamesimply. InsertingRecords Youinsertrecordsintoatableusingtheinsertcommand.insertworksonasingletableandcanboth insertonerowatatimeandcaninsertmanyrowsatonceusingaselectcommand.Thegeneralformof theinsertcommandisasfollows: insert into table (column_list) values (value_list); Thevariabletablespecifieswhichtable—thetargettable—toinsertinto.Thevariablecolumn_listisa comma-separatedlistofcolumnnames,allofwhichmustexistinthetargettable.Thevariable value_listisacomma-separatedlistofvaluesthatcorrespondtothenamesgivenincolumn_list.The orderofvaluesinvalue_listmustcorrespondtotheorderofcolumnsincolumn_list. Inserting One Row Forexample,you’dusethistoinsertarowintofoods: sqlite> insert into foods (name, type_id) values ('Cinnamon Bobka', 1); Thisstatementinsertsonerow,specifyingtwocolumnvalues.'Cinnamon Bobka'—thefirstvalueinthe valuelist—correspondstothecolumnname,whichisthefirstcolumninthecolumnlist.Similarly,the value1correspondstotype_id,whichislistedsecond.Noticethatidwasnotmentioned.Inthiscase, 87 CHAPTER4■ADVANCEDSQLFORSQLITE thedatabaseusesthedefaultvalue.Sinceidisdeclaredasinteger primary key,itwillbeautomatically generatedandassociatedwiththerecord(asexplainedinthesection“PrimaryKeyConstraints”).The insertedrecordcanbeverifiedwithasimpleselect,andthevalueusedforidcanbequeriedaswell: sqlite> select * from foods where name='Cinnamon Bobka'; id ---------413 type_id ---------1 name -------------Cinnamon Bobka sqlite> select max(id) from foods; MAX(id) ---------413 sqlite> select last_insert_rowid(); last_insert_rowid() ------------------413 Noticethatthevalue413wasautomaticallygeneratedforid,whichisthelargestvalueinthe column.Thus,SQLiteprovidedamonotonicallyincreasingvalue.Youcanconfirmthiswiththebuilt-in SQLfunctionlast_insert_rowid(),whichreturnsthelastautomaticallygeneratedkeyvalue,asshown intheexample. Ifyouprovideavalueforeverycolumnofatableininsert,thenthecolumnlistcanbeomitted.In thiscase,thedatabaseassumesthattheorderofvaluesprovidedinthevaluelistcorrespondstothe orderofcolumnsasdeclaredinthecreate tablestatement.Here’sanexample: sqlite> insert into foods values(NULL, 1, 'Blueberry Bobka'); sqlite> select * from foods where name like '%Bobka'; id ---------10 413 414 type_id ---------1 1 1 name --------------Chocolate Bobka Cinnamon Bobka Blueberry Bobka Noticeheretheorderofarguments.'Blueberry Bobka'cameafter1inthevaluelist.Thisisbecauseof thewaythetablewasdeclared.Toviewthetable’sdefinition,type.schema foodsattheshellprompt: sqlite> .schema foods CREATE TABLE foods( id integer primary key, type_id integer, name text ); CREATE INDEX foods_name_idx on foods (name COLLATE NOCASE); Thefirstcolumnisid,followedbytype_id,followedbyname.This,therefore,istheorderyoumustlist valuesininsertstatementsonfoods.WhydidtheprecedinginsertstatementuseaNULLforid?SQLite 88 CHAPTER4■ADVANCEDSQLFORSQLITE knowsthatidinfoodsisanautoincrementcolumn,andspecifyingaNULListheequivalentofnot providingavalueatall.Notspecifyingavaluetriggerstheautomatickeygeneration.It’sjusta convenienttrick.Thereisnodeepermeaningortheoreticalbasisbehindit.Wewilllookatthesubtleties ofautoincrementcolumnslaterinthischapter. Inserting a Set of Rows Subqueriescanbeusedininsertstatements,bothascomponentsofthevaluelistandasacomplete replacementofthevaluelist.Whenyouspecifyasubqueryasthevaluelist,youarereallyinsertingaset ofrows,becauseyouareinsertingthesetofrowsreturnedbythatsubquery.Here’sanexamplethat generatesasethavingjustonerow: insert into foods values (null, (select id from food_types where name='Bakery'), 'Blackberry Bobka'); select * from foods where name like '%Bobka'; id ---------10 413 414 415 type_id ---------1 1 1 1 name ---------------Chocolate Bobka Cinnamon Bobka Blueberry Bobka Blackberry Bobka Here,ratherthanhard-codingthetype_idvalue,IhadSQLitelookitupforme.Here’sanotherexample: insert into foods select last_insert_rowid()+1, type_id, name from foods where name='Chocolate Bobka'; select * from foods where name like '%Bobka'; id ---------10 413 414 415 416 type_id ---------1 1 1 1 1 name ---------------Chocolate Bobka Cinnamon Bobka Blueberry Bobka Blackberry Bobks Chocolate Bobka Thisquerycompletelyreplacesthevaluelistwithaselectstatement.Aslongasthenumberof columnsintheselectclausematchesthenumberofcolumnsinthetable(orthenumberofcolumnsin thecolumnslist,ifprovided),insertwillworkjustfine.Here,thisexampleaddedanotherchocolate bobkaandusedtheexpressionlast_insert_rowid()+1astheidvalue.Youcouldhavejustaseasilyused NULLinstead.Infact,youprobablyshoulduseNULLratherthanlast_insert_rowid(),because last_insert_rowid()willreturn0ifyoudidnotpreviouslyinsertarowinthecurrentsession. 89 CHAPTER4■ADVANCEDSQLFORSQLITE Youcouldsafelyassumethatthiswouldworkproperlyfortheseexamples,butitwouldnotbeagood ideatomakethisassumptioninaprogram. Inserting Multiple Rows Thereisnothingstoppingyoufrominsertingmultiplerowsatatimeusingtheselectformofinsert.As longasthenumberofcolumnsmatches,insertwillinserteveryrowintheresult.Here’sanexample: sqlite> create table foods2 (id int, type_id int, name text); sqlite> insert into foods2 select * from foods; sqlite> select count(*) from foods2; count(*) -------------------418 Thiscreatesanewtablefoods2andinsertsintoitalltherecordsfromfoods. However,thereisaneasierwaytocreateandpopulateatable.Thecreate tablestatementhasa specialsyntaxforcreatingtablesfromselectstatements.Thepreviousexamplecouldhavebeen performedinonestepusingthissyntax: sqlite> create table foods2 as select * from foods; sqlite> select count(*) from list; count(*) -------418 create tabledoesbothstepsinonefellswoop.Thiscanbeespeciallyusefulforcreatingtemporary tables: create temp table list as select f.name food, t.name name, (select count(episode_id) from foods_episodes where food_id=f.id) episodes from foods f, food_types t where f.type_id=t.id; select * from list; Food Name Episodes -------------------- ---------- ---------Bagels Bakery 1 Bagels, raisin Bakery 2 Bavarian Cream Pie Bakery 1 Bear Claws Bakery 3 Black and White cook Bakery 2 Bread (with nuts) Bakery 1 Butterfingers Bakery 1 90 CHAPTER4■ADVANCEDSQLFORSQLITE Carrot Cake Chips Ahoy Cookies Chocolate Bobka Bakery Bakery Bakery 1 1 1 WhenusingthisformofCREATE TABLE,beawarethatanyconstraintsdefinedinthesourcetableare notcreatedinthenewtable.Specifically,theautoincrementcolumnswillnotbecreatedinthenew table,norwillindexes,UNIQUEconstraints,andsoforth.Manyotherdatabasesrefertothisapproachas CTAS,whichstandsforCreateTableAsSelect,andthatphraseisnotuncommonamongSQLiteusers. Itisalsoworthmentioningherethatyouhavetobeawareofuniqueconstraintswheninserting rows.Ifyouaddduplicatevaluesoncolumnsthataredeclaredasunique,SQLitewillstopyouinyour tracks: sqlite> select max(id) from foods; max(id) ------416 sqlite> insert into foods values (416, 1, 'Chocolate Bobka'); SQL error: PRIMARY KEY must be unique UpdatingRecords Youupdaterecordsinatableusingtheupdatecommand.Theupdatecommandmodifiesoneormore columnswithinoneormorerowsinatable.updatehasthefollowinggeneralform: update table set update_list where predicate; update_listisalistofoneormorecolumnassignmentsoftheformcolumn_name=value.Thewhere clauseworksexactlyasinselect.Halfofupdateisreallyaselectstatement.Thewhereclauseidentifies rowstobemodifiedusingapredicate.Thoserowsthenhavetheupdatelistappliedtothem.Here’san example: update foods set name='CHOCOLATE BOBKA' where name='Chocolate Bobka'; select * from foods where name like 'CHOCOLATE%'; id type_ name ----- ----- -----------------------------10 1 CHOCOLATE BOBKA 11 1 Chocolate Eclairs 12 1 Chocolate Cream Pie 222 9 Chocolates, box of 223 9 Chocolate Chip Mint 224 9 Chocolate Covered Cherries 91 CHAPTER4■ADVANCEDSQLFORSQLITE updateisaverysimpleanddirectcommand,andthisisprettymuchtheextentofitsuse.Asin insert,youmustbeawareofanyuniqueconstraints,becausetheywillstopupdateeverybitasmuchas insert: sqlite> update foods set id=11 where name='CHOCOLATE BOBKA'; SQL error: PRIMARY KEY must be unique Thisistrueforanyconstraint,however. DeletingRecords Youdeleterecordsfromatableusingthedeletecommand.Thedeletecommanddeletesrowsfroma table.deletehasthefollowinggeneralform: delete from table where predicate; Syntactically,deleteisawatered-downupdatestatement.RemovetheSETclausefromupdate,and youhavedelete.Thewhereclauseworksexactlylikeselect,exceptthatitidentifiesrowstobedeleted. Here’sanexample: delete from foods where name='CHOCOLATE BOBKA'; Data Integrity Dataintegrityisconcernedwithdefiningandprotectingrelationshipswithinandbetweentables.There arefourgeneraltypes:domainintegrity,entityintegrity,referentialintegrity,anduser-definedintegrity. Domainintegrityinvolvescontrollingvalueswithincolumns.Entityintegrityinvolvescontrollingrows intables.Referentialintegrityinvolvescontrollingrowsbetweentables—specificallyforeignkey relationships.Anduser-definedintegrityisacatchallforeverythingelse. Dataintegrityisimplementedusingconstraints.Aconstraintisacontrolmeasureusedtorestrict thevaluesthatcanbestoredinacolumnorcolumns.Goingbyjustthevaluesincolumns,thedatabase canenforceallfourtypesofintegrityconstraints.InSQLite,constraintsalsoincludesupportforconflict resolution.Conflictresolutioniscoveredindetaillaterinthischapter. Let’sdeviatefromourfoodsdatabaseforamomentandfocusonthesamecontactstable introducedinChapter3.Thecontactstableisdefinedasfollows: create table contacts ( id integer primary key, name text not null collate nocase, phone text not null default 'UNKNOWN', unique (name,phone) ); Asyouknowbynow,constraintsarepartofatable’sdefinition.Theycanbeassociatedwitha columndefinitionordefinedindependentlyinthebodyofthetabledefinition.Column-levelconstraints includenot null,unique,primary key,foreign key,check,andcollate.Table-levelconstraintsinclude primary key,unique,andcheck.Alloftheseconstraintsarecoveredinthefollowingsectionsaccording totheirrespectiveintegritytypes. 92 CHAPTER4■ADVANCEDSQLFORSQLITE Nowthatyouhavefamiliaritywiththeupdate,insert,anddeletecommandsinSQLite,the operationofmanyoftheconstraintswillmakesense.Justasthesecommandsoperateondata, constraintsoperateonthem,makingsurethattheyworkwithintheguidelinesdefinedinthetablesthey modify. EntityIntegrity Relationaltheory—asimplementedinmostdatabasesincludingSQLite—requiresthateveryfieldinthe databasemustbeuniquelyidentifiableandcapableofbeinglocated.Forafieldtobeaddressable,its correspondingrowmustalsobeaddressable.Andforthat,therowmustbeuniqueinsomeway.Thisis thejoboftheprimarykey. Theprimarykeyconsistsofleastonecolumnoragroupofcolumnswithauniqueconstraint.The uniqueconstraint,asyouwillsoonsee,simplyrequiresthateveryvalueinacolumn(orgroupof columns)bedistinct.Therefore,theprimarykeyensuresthateachrowissomehowdistinctfromall otherrowsinatable,ultimatelyensuringthateveryfieldisalsoaddressable.Entityintegritybasically keepsdataorganizedinatable.Afterall,whatgoodisdataifyoucan’tfindit? Unique Constraints Sinceprimarykeysarebasedonuniqueconstraints,we’llstartwiththem.Auniqueconstraintsimply requiresthatallvaluesinacolumnoragroupofcolumnsaredistinctfromoneanotherorunique.Ifyou attempttoinsertaduplicatevalueorupdateavaluetoanothervaluethatalreadyexistsinthecolumn, thedatabasewillissueaconstraintviolationandaborttheoperation.uniqueconstraintscanbedefined atthecolumnorthetablelevel.Whendefinedatthetablelevel,uniqueconstraintscanbeappliedacross multiplecolumns.Inthiscase,thecombinedvalueofthecolumnsmustbeunique.Incontacts,thereis auniqueconstraintonbothnameandphonetogether.Seewhathappensifweattempttoinsertanother 'Jerry'recordwithaphonevalue'UNKNOWN': sqlite> insert into contacts (name,phone) values ('Jerry','UNKNOWN'); SQL error: columns name, phone are not unique sqlite> insert into contacts (name) values ('Jerry'); SQL error: columns name, phone are not unique sqlite> insert into contacts (name,phone) values ('Jerry', '555-1212'); Inthefirstcase,Iexplicitlyspecifiednameandphone.Thismatchedthevaluesoftheexistingrecord,and theuniqueconstraintkickedinanddidnotletmedoit.Thethirdinsertillustratesthattheunique constraintappliestonameandphonecombined,notindividually.Itinsertedanotherrowwith'Jerry'as thevalueforname,whichdidnotcauseanerror,becausenamebyitselfitnotunique—onlynameand phonetogether. 93 s CHAPTER4■ADVANCEDSQLFORSQLITE NULL AND UNIQUE BasedonyourknowledgeofNULLfromChapter3andyournewknowledgeofunique constraints,how manyNULLvaluescanyouputinacolumnthatisdeclaredunique?Fromatheoreticalperspective,the answerisasmanyNULLsasyoulike.RememberthatNULLisnotequaltoanythingelse,evenotherNULLs. AndthisisthebasisforhowSQLitehandlesNULLentriesinuniquecolumns.It’salsohowothermajor databaseslikeOracleandPostgreSQLoperate.Butthedatabasecommunityisdividedonthisissue.Users ofInformix,Sybase,andMicrosoftSQLServerarelimitedtoonlyoneNULLentryinauniquecolumn.Those usingDB2areforbiddenanyatall! Primary Key Constraints InSQLite,aprimarykeycolumnisalwayscreatedwhenyoucreateatable,whetheryoudefineoneor not.Thiscolumnisa64-bitintegervaluecalledrowid.Ithastwoaliases,_rowid_andoid,whichcanbe usedtorefertoitaswell.Defaultvaluesareautomaticallygeneratedforit. SQLiteprovidesanautoincrementfeatureforprimarykeys,shouldyouwanttodefineyourown.If youdefineacolumn’stypeasinteger primary key,SQLitewillcreateadefaultvalueonthatcolumn, whichwillprovideanintegervaluethatisguaranteedtobeuniqueinthatcolumn.Inreality,however, thiscolumnwillsimplybeanaliasforrowid.Theywillallrefertothesamevalue.SinceSQLiteusesa64bitsignedintegerfortheprimarykey,themaximumvalueforthiscolumnis9,223,372,036,854,775,807. Evenifyoumanagetoreachthislimit,SQLitewillsimplystartsearchingforuniquevaluesthatare notinthecolumnforsubsequentinserts.Whenyoudeleterowsfromthetable,rowidsmayberecycled andreusedonsubsequentinserts.Asaresult,newlycreatedrowidsmightnotalwaysbeinstrictly ascendingorder. ■CautionYouwillrememberourdiscussiononrelationaldatanothavingimplicitorderwhenwediscussedthe order by statementinChapter3.Thisisanotherstrongremindernevertoassumedatainarelationaldatabase suchasSQLitehasanyparticularorder—evenwhenyourinstinctssayitshouldbesafe. IfyouwantSQLitetouseuniqueautomaticprimarykeyvaluesforthelifeofthetable—andnot“fill inthegaps”—thenaddtheautoincrementkeywordaftertheinteger primary keyclause. Intheexamplessofar,youhavemanagedtoinserttworecordsintocontacts.Notoncedidyou specifyavalueforid.Asmentionedbefore,thisisbecauseidisdeclaredasinteger primary key. Therefore,SQLitesuppliedanintegervalueforeachinsertautomatically,asyoucanseehere: 94 CHAPTER4■ADVANCEDSQLFORSQLITE sqlite> select * from contacts; id --1 2 name ----Jerry Jerry phone -------UNKNOWN 555-1212 Noticethattheprimarykeyisaccessiblefromalltheaforementionedaliases,inadditiontoid: sqlite> select rowid, oid,_rowid_,id, name, phone from contacts; id -1 2 id -1 2 id -1 2 id -1 2 name ---Jerry Jerry phone ----UNKNOWN 555-1212 Ifyouincludethekeywordautoincrementafterinteger primary key,SQLitewilluseadifferentkey generationalgorithmforthecolumn.Thisalgorithmbasicallypreventsrowidsfrombeingrecycled.It guaranteesthatonlynew(notrecycled)rowidsareprovidedforeveryinsert.Whenatableiscreated withacolumncontainingtheautoincrementconstraint,SQLitewillkeeptrackofthatcolumn’s maximumrowidinasystemtablecalledsqlite_sequence.Itwillonlyusevaluesgreaterthanthat maximumonallsubsequentinserts.Ifyoueverreachtheabsolutemaximum,thenSQLitewillreturna SQLITE_FULLerroronsubsequentinserts.Here’sanexample: sqlite> create table maxed_out(id integer primary key autoincrement, x text); sqlite> insert into maxed_out values (9223372036854775807, 'last one'); sqlite> select * from sqlite_sequence; name ---------maxed_out seq ------------------9223372036854775807 sqlite> insert into maxed_out values (null, 'will not work'); SQL error: database is full Here,weprovidedtheprimarykeyvalue.SQLitethenstoredthisvalueasthemaximumfor maxed_out.idinsqlite_sequence.Wesuppliedtheverylast(maximum)64-bitvaluebeforewraparound. Inthenextinsert,youusedthegenerateddefaultvalue,whichmustbeamonotonicallyincreasing value.Thiswrappedaroundto0,andSQLiteissuedaSQLITE_FULLerror. AlthoughSQLitetracksthemaximumvalueforanautoincrementcolumninthesqlite_sequence table,itdoesnotpreventyoufromprovidingyourownvaluesforitintheinsertcommand.Theonly requirementisthatthevalueyouprovidemustbeuniquewithinthecolumn.Here’sanexample: sqlite> sqlite> sqlite> sqlite> drop table maxed_out; create table maxed_out(id integer primary key autoincrement, x text); insert into maxed_out values(10, 'works'); select * from sqlite_sequence; 95 CHAPTER4■ADVANCEDSQLFORSQLITE name ---------maxed_out seq ---------10 sqlite> insert into maxed_out values(9, 'works'); sqlite> select * from sqlite_sequence; name ---------maxed_out seq ---------10 sqlite> insert into maxed_out values (9, 'fails'); SQL error: PRIMARY KEY must be unique sqlite> insert into maxed_out values (null, 'should be 11'); sqlite> select * from maxed_out; id ---------9 10 11 x -----------works works should be 11 sqlite> select * from sqlite_sequence; name ---------maxed_out seq ---------11 Here,youdroppedandre-createdthemaxed_outtableandinsertedarecordwithanexplicitlydefined rowidof10.Thenyouinsertedarecordwitharowidlessthan10,whichworked.Youtrieditagainwith thesamevalueanditfailed,becauseoftheuniqueconstraint.Finally,youinsertedanotherrecordusing thedefaultkeyvalue,andSQLiteprovidedthenextlvalue—10+1. Insummary,autoincrementpreventsSQLitefromrecyclingprimarykeyvalues(rowids)andstops whentherowidreachesthemaximumsigned64-bitintegervalue.Thisfeaturewasaddedforspecific applicationsthatrequiredthisbehavior.Unlessyouhavesuchaspecificneedinyourapplication,itis perhapsbesttojustuseinteger primary keyforautoincrementcolumns. Likeuniqueconstraints,primary keyconstraintscanbedefinedovermultiplecolumns.Youdon’t havetouseanintegervalueforyourprimarykey.Ifyouchoosetouseanothervalue,SQLitewillstill maintaintherowidcolumninternally,butitwillalsoplaceauniqueconstraintonyourdeclaredprimary key.Here’sanexample: sqlite> sqlite> sqlite> sqlite> 96 create insert insert select table pkey(x text, y text, primary key(x,y)); into pkey values ('x','y'); into pkey values ('x','x'); rowid, x, y from pkey; CHAPTER4■ADVANCEDSQLFORSQLITE rowid ---------1 2 x ---------x x y ---------y x sqlite> insert into pkey values ('x','x'); SQL error: columns x, y are not unique Theprimarykeyhereistechnicallyjustauniqueconstraintacrosstwocolumns,becauseSQLitewill alwaysstillmaintainaninternalrowid.Butmanydatabasedesignexpertswillencourageyoutousereal columnsforyourprimarykeys,andIencourageyoutodothatwhereveritmakessense. DomainIntegrity Thesimplestdefinitionofdomainintegrityistheconformanceofacolumn’svaluestoitsassigned domain.Thatis,everyvalueinacolumnshouldexistwithinthatcolumn’sdefineddomain.However, thetermdomainisalittlevague.Domainsareoftencomparedtotypesinprogramminglanguages,such asstringsorfloats.Andalthoughthatisnotabadanalogy,domainintegrityisactuallymuchbroader thanthat. Domainconstraintsmakeitpossibleforyoutostartwithasimpletype—suchasaninteger—and addadditionalconstraintstocreateamorerestrictedsetofacceptablevaluesforacolumn.Forexample, youcancreateacolumnwithanintegertypeandaddtheconstraintthatonlythreesuchvaluesare allowed:{-1,0.1}.Inthiscase,youhavemodifiedtherangeofacceptablevalues(fromthedomainofall integerstojustthreeintegers),butnotthedatatypeitself.Youaredealingwithtwothings:atypeanda range. Consideranotherexample:thenamecolumninthecontactstable.Itisdeclaredasfollows: name text not null collate nocase Thedomaintextdefinesthetypeandinitialrangeofacceptablevalues.Everythingfollowingitservesto restrictandqualifythatrangeevenfurther.Thenamecolumnisthenthedomainofalltextvaluesthatdo notincludeNULLvalueswhereuppercaselettersandlowercaselettershaveequalvalue.Itisstilltextand operatesastext,butitsrangeofacceptablevaluesisfurtherrestrictedfromthatoftext. Youmightsaythatacolumn’sdomainisnotthesamethingasitstype.Rather,itsdomainisa combinationoftwothings:atypeandarange.Thecolumn’stypedefinestherepresentationand operatorsofitsvalues—howtheyarestoredandhowyoucanoperateonthem—sort,search,add, subtract,andsoforth.Acolumn’srangeisitssetofacceptablevaluesyoucanstoreinit,whichisnot necessarilythesameasitsdeclaredtype.Thetype’srangerepresentsamaximumrangeofvalues.The column’srange—asyouhaveseen—canberestrictedthroughconstraints.Soforallpracticalpurposes, youcanthinkofacolumn’sdomainasatypewithconstraintstackedon. Similarly,thereareessentiallytwocomponentstodomainintegrity:typecheckingandrange checking.AlthoughSQLitesupportsmanyofthestandarddomainconstraintsforrangechecking(not null,check,andsoon),itsapproachtotypecheckingiswherethingsdivergefromotherdatabases.In fact,SQLite’sapproachtotypesandtypecheckingisoneofitsmostcontroversial,misunderstood,and disputedfeatures.We’llcoverthebasicsshortlyandgointogreaterdepthsinChapter11whenwe discussSQLiteinternals. Fornow,let’scovertheeasystufffirst:defaultvalues,not nullconstraints,checkconstraints,and collations. 97 CHAPTER4■ADVANCEDSQLFORSQLITE Default Values Thedefaultkeywordprovidesadefaultvalueforacolumnifoneisnotprovidedinaninsertcommand. Thedefaultkeywordisonlyaconstraintinthatitpreventstheabsenceofavalue,steppinginwhen needed.However,itdoesfallwithindomainintegritybecauseitprovidesapolicyforhandlingnull valuesinacolumn.Ifacolumndoesn’thaveadefaultvalueandyoudon’tprovideavalueforitinan insertstatement,thenSQLitewillinsertnullforthatcolumn.Forexample,contacts.namehasadefault valueof'UNKNOWN'.Withthisinmind,considerthefollowingexample: sqlite> insert into contacts (name) values ('Jerry'); sqlite> select * from contacts; id ---------1 name ---------Jerry phone ---------UNKNOWN Theinsertcommandinsertedarow,specifyingavaluefornamebutnotphone.Asyoucanseefromthe resultingrow,thedefaultvalueforphonekickedinandprovidedthestring'UNKNOWN'.Ifphonedidnot haveadefaultvalue,theninthisexample,thevalueforphoneinthisrowwouldhavebeenNULLinstead. defaultalsoacceptsthreepredefinedANSI/ISOreservedwordsforgeneratingdefaultdatesand times.current_timewillgeneratethecurrentlocaltimeinANSI/ISO-8601timeformat(HH:MM:SS). current_datewillgeneratethecurrentdate(inYYYY-MM-DDformat).current_timestampwillproducea combinationofthesetwo(inYYYY-MM-DD HH:MM:SSformat).Here’sanexample: create table times ( id int, date not null default current_date, time not null default current_time, timestamp not null default current_timestamp ); insert into times (id) values (1); insert into times (id) values (2); select * from times; id --1 2 date ---------2010-06-15 2010-06-15 time ---------23:30:25 23:30:40 timestamp ------------------2010-06-15 23:30:25 2010-06-15 23:30:40 Thesedefaultscomeinquitehandyfortablesthatneedtologortimestampevents. NOT NULL Constraints IfyouareoneofthosepeoplewhoisnotfondofNULL,thentheNOT NULLconstraintisforyou.NOT NULL ensuresthatvaluesinthecolumnmayneverbeNULL.insertcommandsmaynotaddNULLinthe column,andupdatecommandsmaynotchangeexistingvaluestoNULL.Oftentimes,youwillseeNOT NULLraiseitsuglyheadininsertstatements.Specifically,aNOT NULLconstraintwithoutadefault constraintwillpreventanyunspecifiedvaluesfrombeingusedintheinsert(becausethedefaultvalues providedinthiscaseareNULL).Intheprecedingexample,theNOTNULLconstraintonnamerequiresthat aninsertcommandalwaysprovideavalueforthatcolumn.Here’sanexample: 98 CHAPTER4■ADVANCEDSQLFORSQLITE sqlite> insert into contacts (phone) values ('555-1212'); SQL error: contacts.name may not be NULL Thisinsertcommandspecifiedaphonevaluebutnotaname.TheNOT NULLconstraintonnamekickedin andforbadetheoperation. ApragmaticwaytodealwithunknowndataandNOT NULLconstraintsistoalsoincludeadefault constraintforthecolumn.Thisisthecaseforphone.AlthoughphonehasaNOT NULLconstraint,ithasa defaultconstraintaswell.Ifaninsertcommanddoesnotspecifyavalueforphone,thedefault constraintstepsinandprovidesthevalue'UNKNOWN',thussatisfyingtheNOT NULLconstraint.Tothisend, peopleoftenusedefaultconstraintsinconjunctionwithNOT NULLconstraintssothatinsertcommands cansafelyusedefaultvalueswhileatthesametimekeepingNULLoutofthecolumn. Check Constraints Checkconstraintsallowyoutodefineexpressionstotestvalueswhenevertheyareinsertedintoor updatedwithinacolumn.Ifthevaluesdonotmeetthecriteriasetforthintheexpression,thedatabase issuesaconstraintviolation.Thus,itallowsyoutodefineadditionaldataintegritychecksbeyondunique orNOT NULLtosuityourspecificapplication.Anexampleofacheckconstraintmightbetoensurethat thevalueofaphonenumberfieldisatleastsevencharacterslong.Todothis,youcanaddtheconstraint tothecolumndefinitionofphoneorasastand-aloneconstraintinthetabledefinitionasfollows: create table contacts ( id integer primary key, name text not null collate nocase, phone text not null default 'UNKNOWN', unique (name,phone), check (length(phone)>=7) ); Here,anyattempttoinsertorupdateavalueforphonelessthansevencharacterswillresultina constraintviolation.Youcanuseanyexpressioninacheckconstraintthatyouwouldinawhereclause, withtheexceptionofsubqueries.Forexample,sayyouhavethetablefoodefinedasfollows: create table foo ( x integer, y integer check (y>x), z integer check (z>abs(y)) ); Inthistable,everyvalueofzmustalwaysbegreaterthany,whichinturnmustbegreaterthanx.To showillustratethis,trythefollowing: insert into foo values (-2, -1, 2); insert into foo values (-2, -1, 1); SQL error: constraint failed update foo set y=-3 where x=-3; SQL error: constraint failed Thecheckconstraintsforallcolumnsareevaluatedbeforeanymodificationismade.Forthe modificationtosucceed,theexpressionsforallconstraintsmustevaluatetotrue. 99 CHAPTER4■ADVANCEDSQLFORSQLITE Functionally,triggerscanbeusedjustaseffectivelyascheckconstraintsfordataintegrity.Infact, triggerscandomuchmore.Ifyoufindthatyoucan’tquiteexpresswhatyouneedinacheckconstraint, thentriggersareagoodalternative.Triggersarecoveredlaterinthischapterinthesection“Triggers.” Foreign Key Constraints SQLitesupportstheconceptofrelationalintegrityfromrelationaltheory.Likemostdatabases,it supportsthisthroughthemechanismofforeignkeyconstraints.Relationalintegrity,andbyextension foreignkeys,ensuresthatwhereakeyvalueinonetablelogicallyreferstodatainanothertable,thedata intheothertableactuallyexists.Classicexamplesareparent-childrelationships,master-detail relationshipsforthingssuchasordersandlineitems,andevenepisode-foodrelationships. SQLitesupportsforeignkeycreationinthecreate tablestatementusingthefollowingsyntax (simplifiedhereforeasyreading): create table table_name ( column_definition references foreign_table (column_name) on {delete|update} integrity_action [not] deferrable [initially {deferred|immediate}, ] … ); Thatsyntaxlooksdaunting,butinrealityitcanbebrokendownintothreebasiccomponents.Let’s usearealexampleoffoodsdatabase.Thefoodsandfood_typestablesarecurrentlydefinedasfollows: CREATE TABLE food_types( id integer primary key, name text ); CREATE TABLE foods( id integer primary key, type_id integer, name text ); Weknoweachfood_typehasanidthatuniquelyidentifiesit(seetheearlierdiscussiononprimary keys).Thefoodstableusesthetype_idcolumntoreferencefoodsinthefood_typestable.Ifyouwantto usereferentialintegritytohaveSQLiteprotectyourdataandensurethattherealwaysexistsafoodtype foranyreferenceofafood,thenyoucancreatethefoodstablelikethisinstead: create table foods( id integer primary key, type_id integer references food_types(id) on delete restrict deferrable initially deferred, name text ); Thedifferencesareshowninboldandareeasytounderstandiftakenoneatatime.Thefirstpartof theforeignkeyinstructsSQLitethatthetype_idcolumnreferencestheidcolumnofthefood_types table.Fromthere,youmoveontotheintegrityactionclause,whichdoesmostofthehardwork.Inthis example,you’veusedtheoptionon delete restrict.ThisinstructsSQLitetopreventanydeletionfrom thefood_typestablethatwouldleaveafoodinthefoodstablewithoutaparentfoodid.restrictisone offivepossibleactionsyoucandefine.Thefullsetisasfollows: 100 CHAPTER4■ADVANCEDSQLFORSQLITE set null:ChangeanyremainingchildvaluetoNULLiftheparentvalueis removedorchangedtonolongerexist. set default:Changeanyremainingchildvaluetothecolumndefaultifthe parentvalueisremovedorchangedtonolongerexist. cascade:Wheretheparentkeyisupdated,updateallchildkeystomatch. Whereitisdeleted,deleteallchildrowswiththekey.Payparticularattentionto thisoption,becausecascadingdeletescansurpriseyouwhenyouleastexpect them. restrict:Wheretheupdateordeleteoftheparentkeywouldresultin orphanedchildkeys,prevent(abort)thetransaction. no action:Takealaid-backapproach,andwatchchangesflybywithout intervening.Onlyattheendoftheentirestatement(ortransactionifthe constraintisdeferred)isanerrorraised. Lastly,SQLitesupportsthedeferrableclause,whichcontrolswhethertheconstraintasdefinedwill beenforcedimmediatelyordeferreduntiltheendofthetransaction. Collations Collationreferstohowtextvaluesarecompared.Differentcollationsemploydifferentcomparison methods.Forexample,onecollationmightbecaseinsensitive,sothestrings'JujyFruit'and 'JUJYFRUIT'areconsideredthesame.Anothercollationmightbecasesensitive,inwhichcasethe stringswouldbeconsidereddifferent. SQLitehasthreebuilt-incollations.Thedefaultisbinary,whichcomparestextvaluesbytebybyte usingaspecificCfunctioncalledmemcmp().ThishappenstoworknicelyformanyWesternlanguages suchasEnglish.nocaseisbasicallyacase-insensitivecollationforthe26ASCIIcharactersusedinLatin alphabets.Finallythereisreverse,whichisthereverseofthebinarycollation.Reverseismorefor testing(andperhapsillustration)thananythingelse. TheSQLiteCAPIprovidesawaytocreatecustomcollations.Thisfeatureallowsdevelopersto supportlanguagesand/orlocalesthatarenotwellservedbythebinarycollation.SeeChapter7formore information. Thecollatekeyworddefinesthecollationforacolumn.Forexample,thecollationfor contacts.nameisdefinedasnocase,whichmeansthatitiscaseinsensitive.Thus,ifyoutrytoinsert anotherrowwithanamevalueof'JERRY'andaphonevalueof'555-1212',itshouldfail: sqlite> insert into contacts (name,phone) values ('JERRY','555-1212'); SQL error: columns name, phone are not unique Accordingtoname’scollation,'JERRY'isthesameas'Jerry',andthereisalreadyarowwiththatvalue. Therefore,anewrowwithname='JERRY'wouldbeaduplicatevalue.Bydefault,collationinSQLiteis casesensitive.Thepreviousexamplewouldhaveworkedhadwenotdefinednocaseonname. StorageClasses Asmentionedearlier,SQLitedoesnotworklikeotherdatabaseswhenitcomestohandlingdatatypes.It differsinthetypesitsupportsandinhowtheyarestored,compared,enforced,andassigned.I’llcover thebasicsofSQLitestorageclassesnexttogiveyouagoodworkingknowledge.InChapter11,Iwill 101 CHAPTER4■ADVANCEDSQLFORSQLITE addressmanyoftheinternalsofSQLite’sradicallydifferentbutsurprisinglyflexibleapproachtodata types. Internally,SQLitehasfiveprimitivedatatypes,whicharereferredtoasstorageclasses.Theterm storageclassreferstotheformatinwhichavalueisstoredondisk.Regardless,itisstillsynonymouswith type,ordatatype.Table4-1describesthefivestorageclasses. Table4-1.SQLiteStorageClasses Name Description integer Integervaluesarewholenumbers(positiveandnegative).Theycanvaryinsize:1,2,3,4,6, or8bytes.Themaximumintegerrange(8bytes)is{-9223372036854775808,-1,0,1, 9223372036854775807}.SQLiteautomaticallyhandlestheintegersizesbasedonthe numericvalue. real Realvaluesarerealnumberswithdecimalvalues.SQLiteuses8-bytefloatstostorereal numbers. text Textischaracterdata.SQLitesupportsvariouscharacterencodings,whichincludeUTF-8 andUTF-16(bigandlittleendian).ThemaximumstringvalueinSQLiteisadjustableat compiletimeandatruntimeanddefaultsto1,000,000,000bytes. blob Binarylargeobject(BLOB)dataisanykindofdata.ThemaximumsizeforBLOBsinSQLiteis adjustableatcompiletimeandatruntimeanddefaultsto1,000,000,000bytes. NULL NULLrepresentsmissinginformation.SQLitehasfullsupportforNULLhandling. SQLiteinfersavalue’stypefromitsrepresentation.Thefollowinginferencerulesareusedtodothis: • AvaluespecifiedasaliteralinSQLstatementsisassignedclasstextifitis enclosedbysingleordoublequotes. • Avalueisassignedclassintegeriftheliteralisspecifiedasanunquotednumber withnodecimalpointorexponent. • Avalueisassignedclassrealiftheliteralisanunquotednumberwithadecimal pointoranexponent. • AvalueisassignedclassNULLifitsvalueisNULL. • Avalueisassignedclassblobifitisoftheformatx'ABCD',whereABCDare hexadecimalnumbers.Thexprefixandvaluescanbeeitheruppercaseor lowercase. Thetypeof()SQLfunctionreturnsthestorageclassofavaluebasedonitsrepresentation.Usingthis function,thefollowingSQLillustratestypeinferenceinaction: 102 CHAPTER4■ADVANCEDSQLFORSQLITE sqlite> select typeof(3.14), typeof('3.14'), typeof(314), typeof(x'3142'), typeof(NULL); typeof(3.14) -----------real typeof('3.14') -------------text typeof(314) ----------integer typeof(x'3142') --------------blob typeof(NULL) -----------null Hereareallofthefiveinternalstorageclassesinvokedbyspecificrepresentationsofdata.Thevalue3.14 lookslikearealandthereforeisareal.Thevalue'3.14'looksliketextandthereforeistext,andsoon. AsinglecolumninSQLitemaycontaindifferentvaluesofdifferentstorageclasses.Thisisthefirst differenceinSQLitedatahandlingthatusuallymakesthosefamiliarwithotherdatabasessitupandsay, “What?”Considerthefollowingexample: sqlite> sqlite> sqlite> sqlite> sqlite> sqlite> sqlite> sqlite> drop table domain; create table domain(x); insert into domain values (3.142); insert into domain values ('3.142'); insert into domain values (3142); insert into domain values (x'3142'); insert into domain values (null); select rowid, x, typeof(x) from domain; rowid ---------1 2 3 4 5 x ---------3.142 3.142 3142 1B NULL typeof(x) ---------real text integer blob null Thisraisesafewquestions.Howarethevaluesinacolumnsortedorcompared?Howdoyousorta columnwithinteger,real,text,blob,andNULLvalues?Howdoyoucompareanintegerwithablob? Whichisgreater?Cantheyeverbeequal? Asitturnsout,valuesinacolumnwithdifferentstoragesclassescanbesorted.Andtheycanbe sortedbecausetheycanbecompared.SQLiteimplementswell-definedrulestodoso.Storageclasses aresortedbyusingtheirrespectiveclassvalues,whicharedefinedasfollows: 1. TheNULLstorageclasshasthelowestclassvalue.AvaluewithaNULLstorage classisconsideredlessthananyothervalue(includinganothervaluewith storageclassNULL).WithinNULLvalues,thereisnospecificsortorder. 2. integerorrealstorageclasseshavehighervaluethanNULLsandshareequal classvalue.integerandrealvaluesarecomparednumerically. 3. Thetextstorageclasshashighervaluethanintegerorreal.Avaluewithan integerorarealstorageclasswillalwaysbelessthanavaluewithatext storageclassnomatteritsvalue.Whentwotextvaluesarecompared,the comparisonisdeterminedbythecollationdefinedforthevalues. 4. Theblobstorageclasshasthehighestvalue.Anyvaluethatisnotofclassblob willalwaysbelessthanavalueofclassblob.blobvaluesarecomparedusing theCfunctionmemcmp(). 103 CHAPTER4■ADVANCEDSQLFORSQLITE WhenSQLitesortsacolumn,itfirstgroupsvaluesaccordingtostorageclass—firstNULLs,then integersandreals,nexttext,andfinallyblobs.Itthensortsthevalueswithineachgroup.NULLsarenot orderedatall,integersandrealsarecomparednumerically,textisarrangedbytheappropriate collation,andblobsaresortedusingmemcmp(),effectivelycomparingtheminabitwisefashion.Figure41illustratesahypotheticalcolumnsortedinascendingorder. NULL NULL NULL NULL -1 INTEGER, REAL 1. 1 10 1.299E9 1 TEXT Cheerios JujyFruit x 0003 BLOB x 000e Figure4-1.Storageclasssortorder It’sprobablyworthreadingthissectionagainonceyou’vehadachancetopracticesomeSQLusing SQLite’sstorageclasses,justtoreinforcethisparticularaspectofSQLite.You’llreturntothistopicin Chapter11,whenyou’lldelveintotheinternalsofstorageclasses,manifesttyping,typeaffinity,and otherunder-the-hoodtopicsrelatedtotypesandstorageclasses. Views Viewsarevirtualtables.Theyarealsoknownasderivedtables,becausetheircontentsarederivedfrom theresultsofqueriesonothertables.Althoughviewslookandfeellikebasetables,theyaren’t.The contentsofbasetablesarepersistent,whereasthecontentsofviewsaredynamicallygeneratedwhen theyareused.Thesyntaxtocreateaviewisasfollows: create view name as select-stmt; Thenameoftheviewisgivenbynameanditsdefinitionbyselect-stmt.Theresultingviewwilllooklike abasetablenamedname.Imagineyouhadaqueryyouranallthetime,somuchthatyougetsickof writingit.Viewsarethesolutionforthisparticularchore.Sayyourquerywasasfollows: 104 CHAPTER4■ADVANCEDSQLFORSQLITE select f.name, ft.name, e.name from foods f inner join food_types ft on f.type_id=ft.id inner join foods_episodes fe on f.id=fe.food_id inner join episodes e on fe.episode_id=e.id; Thisreturnsthenameofeveryfood,itstype,andeveryepisodeitwasin.Itisonebigtableof504rows withjustabouteveryfoodfact.Ratherthanhavingtowriteout(orremember)thepreviousqueryevery timeyouwanttheseresults,youcantidilyrestateitintheformofaview.Let’snameitdetails: create view details as select f.name as fd, ft.name as tp, e.name as ep, e.season as ssn from foods f inner join food_types ft on f.type_id=ft.id inner join foods_episodes fe on f.id=fe.food_id inner join episodes e on fe.episode_id=e.id; Nowyoucanquerydetailsjustasyouwouldatable.Here’sanexample: sqlite> select fd as Food, ep as Episode from details where ssn=7 and tp like 'Drinks'; Food -------------------Apple Cider Bosco Cafe Latte Cafe Latte Champagne Coolies Cider Hershey's Hot Coffee Latte Mellow Yellow soda Merlot Orange Juice Tea Wild Turkey Episode -------------------The Bottle Deposit 1 The Secret Code The Postponement The Maestro The Wig Master The Bottle Deposit 2 The Secret Code The Maestro The Maestro The Bottle Deposit 1 The Rye The Wink The Hot Tub The Hot Tub Thecontentsofviewsaredynamicallygenerated.Thus,everytimeyouusedetails,itsassociatedSQL willbereexecuted,producingresultsbasedonthedatainthedatabaseatthatmoment.Somefeaturesof viewsavailableinotherdatabases,likeview-basedsecurity,arenotgenerallyavailable.SomeviewbasedsecurityisavailableifyouprogramwithSQLite,usingitsoperationalcontrolfacilities.Thisis coveredinChapters5and6. 105 CHAPTER4■ADVANCEDSQLFORSQLITE Finally,todropaview,usetheDROP VIEWcommand: drop view name; Thenameoftheviewtodropisgivenbyname. UPDATABLE VIEWS Therelationalmodelcallsforupdatableviews.Theseareviewsthatyoucanmodify.Youcanruninsert orupdatestatementsonthem,forexample,andtherespectivechangesareapplieddirectlytotheir underlyingtables.UpdatableviewsarenotsupportedinSQLite.However,usingtriggers,youcancreate somethinglikethem.Weshowthetechniquelaterinthesection“Triggers.” Indexes Indexesareaconstructdesignedtospeedupqueriesundercertainconditions.Considerthefollowing query: SELECT * FROM foods WHERE name='JujyFruit'; Whenadatabasesearchesformatchingrows,thedefaultmethoditusestoperformthisiscalleda sequentialscan.Thatis,itliterallysearches(orscans)everyrowinthetabletoseewhetheritsname attributematches'JujyFruit'. However,ifthisqueryisusedfrequentlyandthefoodstableisverylarge,itmakesfarmoresenseto useanindexapproachtofindingthedata.SQLiteusesB-treeindexes,similartomanyotherrelational databases. Indexesalsoincreasethesizeofthedatabase.Theyliterallykeepacopyofallcolumnstheyindex.If youindexeverycolumninatable,youeffectivelydoublethesizeofthetable.Anotherconsiderationis thatindexesmustbemaintained.Whenyouinsert,update,ordeleterecords,inadditiontomodifying thetable,thedatabasemustmodifyeachandeveryindexonthattableaswell.Soalthoughindicescan makequeriesrunmuchfaster,theycanslowdowninserts,updates,andsimilaroperations. Thecommandtocreateanindexisasfollows: create index [unique] index_name on table_name (columns) Thevariableindex_nameisthenameoftheindex,andtable_nameisthenameofthetablecontainingthe column(s)toindex.Thevariablecolumnsiseitherasinglecolumnoracomma-separatedlistofcolumns. Ifyouusetheuniquekeyword,thentheindexwillhavetheaddedconstraintthatallvaluesinthe indexmustbeunique.Thisappliestoboththeindexand,byextension,tothecolumnorcolumnsit indexes.Theuniqueconstraintcoversallcolumnsdefinedintheindex,anditistheircombinedvalues (notindividualvalues)thatmustbeunique.Here’sanexample: sqlite> create table foo(a text, b text); sqlite> create unique index foo_idx on foo(a,b); sqlite> insert into foo values ('unique', 'value'); 106 CHAPTER4■ADVANCEDSQLFORSQLITE sqlite> insert into foo values ('unique', 'value2'); sqlite> insert into foo values ('unique', 'value'); SQL error: columns a, b are not unique Youcanseeherethatuniquenessisdefinedbybothcolumnscollectively,notindividually.Noticethat collationplaysanimportantrolehereaswell. Toremoveanindex,usethedrop indexcommand,whichisdefinedasfollows: drop index index_name; Collations Eachcolumnintheindexcanhaveacollationassociatedwithit.Forexample,tocreateacaseinsensitiveindexonfoods.name,you’dusethefollowing: create index foods_name_idx on foods (name collate nocase); Thismeansthatvaluesinthenamecolumnwillsortwithoutrespecttocase.Youcanlisttheindexesfora tableintheSQLitecommand-lineprogrambyusingthe.indicesshellcommand.Here’sexample: sqlite> .indices foods foods_name_idx For more information, you can use the .schema shell command as well: sqlite> .schema foods CREATE TABLE foods( id integer primary key, type_id integer, name text ); CREATE INDEX foods_name_idx on foods (name COLLATE NOCASE); Youcanalsoobtainthisinformationbyqueryingthesqlite_mastertable,describedlaterinthissection. Index Utilization Itisimportanttounderstandwhenindexesareusedandwhentheyaren’t.Thereareveryspecific conditionsinwhichSQLitewilldecidetouseanindex.SQLitewilluseasinglecolumnindex,ifavailable, forthefollowingexpressionsintheWHEREclause: column {=|>|>=|=|1expressionbecomestherightmostindexcolumn becauseitusestheinequality.Allcolumnsafteritarenoteligibletobeusedasaresult.Similarly,the following: select * from foo where a=1 and b>2 and c=3 and d=4 willusetheindexcolumnsaandbandstopthereasb>2becomestherightmostindextermbyitsuseof aninequalityoperator. Lastly,whenyoucreateanindex,haveareasonforcreatingit.Makesurethereisaspecific performancegainyouaregettingbeforeyoutakeontheoverheadthatcomeswithit.Well-chosen indexesareawonderfulthing.Indexesthatarethoughtlesslyscatteredhereandthereinthevainhopeof performanceareofdubiousvalue. Triggers TriggersexecutespecificSQLcommandswhenspecificdatabaseeventstranspireonspecifictables.The generalsyntaxforcreatingatriggerisasfollows: create [temp|temporary] trigger name [before|after] [insert|delete|update|update of columns] on table action Atriggerisdefinedbyaname,anaction,andatable.Theaction,ortriggerbody,consistsofaseries ofSQLcommands.Triggersaresaidtofirewhensucheventstakeplace.Furthermore,triggerscanbe madetofirebeforeoraftertheeventusingthebeforeorafterkeyword,respectively.Eventsinclude delete,insert,andupdatecommandsissuedonthespecifiedtable.Triggerscanbeusedtocreateyour ownintegrityconstraints,logchanges,updateothertables,andmanyotherthings.Theyarelimitedonly bywhatyoucanwriteinSQL. 108 CHAPTER4■ADVANCEDSQLFORSQLITE Update Triggers Updatetriggers,unlikeinsertanddeletetriggers,maybedefinedforspecificcolumnsinatable.The generalformofthiskindoftriggerisasfollows: create trigger name [before|after] update of column on table action ThefollowingisaSQLscriptthatshowsanUPDATEtriggerinaction: create temp table log(x); create temp trigger foods_update_log update of name on foods begin insert into log values('updated foods: new name=' || new.name); end; begin; update foods set name='JUJYFRUIT' where name='JujyFruit'; select * from log; rollback; Thisscriptcreatesatemporarytablecalledlog,aswellasatemporaryupdatetriggeronfoods.namethat insertsamessageintologwhenitfires.Theactiontakesplaceinsidethetransactionthatfollows.The firststepofthetransactionupdatesthenamecolumnoftherowwhosenameis'JUJYFRUIT'.Thiscauses theupdatetriggertofire.Whenitfires,itinsertsarecordintothelog.Next,thetransactionreadsthelog, whichshowsthatthetriggerdidindeedfire.Thetransactionthenrollsbackthechange,andwhenthe sessionends,thelogtableandtheupdatetriggeraredestroyed.Runningthescriptproducesthe followingoutput: # sqlite3 foods.db < trigger.sql create temp table log(x); create temp trigger foods_update_log after update of name on foods begin insert into log values('updated foods: new name=' || new.name); end; begin; update foods set name='JUJYFRUIT' where name='JujyFruit'; SELECT * FROM LOG; x -------------------------------------------------updated foods: new name=JUJYFRUIT rollback; 109 CHAPTER4■ADVANCEDSQLFORSQLITE SQLiteprovidesaccesstoboththeold(original)rowandthenew(updated)rowinupdatetriggers. Theoldrowisreferredtoasoldandthenewrowasnew.Noticeinthescripthowthetriggerrefersto new.name.Allattributesofbothrowsareavailableinoldandnewusingthedotnotation.Youcouldhave justaseasilyrecordednew.type_idorold.id. Error Handling Definingatriggerbeforeaneventtakesplacegivesyoutheopportunitytostoptheeventfrom happeningand,equally,examiningtheeventafterwardallowsyoutohavesecondthoughts.beforeand aftertriggersenableyoutoimplementnewintegrityconstraints.SQLiteprovidesaspecialSQLfunction fortriggerscalledraise(),whichallowsthemtoraiseanerrorwithinthetriggerbody.raiseisdefined asfollows: raise(resolution, error_message); Thefirstargumentisaconflictresolutionpolicy(abort,fail,ignore,rollback,andsoon).Thesecond argumentisanerrormessage.Ifyouuseignore,theremainderofthecurrenttriggeralongwiththeSQL statementthatcausedthetriggertofire,aswellasanysubsequenttriggersthatwouldhavebeenfired, areallterminated.IftheSQLstatementthatcausedthetriggertofireisitselfpartofanothertrigger,then thattriggerresumesexecutionatthebeginningofthenextSQLcommandinthetriggeraction. Updatable Views Triggersmakeitpossibletocreatesomethinglikeupdatableviews,asmentionedearlierinthischapter. Theideahereisthatyoucreateaviewandthencreateatriggerthathandlesupdateeventsonthatview. SQLitesupportstriggersonviewsusingtheinsteadofkeywordsinthetriggerdefinition.Toillustrate this,let’screateaviewthatcombinesfoodswithfood_types: create view foods_view as select f.id fid, f.name fname, t.id tid, t.name tname from foods f, food_types t; Thisviewjoinsthetwotablesaccordingtotheirforeignkeyrelationship.Noticethatyouhavecreated aliasesforallcolumnnamesintheview.Thisallowsyoutodifferentiatetherespectiveidandname columnsineachtablewhenyoureferencethemfrominsidethetrigger.Now,let’smaketheview updatablebycreatinganUPDATEtriggeronit: create trigger on_update_foods_view instead of update on foods_view for each row begin update foods set name=new.fname where id=new.fid; update food_types set name=new.tname where id=new.tid; end; Nowifyoutrytoupdatethefoods_view,thistriggergetscalled.Thetriggersimplytakesthevalues providedintheUPDATEstatementandusesthemtoupdatetheunderlyingbasetablesfoodsand food_types.Testingityieldsthefollowing: 110 CHAPTER4■ADVANCEDSQLFORSQLITE .echo on -- Update the view within a transaction begin; update foods_view set fname='Whataburger', tname='Fast Food' where fid=413; -- Now view the underlying rows in the base tables: select * from foods f, food_types t where f.type_id=t.id and f.id=413; -- Roll it back rollback; -- Now look at the original record: select * from foods f, food_types t where f.type_id=t.id and f.id=413; begin; update foods_view set fname='Whataburger', tname='Fast Food' where fid=413; select * from foods f, food_types t where f.type_id=t.id and f.id=413; id type_id name id name --- ------- -------------- --- --------413 1 Whataburger 1 Fast Food rollback; select * from id type_id --- ------413 1 foods f, food_types t where f.type_id=t.id and f.id=413; name id name -------------- --- ------Cinnamon Bobka 1 Bakery Youcanjustaseasilyaddinsertanddeletetriggerstocompletethetriggerbasedmanipulationof dataviaviews. Transactions TransactionsdefineboundariesaroundagroupofSQLcommandssuchthattheyeitherallsuccessfully executetogetherornotatall.Thisistypicallyreferredtoastheatomicprincipleofdatabaseintegrity.A classicexampleoftherationalebehindtransactionsisamoneytransfer.Sayabankprogramis transferringmoneyfromoneaccounttoanother.Themoneytransferprogramcandothisinoneoftwo ways:firstinsert(credit)thefundsintoaccount2andthendelete(debit)itfromaccount1,orfirstdelete itfromaccount1andinsertitintoaccount2.Eitherway,thetransferisatwo-stepprocess:aninsert followedbyadelete,oradeletefollowedbyaninsert. Butwhathappensif,duringthetransfer,thedatabaseserversuddenlycrashesorthepowergoes out,andthesecondoperationdoesnotcomplete?Nowthemoneyeitherexistsinbothaccounts(the firstscenario)orhasbeencompletelylostaltogether(secondscenario).Eitherway,someoneisnot goingtobehappy.Andthedatabaseisinaninconsistentstate.Thepointhereisthatthesetwo operationsmusteitherhappentogetherornotatall.Thatistheessenceoftransactions. TransactionScopes Transactionsareissuedwiththreecommands:begin,commit,androllback.beginstartsatransaction. Everyoperationfollowingabegincanbepotentiallyundoneandwillbeundoneifacommitisnotissued 111 CHAPTER4■ADVANCEDSQLFORSQLITE beforethesessionterminates.Thecommitcommandcommitstheworkperformedbyalloperations sincethestartofthetransaction.Similarly,therollbackcommandundoesalltheworkperformedbyall operationssincethestartofthetransaction.Atransactionisascopeinwhichoperationsareperformed andcommitted,orrolledback,together.Hereisanexample: sqlite> sqlite> sqlite> sqlite> begin; delete from foods; rollback; select count(*) from foods; count(*) -------412 Westartedatransaction,deletedalltherowsinfoods,changedourmind,andreversedthosechangesby issuingarollback.Theselectstatementshowsthatnothingwaschanged. Bydefault,everySQLcommandinSQLiteisrununderitsowntransaction.Thatis,ifyoudonot defineatransactionscopewithbegin…commit/rollback,SQLitewillimplicitlywrapeveryindividualSQL commandwithabegin…commit/rollback.Inthatcase,everycommandthatcompletessuccessfullyis committed.Likewise,everycommandthatencountersanerrorisrolledback.Thismodeofoperation (implicittransactions)isreferredtoasautocommitmode:SQLiteautomaticallyrunseachcommandin itsowntransaction,andifthecommanddoesnotfail,itschangesareautomaticallycommitted. SQLitealsosupportsthesavepointandreleasecommands.Thesecommandsextendtheflexibility oftransactionssothatabodyofworkthatincorporatesmultiplestatementscansetasavepoint,which SQLitecanthenreverttointheeventofarollback.Creatingasavepointisasimpleasissuingthe savepointcommandwithanameofyourchoice,justasinthisnextexample: savepoint justincase; Later,ifwerealizeourprocessingneedstobereverted,insteadofrollingallthewaybacktothestart ofthetransaction,wecanuseanamedrollbackasfollows: rollback [transaction] to justincase; I’vechosenjustincaseasthesavepointname.Youcanchooseanynameyoulike. ConflictResolution Asyou’veseeninpreviousexamples,constraintviolationscausethecommandthatcommittedthe violationtoterminate.Whatexactlyhappenswhenacommandterminatesinthemiddleofmakinga bunchofchangestothedatabase?Inmostdatabases,allofthechangesareundone.Thatisthewaythe databaseisprogrammedtohandleaconstraintviolation—endofstory. SQLite,however,hasanuncommonfeaturethatallowsyoutospecifydifferentwaystohandle(or recoverfrom)constraintviolations.Itiscalledconflictresolution.Take,forexample,thefollowing UPDATE: sqlite> update foods set id=800-id; SQL error: PRIMARY KEY must be unique ThisresultsinaUNIQUEconstraintviolationbecauseoncetheupdatestatementreachesthe388threcord, itattemptstoupdateitsidvalueto800-388=412.Butarowwithanidof412alreadyexists,soitaborts thecommand.ButSQLitealreadyupdatedthefirst387rowsbeforeitreachedthisconstraintviolation. 112 CHAPTER4■ADVANCEDSQLFORSQLITE Whathappenstothem?Thedefaultbehavioristoterminatethecommandandreverseallthechangesit made,whileleavingthetransactionintact. Butwhatifyouwantedthese387changestostickdespitetheconstraintviolation?Well,believeitor not,youcanhaveitthatwaytoo,ifyouwant.Youjustneedtousetheappropriateconflictresolution. Therearefivepossibleresolutions,orpolicies,thatcanbeappliedtoaddressaconflict(constraint violation): replace,ignore,fail,abort,androllback.Thesefiveresolutionsdefineaspectrumoferror toleranceorsensitivity:fromreplace,themostforgiving,torollback,themoststrict.Theresolutionsare definedasfollowsinorderoftheirseverity: 1. replace:Whenauniqueconstraintviolationisencountered,SQLiteremoves therow(orrows)thatcausedtheviolationandreplacesit(them)withthenew rowfromtheinsertorupdate.TheSQLoperationcontinueswithouterror.Ifa NOT NULLconstraintviolationoccurs,theNULLvalueisreplacedbythedefault valueforthatcolumn.Ifthecolumnhasnodefaultvalue,thenSQLiteapplies theabortpolicy.Itisimportanttonotethatwhenthisconflictresolution strategydeletesrowsinordertosatisfyaconstraint,itdoesnotinvokedelete triggersonthoserows.Thisbehavior,however,issubjecttochangeinafuture release. 2. ignore:Whenaconstraintviolationisencountered,SQLiteallowsthe commandtocontinueandleavestherowthattriggeredtheviolation unchanged.Otherrowsbeforeandaftertherowinquestioncontinuetobe modifiedbythecommand.Thus,allrowsintheoperationthattrigger constraintviolationsaresimplyleftunchanged,andthecommandproceeds withouterror. 3. fail:Whenaconstraintviolationisencountered,SQLiteterminatesthe commandbutdoesnotrestorethechangesitmadepriortoencounteringthe violation.Thatis,allchangeswithintheSQLcommanduptotheviolationare preserved.Forexample,ifanupdatestatementencounteredaconstraint violationonthe100throwitattemptstoupdate,thenthechangestothefirst 99rowsalreadymodifiedremainintact,butchangestorows100andbeyond neveroccurasthecommandisterminated. 4. abort:Whenaconstraintviolationisencountered,SQLiterestoresallchanges thecommandmadeandterminatesit.abortisthedefaultresolutionforall operationsinSQLite.ItisalsothebehaviordefinedintheSQLstandard.Asa sidenote,abortisalsothemostexpensiveconflictresolutionpolicy— requiringextraworkevenifnoconflictseveroccur. 5. rollback:Whenaconstraintviolationisencountered,SQLiteperformsa rollback—abortingthecurrentcommandalongwiththeentiretransaction. Thenetresultisthatallchangesmadebythecurrentcommandandall previouscommandsinthetransactionarerolledback.Thisisthemostdrastic levelofconflictresolutionwhereasingleviolationresultsinacomplete reversalofeverythingperformedinatransaction. ConflictresolutioncanbespecifiedwithinSQLcommandsaswellaswithintableandindex definitions.Specifically,conflictresolutioncanbespecifiedininsert,update,create table,andcreate index.Furthermore,ithasspecificimplicationswithintriggers.Thesyntaxforconflictresolutionin insertandupdateisasfollows: 113 CHAPTER4■ADVANCEDSQLFORSQLITE insert or resolution into table (column_list) values (value_list); update or resolution table set (value_list) where predicate; TheconflictresolutionpolicycomesrightaftertheinsertorupdatecommandandisprefixedwithOR. Also,theinsert or replaceexpressioncanbeabbreviatedasjustreplace.Thisissimilartoother database’s“merge”or“upsert”behavior. Intheprecedingupdateexample,theupdatesmadetothe387recordswererolledbackbecausethe defaultresolutionisabort.Ifyouwantedtheupdatestostick,youcouldusethefailresolution.To illustratethis,inthefollowingexampleyoucopyfoodsintoanewtabletestanduseitastheguineapig. Youaddanadditionalcolumntotestcalledmodified,thedefaultvalueofwhichis'no'.Intheupdate, youchangethisto'yes'totrackwhichrecordsareupdatedbeforetheconstraintviolationoccurs.Using thefailresolution,theseupdateswillremainunchanged,andyoucantrackafterwardhowmany recordswereupdated. create table test as select * from foods; create unique index test_idx on test(id); alter table test add column modified text not null default 'no'; select count(*) from test where modified='no'; count(*) -------------------412 update or fail test set id=800-id, modified='yes'; SQL error: column id is not unique select count(*) from test where modified='yes'; count(*) -------------------387 drop table test; ■CautionThereisoneconsiderationwithfailofwhichyouneedtobeaware.Theorderthatrecordsare updatedisnondeterministic.Thatis,youcannotbecertainoftheorderoftherecordsinthetableortheorderin whichSQLiteprocessesthem.Youmightassumethatitfollowstheorderoftherowidcolumn,butthisisnota safeassumptiontomake.Thereisnothinginthedocumentationthatsaysso.Onceagain,neverassumeany implicitorderingwhenworkingwithanykindofdatabase.Ifyouaregoingtousefail,inmanycasesitmightbe bettertouseignore.ignorewillfinishthejobandmodifyallrecordsthatcanbemodifiedratherthanbailingout onthefirstviolation. Whendefinedwithintables,conflictresolutionisspecifiedforindividualcolumns.Here’san example: 114 CHAPTER4■ADVANCEDSQLFORSQLITE sqlite> sqlite> sqlite> sqlite> create insert insert insert temp into into into table cast(name text unique on conflict rollback); cast values ('Jerry'); cast values ('Elaine'); cast values ('Kramer'); Thecasttablehasasinglecolumnnamewithauniqueconstraintandconflictresolutionsetto rollback.Anyinsertorupdatethattriggersaconstraintviolationonnamewillbearbitratedbythe rollbackresolutionratherthanthedefaultabort.Theresultwillabortnotonlythestatementbutthe entiretransactionaswell: sqlite> begin; sqlite> insert into cast values('Jerry'); SQL error: uniqueness constraint failed sqlite> commit; SQL error: cannot commit - no transaction is active commitfailedherebecausethename’sconflictresolutionalreadyabortedthetransaction.create index worksthesameway.Conflictresolutionwithintablesandindiceschangesthedefaultbehaviorofthe operationfromaborttothatdefinedforthespecificcolumnswhenthosecolumnsarethesourceofthe constraintviolation. Conflictresolutionatthestatementlevel(DML)overridesthatdefinedattheobjectlevel(DDL). Workingfromthepreviousexample: sqlite> begin; sqlite> insert or replace into cast values('Jerry'); sqlite> commit; thereplaceresolutionintheinsertoverridestherollbackresolutiondefinedoncast.name. DatabaseLocks LockingiscloselyassociatedwithtransactionsinSQLite.Tousetransactionseffectively,youneedto knowalittlesomethingabouthowitdoeslocking. SQLitehascoarse-grainedlocking.Whenasessioniswritingtothedatabase,allothersessionsare lockedoutuntilthewritingsessioncompletesitstransaction.Tohelpwiththis,SQLitehasalocking schemethathelpsdeferwriterlocksuntilthelastpossiblemomentinordertomaximizeconcurrency. WRITE-AHEAD LOGGING: THE FUTURE OF SQLITE Comingsooninversion3.7.0ofSQLiteiswrite-aheadlogging(WAL).Thiswillchangethebehaviorof transactionsandlockingtofreeSQLiteofthe“onewriter”behaviordescribedhere.Chapter11covers theseforthcomingchangestotheinternalsofSQLite. 115 CHAPTER4■ADVANCEDSQLFORSQLITE SQLiteusesalockescalationpolicywherebyaconnectiongraduallyobtainsexclusiveaccesstoa databaseinordertowritetoit.TherearefivedifferentlockingstatesinSQLite:unlocked,shared, reserved,pending,andexclusive.Eachdatabasesession(orconnection)canbeinonlyoneofthesestates atanygiventime.Furthermore,thereisacorrespondinglockforeachstate,exceptforunlocked—there isnolockrequiredtobeintheunlockedstate. Tobeginwith,themostbasicstateisunlocked.Inthisstate,nosessionisaccessingdatafromthe database.WhenyouconnecttoadatabaseoreveninitiateatransactionwithBEGIN,yourconnectionis intheunlockedstate. Thenextstatebeyondunlockedisshared.Forasessiontoreadfromthedatabase(notwrite),it mustfirstenterthesharedstateandmustthereforeacquireasharedlock.Multiplesessionscan simultaneouslyacquireandholdsharedlocksatanygiventime.Therefore,multiplesessionscanread fromacommondatabaseatanygiventime.However,nosessioncanwritetothedatabaseduringthis time—whileanysharedlocksareactive. Ifasessionwantstowritetothedatabase,itmustfirstacquireareservedlock.Onlyonereserved lockmaybeheldatonetimeforagivendatabase.Sharedlockscancoexistwithareservedlock.A reservedlockisthefirstphaseofwritingtoadatabase.Itdoesnotblocksessionswithsharedlocksfrom reading,anditdoesnotpreventsessionsfromacquiringnewsharedlocks. Onceasessionhasareservedlock,itcanbegintheprocessofmakingmodifications;however,these modificationsarecachedandnotactuallywrittentodisk.Thereader’schangesarestoredinamemory cache(seethediscussionofthecache_sizepragmainthesection“DatabaseConfiguration,”laterinthis chapter,formoreinformation). Whenthesessionwantstocommitthechanges(ortransaction)tothedatabase,itbeginsthe processofpromotingitsreservedlocktoanexclusivelock.Togetanexclusivelock,itmustfirstpromote itsreservedlocktoapendinglock.Apendinglockstartsaprocessofattritionwherebynonewshared lockscanbeobtained.Thatis,othersessionswithexistingsharedlocksareallowedtocontinueas normal,butothersessionscannotacquirenewsharedlocks.Atthispoint,thesessionwiththepending lockiswaitingfortheothersessionswithsharedlockstofinishwhattheyaredoingandreleasethem. Onceallsharedlocksarereleased,thesessionwiththependinglockcanpromoteittoanexclusive lock.Itisthenfreetomakechangestothedatabase.Allofthepreviouslycachedchangesarewrittento thedatabasefile. Deadlocks Althoughyoumayfindtheprecedingdiscussiononlockingtobeinteresting,youareprobably wonderingatthispointwhyanyofitmatters.Whydoyouneedtoknowaboutlocking?Well,ifyoudon’t knowwhatyouaredoing,youcanendupinadeadlock. ConsiderthefollowingscenarioillustratedinTable4-2.Twosessions,AandB—completely oblivioustooneanother—areworkingonthesamedatabaseatthesametime.SessionAissuesthefirst command,Bthesecondandthird,Athefourth,andsoon. 116 CHAPTER4■ADVANCEDSQLFORSQLITE Table4-2.APortraitofaDeadlock Session A Session B sqlite> begin; sqlite> begin; sqlite> insert into foo values ('x'); sqlite> select * from foo; sqlite> commit; SQL error: database is locked sqlite> insert into foo values ('x'); SQL error: database is locked Bothsessionswindupinadeadlock.SessionBwasthefirsttotrytowritetothedatabaseand thereforehasapendinglock.AattemptstowritebutfailswhenINSERTtriestopromoteitssharedlockto areservedlock. Forthesakeofargument,let’ssaythatAdecidestojustwaitaroundforthedatabasetobecome writable.SodoesB.Thenatthispoint,everyoneelseiseffectivelylockedouttoo.Ifyoutrytoopena thirdsession,itwon’tevenbeabletoreadfromthedatabase.ThereasonisthatBhasapendinglock, whichpreventsanysessionsfromacquiringsharedlocks.So,notonlyareAandBdeadlocked,theyhave lockedeveryoneelseoutofthedatabaseaswell.Basically,youhaveasharedlockandonependinglock thatdon’twanttorelinquishcontrol,anduntilonedoes,nobodycandoanything. Howdoyouavoidadeadlock?It’snotlikeAandBcansitdowninameetingandworkitoutwith theirlawyers.AandBdon’tevenknoweachotherexists.Theansweristopicktherighttransactiontype forthejob. TransactionTypes SQLitehasthreedifferenttransactiontypesthatstarttransactionsindifferentlockingstates. Transactionscanbestartedasdeferred,immediate,orexclusive.Atransaction’stypeisspecifiedinthe begincommand: begin [ deferred | immediate | exclusive ] transaction; Adeferredtransactiondoesnotacquireanylocksuntilithasto.Thus,withadeferredtransaction, thebeginstatementitselfdoesnothing—itstartsintheunlockedstate.Thisisthedefault.Ifyousimply issueabegin,thenyourtransactionisdeferredandthereforesittingintheunlockedstate.Multiple sessionscansimultaneouslystartdeferredtransactionsatthesametimewithoutcreatinganylocks.In thiscase,thefirstreadoperationagainstadatabaseacquiresasharedlock,andsimilarlythefirstwrite operationattemptstoacquireareservedlock. 117 CHAPTER4■ADVANCEDSQLFORSQLITE Animmediatetransactionattemptstoobtainareservedlockassoonasthebegincommandis executed.Ifsuccessful,begin immediateguaranteesthatnoothersessionwillbeabletowritetothe database.Asyouknow,othersessionscancontinuetoreadfromthedatabase,butthereservedlock preventsanynewsessionsfromreading.Anotherconsequenceofthereservedlockisthatnoother sessionswillbeabletosuccessfullyissueabegin immediateorbegin exclusivecommand.SQLitewill returnaSQLITE_BUSYerror.Duringthistime,youcanmakesomemodificationstothedatabase,butyou maynotnecessarilybeabletocommitthem.Whenyoucallcommit,youcouldgetSQLITE_BUSY.This meansthatthereareotherreadersactive,asintheearlierexample.Oncetheyaregone,youcancommit thetransaction. Anexclusivetransactionobtainsanexclusivelockonthedatabase.Thisworkssimilarlyto immediate,butwhenyousuccessfullyissueit,exclusiveguaranteesthatnoothersessionisactiveinthe databaseandthatyoucanreadorwritewithimpunity. Thecruxoftheproblemintheprecedingexampleisthatbothsessionsultimatelywantedtowriteto thedatabase,buttheymadenoattempttorelinquishtheirlocks.Ultimately,itwasthesharedlockthat causedtheproblem.Ifbothsessionshadstartedwithbegin immediate,thenthedeadlockwouldnot haveoccurred.Inthiscase,onlyoneofthesessionswouldhavebeenabletoenterbegin immediateat onetime,whiletheotherwouldhavetowait.Theonethathastowaitcouldkeepretryingwiththe assurancethatitwouldeventuallygetin.begin immediate andbegin exclusive,ifusedbyallsessions thatwanttowritetothedatabase,provideasynchronizationmechanism,therebypreventingdeadlocks. Forthisapproachtowork,though,everyonehastofollowtherules. Thebottomlineisthis:ifyouareusingadatabasethatnootherconnectionsareusing,thena simplebeginwillsuffice.If,however,youareusingadatabasethatotherconnectionsarealsowritingto, bothyou,andtheyshouldusebegin immediate orbegin exclusivetoinitiatetransactions.Itworksout bestthatwayforbothofyou.TransactionsandlocksarecoveredinmoredetailinChapter5. Database Administration Databaseadministrationisgenerallyconcernedwithcontrollinghowadatabaseoperates.Manyofthe databaseadministrationtasksyou’llwanttoperformaredoneviaSQLcommands.SQLiteincludes someuniqueadministrativefeaturesofitsown,suchthemeansto“attach”multipledatabasestoa singlesession,aswellasdatabasepragmas,whichcanbeusedforsettingvariousconfiguration parameters. AttachingDatabases SQLiteallowsyouto“attach”multipledatabasestothecurrentsessionusingtheattachcommand. Whenyouattachadatabase,allofitscontentsareaccessibleintheglobalscopeofthecurrentdatabase file.attachhasthefollowingsyntax: attach [database] filename as database_name; Here,filenamereferstothepathandnameoftheSQLitedatabasefile,anddatabase_namereferstothe logicalnamewithwhichtoreferencethatdatabaseanditsobjects.Themaindatabaseisautomatically assignedthenamemain.Ifyoucreateanytemporaryobjects,thenSQLitewillcreateanattached databasenametemp.(Youcanseetheseobjectsusingthedatabase_listpragma,describedlater.)The logicalnamemaybeusedtoreferenceobjectswithintheattacheddatabase.Iftherearetablesorother databaseobjectsthatsharethesamenameinbothdatabases,thenthelogicalnameisrequiredto referencesuchobjectsintheattacheddatabase.Forexample,ifbothdatabaseshaveatablecalledfoo, 118 CHAPTER4■ADVANCEDSQLFORSQLITE andthelogicalnameoftheattacheddatabaseisdb2,thentheonlywaytoqueryfooindb2isbyusingthe fullyqualifiednamedb2.foo,asfollows: sqlite> attach database '/tmp/db' as db2; sqlite> select * from db2.foo; x ---------bar Ifyoureallywantto,youcanqualifyobjectsinthemaindatabaseusingthenamemain: sqlite> select * from main.foods limit 2; id type_id name ---------- ---------- -------------1 1 Bagels 2 1 Bagels, raisin Thesameistruewiththetemporarydatabase: sqlite> create temp table foo as select * from food_types limit 3; sqlite> select * from temp.foo; id --1 2 3 name ------------Bakery Cereal Chicken/Fowl Youdetachdatabaseswiththedetach databasecommand,definedasfollows: detach [database] database_name; Thiscommandtakesthelogicalnameoftheattacheddatabase(givenbydatabase_name)and detachestheassociateddatabasefile.Yougetalistofattacheddatabasesusingthedatabase_list pragma,explainedinthesection“DatabaseConfiguration.” CleaningDatabases SQLitehastwocommandsdesignedforcleaning—reindexandvacuum.reindexisusedtorebuild indexes.Ithastwoforms: reindex collation_name; reindex table_name|index_name; Thefirstformrebuildsallindexesthatusethecollationnamegivenbycollation_name.Itisneededonly whenyouchangethebehaviorofauser-definedcollatingsequence(forexample,multiplesortordersin Chinese).Allindexesinatable(oraparticularindexgivenitsname)canberebuiltwiththesecondform. Vacuumcleansoutanyunusedspaceinthedatabasebyrebuildingthedatabasefile.Vacuumwillnot workifthereareanyopentransactions.AnalternativetomanuallyrunningVACUUMstatementsis autovacuum.Thisfeatureisenabledusingtheauto_vacuumpragma,describedinthenextsection. 119 CHAPTER4■ADVANCEDSQLFORSQLITE DatabaseConfiguration SQLitedoesn’thaveaconfigurationfile.Rather,allofitsconfigurationparametersareimplemented usingpragmas.Pragmasworkindifferentways.Somearelikevariables;othersarelikecommands.They covermanyaspectsofthedatabase,suchasruntimeinformation,databaseschema,versioning,file format,memoryuse,anddebugging.Somepragmasarereadandsetlikevariables,whileothersrequire argumentsandarecalledlikefunctions.Manypragmashavebothtemporaryandpermanentforms. Temporaryformsaffectonlythecurrentsessionforthedurationofitslifetime.Thepermanentformsare storedinthedatabaseandaffecteverysession.Thecachesizeisonesuchexample. Thissectioncoversthemostcommonlyusedpragmas.YoucanfindacompletelistofallSQLite pragmas. The Connection Cache Size Thecachesizepragmasinfluencehowmanydatabasepagesasessioncanholdinmemory.Tosetthe defaultcachesizeforthecurrentsession,youusethecache_sizepragma: sqlite> pragma cache_size; cache_size --------------2000 sqlite> pragma cache_size=10000; sqlite> pragma cache_size; cache_size --------------10000 Youcanpermanentlysetthecachesizeforallsessionsusingthedefault_cache_sizepragma.This settingisstoredinthedatabase.Thiswilltakeeffectonlyforsessionscreatedafterthechange,notfor currentlyactivesessions. Oneoftheusesforthecacheisinstoringpendingchangeswhenasessionisinareservedstate(it hasareservedlock),asdescribedearlierinthesection“Transactions.”Ifthesessionfillsupthecache,it willnotbeabletocontinuefurthermodificationsuntilitgetsanexclusivelock,whichmeansthatit mayhavetofirstwaitforreaderstoclear. Ifyouoryourprogramsperformmanyupdatesordeletesonadatabasethatisbeingusedbymany othersessions,itmayhelpyoutoincreasethecachesize.Thelargerthecachesize,themore modificationsasessioncancachechangebeforeithastogetanexclusivelock.Thisnotonlyallowsa sessiontogetmoreworkdonebeforehavingtowait,italsocutsdownonthetimetheexclusivelocks needstobeheld,becausealltheworkisdoneupfront.Inthiscase,theexclusivelockonlyneedstobe heldlongenoughtoflushthechangesinthecachetodisk.Sometipsfortuningthecachesizeare coveredinChapter5. Getting Database Information Youcanobtaindatabaseinformationusingthedatabaseschemapragmas,definedasfollows: 120 CHAPTER4■ADVANCEDSQLFORSQLITE • database_list:Listsinformationaboutallattacheddatabases. • index_info:Listsinformationaboutthecolumnswithinanindex.Ittakesanindex nameasanargument. • index_list:Listsinformationabouttheindexesinatable.Ittakesatablenameas anargument. • table_info:Listsinformationaboutallcolumnsinatable. Thefollowingillustratessomeinformationprovidedbythesepragmas: sqlite> pragma database_list; seq ---0 2 name ------main db2 file -------------------/tmp/foods.db /tmp/db sqlite> create index foods_name_type_idx on foods(name,type_id); sqlite> pragma index_info(foods_name_type_idx); seqn ---0 1 cid ------2 1 name -------------------name type_id sqlite> pragma index_list(foods); seq ----0 name unique ------------------- --------------foods_name_type_idx 0 sqlite> pragma table_info(foods); cid ----0 1 2 name --------------id type_id name type --------------integer integer text notn ---0 0 0 dflt ---- pk ---------1 0 0 Synchronous Writes Normally,SQLitecommitsallchangestodiskatcriticalmomentstoensuretransactiondurability.This issimilartothecheckpointfunctionalityinotherdatabases.However,itispossibletoturnthisofffor performancegains.Youdothiswiththesynchronouspragma.Therearethreesettings:full,normal,and off.Theyaredefinedasfollows: • Full:SQLitewillpauseatcriticalmomentstomakesurethatdatahasactually beenwrittentothedisksurfacebeforecontinuing.Thisensuresthatifthe operatingsystemcrashesorifthereisapowerfailure,thedatabasewillbe uncorruptedafterrebooting.Fullsynchronousisverysafe,butitisalsoslow. 121 CHAPTER4■ADVANCEDSQLFORSQLITE • Normal:SQLitewillstillpauseatthemostcriticalmomentsbutlessoftenthanin fullmode.Thereisaverysmall(thoughnonzero)chancethatapowerfailureat justthewrongtimecouldcorruptthedatabaseinnormalmode.Butinpractice, youaremorelikelytosufferacatastrophicdiskfailureorsomeother unrecoverablehardwarefault. • Off:SQLitecontinuesoperationwithoutpausingassoonasithashandeddataoff totheoperatingsystem.Thiscanspeedupsomeoperationsasmuchas50or moretimes.IftheapplicationrunningSQLitecrashes,thedatawillbesafe. However,iftheoperatingsystemcrashesorthecomputerlosespower,the databasemaybecorrupted. Thereisnopersistentformofthesynchronouspragma.Chapter5explainsthissetting’scrucialrolein transactiondurabilityandhowitworks. Temporary Storage TemporarystorageiswhereSQLitekeepstransientdatasuchastemporarytables,indexes,andother objects.Bydefault,SQLiteusesacompiled-inlocation,whichvariesbetweenplatforms.Therearetwo pragmasthatgoverntemporarystorage:temp_storeandtemp_store_directory.Thefirstpragma determineswhetherSQLiteusesmemoryordiskfortemporarystorage.Thereareactuallythreepossible values:default,file,ormemory.defaultusesthecompiled-indefault,fileusesanoperatingsystemfile, andmemoryusesRAM.Iffileissetasthestoragemedium,thenthesecondpragma, temp_store_directory,canbeusedtosetthedirectoryinwhichthetemporarystoragefileisplaced. Page Size, Encoding, and Autovacuum Thedatabasepagesize,encoding,andautovacuumingmustbesetbeforeadatabaseiscreated.Thatis, toalterthedefaults,youmustfirstsetthesepragmasbeforecreatinganydatabaseobjectsinanew database.Thedefaultsareapagesizederivedfromanumberofhost-specificfactorssuchasdisksector sizeandUTF-8encoding.SQLitesupportspagesizesrangingfrom512to32,786bytes,inpowersof2. SupportedencodingsareUTF-8,UTF-16le(little-endianUTF-16encoding),andUTF-16be(big-endian UTF-16encoding). Adatabase’ssizecanbeautomaticallykepttoaminimumusingtheauto_vacuumpragma.Normally, whenatransactionthatdeletesdatafromadatabaseiscommitted,thedatabasefileremainsthesame size.Whentheauto_vacuumpragmaisenabled,thedatabasefileshrinkswhenatransactionthatdeletes dataiscommitted.Tosupportthisfunctionality,thedatabasestoresextrainformationinternally, resultinginslightlylargerdatabasefilesthanwouldotherwisebepossible.Thevacuumcommandhasno effectondatabasesthatuseauto_vacuum. Debugging Therearefourpragmasforvariousdebuggingpurposes.Theintegrity_checkpragmalooksforout-oforderrecords,missingpages,malformedrecords,andcorruptedindexes.Ifanyproblemsarefound, thenasinglestringisreturneddescribingtheproblems.Ifeverythingisinorder,SQLitereturnsok.The otherpragmasareusedfortracingtheparserandvirtualdatabaseengineandcanbeenabledonlyif SQLiteiscompiledwithdebugginginformation.Youcanfinddetailedinformationonthesepragmasin Chapter11. 122 CHAPTER4■ADVANCEDSQLFORSQLITE TheSystemCatalog Thesqlite_mastertableisasystemtablethatcontainsinformationaboutallthetables,views,indexes, andtriggersinthedatabase.Forexample,thecurrentcontentsofthefoodsdatabaseareasfollows: sqlite> select type, name, rootpage from sqlite_master; type ---------table table table table index table trigger trigger trigger name ------------------------episodes foods foods_episodes food_types foods_name_idx sqlite_sequence foods_update_trg foods_insert_trg foods_delete_trg rootpage ---------2 3 4 5 30 50 0 0 0 Thetypecolumnreferstothetypeofobject,nameisofcoursethenameoftheobject,androotpagerefers tothefirstB-treepageoftheobjectinthedatabasefile.Thislattercolumnisrelevantonlyfortablesand indexes. Thesqlite_mastertablealsocontainsanothercolumncalledsql,whichstorestheDMLusedto createtheobject.Here’sanexample: sqlite> select sql from sqlite_master where name='foods_update_trg'; create trigger foods_update_trg before update of type_id on foods begin select case when (select id from food_types where id=new.type_id) is null then raise( abort, 'Foreign Key Violation: foods.type_id is not in food_types.id') end; end ViewingQueryPlans YoucanviewthewaySQLitegoesaboutexecutingaquerybyusingtheexplain query plancommand. Theexplain query plancommandliststhestepsSQLitecarriesouttoaccessandprocesstablesand datatosatisfyyourquery. Touseexplain query plan,justissuethecommandfollowedbyyournormalquerytext.For instance,here’swhatexplain query planhastosayabouthowaqueryonthefoodstableisprocessed: sqlite> explain query plan select * from foods where id = 145; order from detail ---------- ---------- ----------------------------0 0 TABLE foods USING PRIMARY KEY 123 CHAPTER4■ADVANCEDSQLFORSQLITE ThismeansthatSQLiteisaccessingthefoodstableandusingtheprimarykey(onid)toperformthe access(ratherthanscanningthetable’sdatainabrute-forcefashion). StudyingthesequeryplansisthekeytounderstandinghowSQLiteisapproachingyourdataand satisfyingyourquery.Youcanspotwhenandhowindicesareusedandtheorderinwhichtablesare usedinjoins.Thisisofimmensehelpwhentroubleshootinglong-runningqueriesandotherissues. Summary SQLmaybeasimplelanguagetouse,butthereisquiteabitofit,andit’stakenustwochaptersjustto introducethemajorconceptsforSQLite’simplementationofSQL.Butthatshouldn’tbetoosurprising, becauseitisthesoleinterfacethroughwhichtointeractwitharelationaldatabase.Whetheryouarea casualuser,systemadministrator,ordeveloper,youhavetoknowSQLifyouaregoingtoworkwitha relationaldatabase. IfyouareprogrammingwithSQLite,thenyoushouldbeofftoagoodstartontheSQLsideofthings. NowyouneedtoknowalittleabouthowSQLitegoesaboutexecutingallofthesecommands.Thisis whereChapter5shouldproveuseful.ItwillintroduceyoutotheAPIandshowyouhowitworksin relationtothewaySQLitefunctionsinternally. 124 CHAPTER 5 ■■■ SQLite Design and Concepts Thischaptersetsthestageforthefollowingchapters,eachofwhichfocusesonadifferentaspectof programmingwithSQLite.ItaddressesthethingsthatyouasaprogrammershouldknowaboutSQLite whenusingitinyourcode.WhetheryouareprogrammingwithSQLiteinitsnativeCorinyourfavorite scriptinglanguage,ithelpstounderstandnotonlyitsAPIbutalsoalittleaboutitsarchitectureand implementation.Armedwiththisknowledge,youwillbebetterequippedtowritecodethatrunsfaster andavoidspotentialpitfallssuchasdeadlocksorunexpectederrors.YouwillseehowSQLiteworksin relationtoyourcode,andyoucanbemoreconfidentthatyouareattackingtheproblemfromtheright direction. Youdon’thavetocombthroughthebowelsofthesourcecodetounderstandthesethings,andyou don’thavetobeaCprogrammer.SQLite’sdesignandconceptsareallverystraightforwardandeasyto understand.Andthereareonlyafewthingsyouneedtoknow.Thischapterlaysoutthemainconcepts andcomponentsonwhichtobuildyourunderstanding. KeytounderstandingSQLiteisknowinghowtheAPIworks.So,thischapterstartswithaconceptual introductiontotheAPI,illustratingitsmajordatastructures,itsgeneraldesign,anditsmajorfunctions. ItalsolooksatsomeofthemajorSQLitesubsystemsthatplayimportantrolesinqueryprocessing. Beyondjustknowingwhatfunctionsdowhat,we’llalsolookabovetheAPI,seeinghoweverything operatesintermsoftransactions.EverythinginvolvingaSQLitedatabaseisdonewithinthecontextofa transaction.ThenyouneedtolookbeneaththeAPI,seeinghowtransactionsworkintermsoflocks. Lockscancauseproblemsifyoudon’tknowhowtheyoperate.Byunderstandinglocks,notonlycanyou avoidpotentialconcurrencyproblems,butyoucanalsooptimizeyourqueriesbycontrollinghowyour programusesthem. Finally,youhavetounderstandhowallofthesethingsapplytowritingcode.Thelastpartofthe chapterbringsallthreetopics—theAPI,transactions,andlocks—togetherandlooksatdifferent examplesofgoodandbadcode.Itspecificallyidentifiesscenariosthatcouldcauseproblemsand providessomeinsightonhowtoaddressthem. Withthesethingsinorder,youwillbewellonyourwaytoconqueringtheCAPIandtheAPIofany languageextension. The API Functionally,theSQLiteAPIcanbeseparatedintotwogeneralparts:thecoreAPIandtheextensionAPI. ThecoreAPIconsistsallthefunctionsusedtoperformbasicdatabaseoperations:connectingtothe database,processingSQL,anditeratingthroughresults.Italsoincludesvariousutilityfunctionsthat helpwithtaskssuchasstringformatting,operationalcontrol,debugging,anderrorhandling.The 125 CHAPTER5■SQLITEDESIGNANDCONCEPTS extensionAPIoffersdifferentwaystoextendSQLitebycreatingyourownuser-definedSQLextensions, whichyoucanintegrateintoSQLite’sSQLdialect. ThePrincipalDataStructures AsyousawinChapter1,therearemanycomponentsinSQLite—parser,tokenizer,virtualmachine,and soon.Butfromaprogrammer’spointofview,themainthingstoknowaboutareconnections, statements,theB-tree,andthepager.Figure5-1showstheirrelationshipstooneanother.Theseobjects collectivelyaddressthethreeprincipalthingsyoumustknowaboutSQLitetowritegoodcode:theAPI, transactions,andlocks. Figure5-1.SQLiteCAPIobjectmodel Technically,theB-treeandpagerarenotpartoftheAPI;theyareoff-limits.Buttheyplayacritical roleintransactionsandlocks.Wewillexploretheirinvolvementinthesemattershereinthissectionand laterinthesection“Transactions.” Connections and Statements ThetwofundamentaldatastructuresintheAPIassociatedwithqueryprocessingaretheconnection andthestatement.Inmostlanguageextensions,youwillseebothaconnectionobjectandastatement object,whichareusedtoexecutequeries.IntheCAPI,theycorresponddirectlytothesqlite3and 126 CHAPTER5■SQLITEDESIGNANDCONCEPTS sqlite3_stmthandles,respectively.EverymajoroperationintheAPIisdoneusingoneofthesetwo structures. Aconnectionrepresentsasingleconnectiontoadatabaseaswellasasingletransactioncontext. Statementsarederivedfromconnections.Thatis,everystatementhasanassociatedconnectionobject. AstatementrepresentsasinglecompiledSQLstatement.Internally,itisexpressedintheformofVDBE bytecode—aprogramthatwhenexecutedwillcarryouttheSQLcommand.Statementscontain everythingneededtoexecuteacommand.TheyincluderesourcestoholdthestateoftheVDBEprogram asitisexecutedinastepwisefashion,B-treecursorsthatpointtorecordsondisk,andotherthingssuch asboundparameters,whichareaddressedlaterinthesection“ParameterBinding.”Althoughthey containmanydifferentthings,youcansimplythinkofthemascursorswithwhichtoiteratethrougha resultset,orasopaquehandlesreferencingasingleSQLcommand. The B-tree and Pager Eachconnectioncanhavemultipledatabaseobjects—onemaindatabasefollowedbyanyattached databases.EachdatabaseobjecthasoneB-treeobject,whichinturnhasonepagerobject. Statementsusetheirconnection’sB-treeandpagerobjectstoreadandwritedatatoandfromthe database.StatementsthatreadthedatabaseiterateoverB-treesusingcursors.Cursorsiterateover records,andrecordsarestoredinpages.Asacursortraversesrecords,italsotraversespages.Fora cursortoaccessapage,itmustfirstbeloadedfromdiskintomemory.Thisisthepager’sjob.Whenever theB-treeneedsaparticularpageinthedatabase,itasksthepagertofetchitfromdisk.Thepagerthen loadsthepageintoitspagecache,whichisamemorybuffer.Onceitisinthepagecache,theB-treeand itsassociatedcursorcangettotherecordsinsidethepage. Ifthecursormodifiesthepage,thenthepagermustalsotakespecialmeasurestopreservethe originalpageintheeventofatransactionrollback.Thus,thepagerisresponsibleforreadingandwriting toandfromthedatabase,maintainingamemorycacheorpages,andmanagingtransactions.In additiontothis,itmanageslocksandcrashrecovery.Alloftheseresponsibilitiesarecoveredlaterin “Transactions.” Therearetwothingsyoushouldknowaboutconnectionsandtransactionsingeneral.First,whenit comestoanyoperationonthedatabase,aconnectionalwaysoperatesunderatransaction.Second,a connectionneverhasmorethanonetransactionopenatatime.Thatmeansallstatementsderivedfrom agivenconnectionoperatewithinthesametransactioncontext.Ifyouwantthetwostatementstorun inseparatetransactions,thenyouhavetousemultipleconnections—oneconnectionforeach transactioncontext. TheCoreAPI Asmentionedearlier,thecoreAPIisconcernedwithexecutingSQLcommands.Itismadeofvarious functionsforperformingqueriesaswellasvariousutilityfunctionsformanagingotheraspectsofthe database.TherearetwoessentialmethodsforexecutingSQLcommands:preparedqueriesandwrapped queries.PreparedqueriesarethewayinwhichSQLiteultimatelyexecutesallcommands,bothintheAPI andinternally.Itisathree-phaseprocessconsistingofpreparation,execution,andfinalization.Thereis asingleAPIfunctionassociatedwitheachphase.Associatedwiththeexecutionphasearefunctionswith whichtoobtainrecordandcolumninformationfromresultsets. 127 CHAPTER5■SQLITEDESIGNANDCONCEPTS Inadditiontothestandardquerymethod,therearetwowrapperfunctions,whichwrapthethree phasesintoasinglefunctioncall.TheyprovideaconvenientwaytoexecuteaSQLcommandallatonce. ThesefunctionsarejustafewofthemanymiscellaneousutilityfunctionsintheAPI.Wewilllookatall ofthequerymethodsalongwiththeirassociatedutilityfunctionsinthissection.Beforewedohowever, let’sfirstlookathowtoconnecttoadatabase. Connecting to a Database Connectingtoadatabaseinvolveslittlemorethanopeningafile.EverySQLitedatabaseisstoredina singleoperatingsystemfile—onedatabasetoonefile.Thefunctionusedtoconnect,oropen,adatabase intheCAPIissqlite3_open()andisbasicallyjustasystemcallforopeningafile.SQLitecanalsocreate in-memorydatabases.Inmostextensions,ifyouuse:memory:oranemptystringasthenameforthe database,itwillcreatethedatabaseinRAM.Thedatabasewillbeaccessibleonlytotheconnectionthat createdit(itcannotbesharedwithotherconnections).Furthermore,thedatabasewillonlylastforthe durationoftheconnection.Itisdeletedfrommemorywhentheconnectioncloses. Whenyouconnecttoadatabaseondisk,SQLiteopensafile,ifitexists.Ifyoutrytoopenafilethat doesn’texist,SQLitewillassumethatyouwanttocreateanewdatabase.Inthiscase,SQLitedoesn’t immediatelycreateanewoperatingsystemfile.Itwillcreateanewfileonlyifyouputsomethinginto thenewdatabase—createatableorvieworotherdatabaseobject.Ifyoujustopenanewdatabase,do nothing,andcloseit,SQLitedoesnotbotherwithcreatingadatabasefile—itwouldjustbeanemptyfile anyway. Thereisanimportantreasonfornotcreatinganewfilerightaway.Certaindatabaseoptions,such asencoding,pagesize,andautovacuum,canbesetonlybeforeyoucreateadatabase.Bydefault,SQLite usesa1,024-bytepagesize.However,youcanusedifferentpagesizesrangingfrom512to32,768bytes bypowersof2.Youmightwanttousedifferentpagesizesforperformancereasons.Forexample,setting thepagesizetomatchtheoperatingsystem’spagesizecanmakeI/Omoreefficient.Largerpagesizes canhelpwithapplicationsthatdealwithalotofbinarydata.Yousetthedatabasepagesizeusingthe page_sizepragma. Encodingisanotherpermanentdatabasesetting.Youspecifyadatabase’sencodingusingthe encodingpragma,whichcanbeUTF-8,UTF-16,UTF-16le(littleendian),andUTF-16be(bigendian). Finallythereisautovacuum,whichyousetwiththeauto_vacuumpragma.Whenatransaction deletesdatafromadatabase,SQLite’sdefaultbehavioristokeepthedeletedpagesaroundforrecycling. Thedatabasefileremainsthesamesize.Tofreethepages,youmustexplicitlyissueavacuumcommand toreclaimtheunusedspace.TheautovacuumfeaturecausesSQLitetoautomaticallyshrinkthe databasefilewhendataisdeleted.Thisfeatureisoftenmoreusefulinembeddedapplicationswhere storageisapremium. Onceyouopenadatabase—fileormemory—itwillberepresentedinternallybyanopaquesqlite3 connectionhandle.Thishandlerepresentsasingleconnectiontoadatabase.Connectionobjectsin extensionsabstractthishandleandsometimesimplementmethodsthatcorrespondtoAPIfunctions thattakethehandleasanargument. 128 CHAPTER5■SQLITEDESIGNANDCONCEPTS Executing Prepared Queries Asstatedearlier,thepreparedquerymethodistheactualprocessbywhichSQLiteexecutesallSQL commands.ExecutingaSQLcommandisathree-stepprocess: • Preparation:Theparser,tokenizer,andcodegeneratorpreparetheSQL statementbycompilingitintoVDBEbytecode.IntheCAPI,thisisperformedby thesqlite3_prepare_v2()function,whichtalksdirectlytothecompiler.The compilercreatesasqlite3_stmthandle(statementhandle)thatcontainsthebyte codeandallotherresourcesneededtoexecutethecommandanditerateoverthe resultset(ifthecommandproducesone). • Execution:TheVDBEexecutesthebytecode.Executionisastepwiseprocess.In theCAPI,eachstepisinitiatedbysqlite3_step(),whichcausestheVDBEtostep throughthebytecode.Thefirstcalltosqlite3_step()usuallyacquiresalockof somekind,whichvariesaccordingtowhatthecommanddoes(readsorwrites). ForSELECTstatements,eachcalltosqlite3_step()positionsthestatement handle’scursoronthenextrowoftheresultset.Foreachrowintheset,itreturns SQLITE_ROWuntilitreachestheend,whereuponitreturnsSQLITE_DONE.Forother SQLstatements(insert,update,delete,andsoon),thefirstcalltosqlite3_step() causestheVDBEtoprocesstheentirecommand. • Finalization:TheVDBEclosesthestatementanddeallocatesresources.IntheC API,thisisperformedbysqlite3_finalize(),whichcausestheVDBEto terminatetheprogram,freeingresourcesandclosingthestatementhandle. Eachstep—preparation,execution,finalization—correspondstoarespectivestatementhandle state—prepared,active,orfinalized.Preparedmeansthatallnecessaryresourceshavebeenallocated andthestatementisreadytobeexecuted,butnothinghasbeenstarted.Nolockhasbeenacquired,nor willalockbeacquireduntilthefirstcalltosqlite3_step().Theactivestatestartswiththefirstcallto sqlite3_step().Atthatpoint,thestatementisintheprocessofbeingexecuted,andsomekindoflockis inplay.Finalizedmeansthatthestatementisclosedandallassociatedresourceshavebeenfreed.Figure 5-2showsthesestepsandstates. 129 CHAPTER5■SQLITEDESIGNANDCONCEPTS Figure5-2.Statementprocessing ThefollowingpseudocodeillustratesthegeneralprocessofexecutingaqueryinSQLite: # 1. Open the database, create a connection object (db) db = open('foods.db') # 2.A. Prepare a statement stmt = db.prepare('select * from episodes') 130 CHAPTER5■SQLITEDESIGNANDCONCEPTS # 2.B. Execute. Call step() is until cursor reaches end of result set. while stmt.step() == SQLITE_ROW print stmt.column('name') end # 2.C. Finalize. Release read lock. stmt.finalize() # 3. Insert a record stmt = db.prepare('INSERT INTO foods VALUES (…)') stmt.step() stmt.finalize() # 4. Close database connection. db.close() Thispseudocodeisanobject-orientedanalogoftheAPI,similartowhatyoumightfindinascripting language.ThemethodsallcorrespondtoSQLiteAPIfunctions.Forexample,prepare()mirrors sqlite3_prepare()_v2,andsoon.ThisexampleperformsaSELECT,iteratingoverallreturnedrows, followedbyanINSERT,whichisprocessedbyasinglecalltostep(). TEMPORARY STORAGE Temporarystorageisanimportantpartofqueryprocessing.SQLiteoccasionallyneedstostore intermediateresultsproducedintheprocessofexecutingcommands—forinstance,whenresultsneedto besortedforanorder byclauseorrowsinonetablearejoinedwithrowsinanothertable.This informationisoftenstoredintemporarystorage.TemporarystorageiskepteitherinRAMorinafile. AlthoughSQLitehassuitabledefaultsforallplatforms,youmaywanttocontrolhowandwhereitusesthis storage.Thetemp_storepragmaletsyouspecifywhethertouseRAMorfile-basedstorage.Ifyouuse file-basedstorage,youcanusethetemp_store_directorypragmatospecifywherethestoragefileis created. Using Parameterized SQL SQLstatementscancontainparameters.Parametersareplaceholdersinwhichvaluesmaybeprovided (or“bound”)atalatertimeaftercompilation.Thefollowingstatementsareexamplesofparameterized queries: insert into foods (id, name) values (?,?); insert into episodes (id, name) (:id, :name); Thesestatementsrepresenttwoformsofparameterbinding:positionalandnamed.Thefirstcommand usespositionalparameters,andthesecondcommandusesnamedparameters. Positionalparametersaredefinedbythepositionofthequestionmarkinthestatement.Thefirst questionmarkhasposition1,thesecond2,andsoon.Namedparametersuseactualvariablenames, whichareprefixedwithacolon.Whensqlite3_prepare_v2()compilesastatementwithparameters,it allocatesplaceholdersfortheparametersintheresultingstatementhandle.Itthenexpectsvaluestobe 131 CHAPTER5■SQLITEDESIGNANDCONCEPTS providedfortheseparametersbeforethestatementisexecuted.Ifyoudon’tbindavaluetoaparameter, SQLitewilluseNULLasthedefaultwhenitexecutesthestatement. Theadvantageofparameterbindingisthatyoucanexecutethesamestatementmultipletimes withouthavingtorecompileit.Youjustresetthestatement,bindanewsetofvalues,andreexecute.This iswhereresettingratherthanfinalizingastatementcomesinhandy:itavoidstheoverheadofSQL compilation.Byresettingastatement,youarereusingthecompiledSQLcode.Youcompletelyavoidthe tokenizing,parsing,andcodegenerationoverhead.ResettingastatementisimplementedintheAPIby thesqlite3_reset()function. TheotheradvantageofparametersisthatSQLitetakescareofescapingthestringvaluesyoubindto parameters.Forexample,ifyouhadaparametervaluesuchas'Kenny's Chicken',theparameter bindingprocesswillautomaticallyconvertitto'Kenny''s Chicken'—escapingthesinglequoteforyou, helpingyouavoidsyntaxerrorsandpossibleSQLinjectionattacks(coveredinthesection“Formatting SQLStatements”).Thefollowingpseudocodeillustratesthebasicprocessofusingboundparameters: db = open('foods.db') stmt = db.prepare('insert into episodes (id, name) values (:id, :name)') stmt.bind('id', '1') stmt.bind('name', 'Soup Nazi') stmt.step() # Reset and use again stmt.reset() stmt.bind('id', '2') stmt.bind('name', 'The Junior Mint') # Done stmt.finalize() db.close() Here,reset()simplydeallocatesthestatement’sresourcesbutleavesitsVDBEbytecodeand parametersintact.Thestatementisreadytorunagainwithouttheneedforanothercalltoprepare(). Thiscansignificantlyimproveperformanceofrepetitivequeriessuchasthisbecausethecompiler completelydropsoutoftheequation. Executing Wrapped Queries Asmentionedearlier,therearetwoveryusefulutilityfunctionsthatwrapthepreparedqueryprocess, allowingyoutoexecuteSQLcommandsinasinglefunctioncall.Onefunction—sqlite3_exec()—is typicallyforqueriesthatdon’treturndata.Theother—sqlite3_get_table()—istypicallyforqueriesthat do.Inmanylanguageextensions,youwillseeanalogstobothfunctions.Mostextensionsrefertothe firstmethodsimplyasexec()andthesecondasjustget_table(). Theexec()functionisaquickandeasywaytoexecuteinsert,update,anddeletestatementsor DDLstatementsforcreatinganddestroyingdatabaseobjects.Itworksstraightfromthedatabase connection,takingasqlite3handletoanopendatabasealongwithastringcontainingoneormoreSQL statements.That’sright;exec()iscapableofprocessingastringofmultipleSQLstatementsdelimitedby semicolonsandrunningthemalltogether. Internally,exec()parsestheSQLstring,identifiesindividualstatements,andthenprocessesthem onebyone.Itallocatesitsownstatementhandlesandprepares,executes,andfinalizeseachstatement. 132 CHAPTER5■SQLITEDESIGNANDCONCEPTS Ifmultiplestatementsarepassedtoitandoneofthemfails,exec()terminatesexecutiononthat command,returningtheassociatederrorcode.Otherwise,itreturnsasuccesscode.Thefollowing pseudocodeillustratesconceptuallyhowexec()worksinanextension: db = open('foods.db') db.exec("insert into episodes (id, name) values (1, 'Soup Nazi')") db.exec("insert into episodes (id, name) values (2, 'The Fusilli Jerry')") db.exec("begin; delete from episodes; rollback") db.close() Althoughyoucanalsouseexec()toprocessrecordsreturnedfromSELECT,itinvolvessubtlemethodsfor doingsothataregenerallysupportedonlybytheCAPI. Thesecondqueryfunction,sqlite3_get_table(),issomewhatofamisnomerbecauseitisnot restrictedtojustqueryingasingletable.Rather,itsnamereferstothetabularresultsofaselectquery. Youcancertainlyprocessjoinswithitjustaswell.Inmanyrespects,get_table()worksinthesameway asexec(),butitreturnsacompleteresultsetinmemory.Thisresultsetisrepresentedinvariousways dependingontheextension.Thefollowingpseudocodeillustrateshowitistypicallyused: db = open('foods.db') table = db.get_table("select * from episodes limit 10") for i=0; i < table.rows; i++ for j=0; j < table.cols; j++ print table[i][j] end end db.close() Theupsideofget_table()isthatitprovidesaone-stepmethodtoqueryandgetresults.The downsideisthatitstorestheresultscompletelyinmemory.So,thelargertheresultset,themore memoryitconsumes.Notsurprisingly,then,itisnotagoodideatouseget_table()toretrievelarge resultsets.Thepreparedquerymethod,ontheotherhand,holdsonlyonerecord(actuallyitsassociated databasepage)inmemoryatatime,soitismuchbettersuitedfortraversinglargeresultsets. Noticethatalthoughthesefunctionsbuyyouconvenience,youalsoloseabitofcontrolsimplyby nothavingaccesstoastatementhandle.Forexample,youcan’tuseparameterizedSQLstatementswith eitherofthem.So,theyarenotgoingtobeasefficientforrepetitivetasksthatcouldbenefitfrom parameters.Also,theAPIincludesfunctionsthatworkwithstatementhandlesthatprovidelotsof informationaboutcolumnsinaresultset—bothdataandmetadata.Thesearenotavailablewith wrappedquerieseither.Wrappedquerieshavetheiruses,tobesure.Butpreparedqueriesdoaswell. Handling Errors Thepreviousexamplesaregreatlyoversimplifiedtoillustratethebasicpartsofqueryprocessing.Inreal life,youalwayshavetoconsiderthepossibilityoferrors.Almosteveryfunctionyouhaveseensofarcan encountererrorsofsomesort.Commonerrorcodesyouneedtobepreparedtohandleinclude SQLITE_ERROR andSQLITE_BUSY.Thelattererrorcodereferstobusyconditionsthatarisewhena connectioncan’tgetalock.Busyconditionsareaddressedinthe“Transactions”section,whileschema errorsarecoveredindetailinChapter6. 133 CHAPTER5■SQLITEDESIGNANDCONCEPTS Withregardtogeneralerrors,theAPIprovidesthereturncodeofthelast-calledfunctionwiththe sqlite3_errcode()function.Youcangetmorespecificerrorinformationusingthesqlite3_errmsg() function,whichprovidesatextdescriptionofthelasterror.Mostlanguageextensionssupportthis functioninsomewayoranother. Withthisinmind,eachcallinthepreviousexampleshouldcheckfortheappropriateerrorsusing somethinglikethefollowing: # Check and report errors if db.errcode() != SQLITE_OK print db.errmsg(stmt) end Ingeneral,errorhandlingisnotdifficult.Thewayyouhandleanyerrordependsonwhatexactly youaretryingtodo.TheeasiestwaytoapproacherrorhandlingisthesameaswithanyotherAPI—read thedocumentationonthefunctionyouareusingandcodedefensively. Formatting SQL Statements Anotherniceconveniencefunctionyoumayseesomeextensionssupportissqlite3_mprintf().Itisa variantofthestandardClibrarysprintf().IthasspecialsubstitutionsthatarespecifictoSQLthatcan beveryhandy.Thesesubstitutionsaredenoted%qand%Q,andtheyescapeSQL-specificvalues.%qworks like%sinthatitsubstitutesanull-terminatedstringfromtheargumentlist.Butitalsodoublesevery single-quotecharacter,makingyourlifeeasierandhelpingguardagainstSQLinjectionattacks(seethe sidebar“SQLInjectionAttacks”).Here’sanexample: char* before = "Hey, at least %q no pig-man."; char* after = sqlite3_mprintf(before, "he's"); Thevalueafterproducedhereis'Hey, at least he''s no pig-man'.Thesinglequoteinhe’sis doubled,makingitacceptableasastringliteralinaSQLstatement.The%Qformattingdoeseverything%q does,butitadditionallyenclosestheresultingstringinsinglequotes.Furthermore,iftheargumentfor %QisaNULLpointer(inC),itproducesthestringNULLwithoutsinglequotes.Formoreinformation,see thesqlite3_mprintf()documentationintheCAPIreferenceinAppendixB. SQL INJECTION ATTACKS IfyourapplicationreliesonanyuserinputwithwhichtoconstructSQLstatements,youcouldbe vulnerabletoaSQLinjectionattack.Ifyouarenotcarefultofilteruserinput,itcouldbepossiblefor someonetocraftinputthatcouldaltertheSQLstatement,injectinganewSQLstatementintothestring. Forexample,sayyourprogramusesuserinputtofillinthevalueofthefollowingSQLstatement: select * from foods where name='%s'; Youreplacethe%swithwhatevertheusersupplies.Ifusershaveanyknowledgeofyourdatabase,they couldprovideinputthatcandramaticallyaltertheSQLstatement.Forexample,saytheuserwereto providethefollowingstringvalueforthenameinput: nothing' limit 0; select name from sqlite_master where name='% 134 CHAPTER5■SQLITEDESIGNANDCONCEPTS Aftersubstitutingtheuser’sinputintoyourSQLstatement,thenewstatementturnsintotwostatements: select * from foods where name='nothing' limit 0; select name from sqlite_master where name='%'; Thefirststatementwillreturnnothing,andthesecondwillreturnthenamesofallobjectsinyour database.Granted,theoddsofthishappeningrequirequiteabitofknowledgeontheattacker’spart,butit isneverthelesspossible.Somemajor(commercial)webapplicationshavebeenknowntokeepSQL statementsembeddedintheirJavaScript,whichcanprovideplentyofhintsaboutthedatabasebeing used.Inthepreviousexample,allamalicioususerhastodonowisinsertdrop tablestatementsfor everytablefoundinsqlite_master,andyoucouldfindyourselffumblingthroughbackups. OperationalControl TheAPIincludesavarietyofcommandsthatallowyoutomonitor,control,orgenerallylimitwhatcan happeninadatabase.SQLiteimplementsthemintheformoffiltersorcallbackfunctionsthatyoucan registertobecalledforspecificevents.Therearethree“hook”functions:sqlite3_commit_hook(),which monitorstransactioncommitsonaconnection;sqlite3_rollback_hook(),whichmonitorsrollbacks; andsqlite3_update_hook(),whichmonitorschangestorowsfrominsert,update,anddelete operations. ■NoteTheforthcomingreleaseofSQLite3.7willincludemanynewfeatures,oneofwhichistheWriteAhead Log(WAL).Withthis,afurthertypeofhooknamedwal_hook()willbeimplemented.Thisisalittledifferenttothe hooksdiscussedhere.MoredetailsonWALwillbecoveredinChapter11. Thesehooksarecalledatruntime—whileacommandisexecuted.Eachhookallowsyoutoregistera callbackfunctiononaconnection-by-connectionbasisandletsyouprovidesomekindofapplicationspecificdatatobepassedtothecallbackaswell.Thegeneraluseofoperationalcontrolfunctionsisas follows: def commit_hook(cnx) log('Attempted commit on connection %x', cnx) return -1 end db = open('foods.db') db.set_commit_hook(rollback_hook, cnx) db.exec("begin; delete from episodes; rollback") db.close() Ahook’sreturnvaluehasthepowertoaltertheeventinspecificways,dependingonthehook.Inthis example,becausethecommithookreturnsanonzerovalue,thecommitwillberolledback. Additionally,theAPIprovidesaverypowerfulcompiletimehookcalledsqlite3_set_authorizer(). Thisfunctionprovidesyouwithfine-grainedcontroloveralmosteverythingthathappensinthe databaseaswellastheabilitytolimitbothaccessandmodificationonadatabase,table,andcolumn basis.ThisfunctioniscoveredindetailinChapter6. 135 CHAPTER5■SQLITEDESIGNANDCONCEPTS UsingThreads SQLitehasanumberoffunctionsforusingitinamultithreadedenvironment.Withversion3.3.1,SQLite introducedauniqueoperationalmodecalledsharedcachemode,whichisdesignedformultithreaded embeddedservers.Thismodelprovidesawayforasinglethreadtohostmultipleconnectionsthatshare acommonpagecache,thusloweringtheoverallmemoryfootprintoftheserver.Italsoemploysa differentconcurrencymodel.Includedwiththisfeaturearevariousfunctionsformanagingmemoryand fine-tuningtheserver.Thisoperationalmodeisexplainedfurtherlaterinthesection“SharedCache Mode”andinfulldetailinChapter6. The Extension API TheextensionAPIintheSQLiteCAPIofferssupportforuser-definedfunctions,aggregates,and collations.Auser-definedfunctionisaSQLfunctionthatmapstosomehandlerfunctionthatyou implementinCoranotherlanguage.WhenusingtheCAPI,youimplementthishandlerinCorC++.In languageextensions,youimplementthehandlerinthesamelanguageastheextension. User-definedextensionsmustberegisteredonaconnection-by-connectionbasisastheyarestored inprogrammemory.Thatis,theyarenotstoredinthedatabase,likestoredproceduresinlarger relationaldatabasesystems.Theyarestoredinyourprogram.Whenyourprogramorscriptstartsup,it isresponsibleforregisteringthedesireduser-definedextensionsforeachconnectionthatitintendsto usethem. CreatingUser-DefinedFunctions Implementingauser-definedfunctionisatwo-stepprocess.First,youwritethehandler.Thehandler doessomethingthatyouwanttoperformfromSQL.Next,youregisterthehandler,providingitsSQL name,itsnumberofarguments,andapointer(orreference)tothehandler. Forexample,sayyouwantedtocreateaspecialSQLfunctioncalledhello_newman(),whichreturns thetext'Hello Jerry'.IntheSQLiteCAPI,youwouldfirstcreateaCfunctiontoimplementthis,such asthefollowing: void hello_newman(sqlite3_context* ctx, int nargs, sqlite3_value** values) { /* Create Newman's reply */ const char *msg = "Hello Jerry"; /* Set the return value.*/ sqlite3_result_text(ctx, msg, strlen(msg), SQLITE_STATIC); } Don’tworryifyoudon’tknowCortheCAPI.Thishandlerjustreturns'Hello Jerry'.Next,toactually useit,youregisterthishandlerusingthesqlite3_create_function()(ortheequivalentfunctioninyour language): sqlite3_create_function(db, "hello_newman", 0, hello_newman); 136 CHAPTER5■SQLITEDESIGNANDCONCEPTS Thefirstargument(db)isthedatabaseconnection.Thesecondargumentisthenameofthefunctionas itwillappearinSQL,andthethirdargumentmeansthatthefunctiontakeszeroarguments.(Ifyou provide-1,thenitmeansthatthefunctionacceptsavariablenumberofarguments.)Thelastargument isapointertothehello_newman()Cfunction,whichwillbecalledwhentheSQLfunctioniscalled. Onceregistered,SQLiteknowsthatwhenitencounterstheSQLfunctionhello_newman(),itneedsto calltheCfunctionhello_newman()toobtaintheresult.Now,youcanexecuteselecthello_newman() withinyourprogram,anditwillreturnasinglerowwithonecolumncontainingthetext'Hello Jerry'. AsmentionedinChapter4,user-definedfunctionsareahandywaytoimplementspecializeddomain constraintsbyembeddingthemincheckconstraints. CreatingUser-DefinedAggregates Aggregatefunctionsarefunctionsthatareappliedtoallrecordsinaresultsetandcomputesomekindof aggregatevaluefromthem.sum(),count(),andavg()areexamplesofstandardSQLaggregatefunctions inSQLite. Implementinguser-definedaggregatesisathree-stepprocessinwhichyouregistertheaggregate, implementastepfunctiontobecalledforeachrecordintheresultset,andimplementafinalize functiontobecalledafterrecordprocessing.Thefinalizefunctionallowsyoutocomputethefinal aggregatevalueanddoanynecessarycleanup. ThefollowingisanexampleofimplementingasimpleSUM()aggregatecalledpysuminoneofthe SQLitePythonextensions: connection=apsw.Connection("foods.db") def step(context, *args): context['value'] += args[0] def finalize(context): return context['value'] def pysum(): return ({'value' : 0}, step, finalize) connection.createaggregatefunction("pysum", pysum) c = connection.cursor() print c.execute("select pysum(id) from foods").next()[0] Thecreateaggregatefunction()functionregisterstheaggregate,passinginthestep()functionandthe finalizefunction.SQLitepassesstep()acontext,whichitusestostoretheintermediatevaluebetween callstostep().Inthiscase,itistherunningsum.SQLitecallsfinalize()afterithasprocessedthelast record.Here,finalize()justreturnstheaggregatedsum.SQLiteautomaticallytakescareofcleaningup thecontext. 137 CHAPTER5■SQLITEDESIGNANDCONCEPTS CreatingUser-DefinedCollations Collationsdefinehowstringvaluesarecompared.User-definedcollationsthereforeprovideawayto createdifferenttextcomparisonandsortingmethods.ThisisdoneintheAPIbythe sqlite3_create_collation()function.SQLiteprovidesthreedefaultcollations:BINARY,NOCASE,and RTRIM.BINARYcomparesstringvaluesusingtheCfunctionmemcmp()(whichforallintentsandpurposesis casesensitive).NOCASEisjusttheopposite—itssortingiscaseinsensitive.TheRTRIMcollationworkslike BINARYexceptthatitignorestrailingspaces. User-definedcollationsareespeciallyhelpfulforlocalesthatarenotwellservedbythedefault BINARYcollationorthosethatneedsupportforUTF-16.Theycanalsobehelpfulinspecificapplications suchassortingdateformatsthatdon’tlendthemselvestobothlexicographicalandchronologicalorder. Chapter7illustratesimplementingauser-definedcollationtosortOracledatesnativelyinSQLite. Transactions BynowyoushouldhaveapictureofhowtheAPIislaidout.You’veseendifferentwaystoexecuteSQL commandsalongwithsomehelpfulutilityfunctions.ExecutingSQLcommands,however,involvesmore thanjustknowingwhat’sintheAPI.Transactionsandlocksarecloselyintertwinedwithquery processing.Queriesarealwaysperformedwithintransactions,transactionsinvolvelocks,andlockscan causeproblemsifnotmanagedproperly.Youcancontrolboththetypeanddurationoflocksbyhow youuseSQLandthewayyouwritecode. Chapter4illustratedaspecificscenariowheredeadlockscanarisejustbythewaythattwo connectionsmanagetransactionsthroughSQLalone.Asaprogrammer,youwillhaveanothervariable tojuggle—code—whichcancontainmultipleconnectionsinmultiplestateswithmultiplestatement handlesonmultipletablesatanygiventime.Allittakesisasinglestatementhandle,andyourcodemay beholdinganEXCLUSIVElockwithoutyouevenrealizingit,preventingotherconnectionsfromgetting anythingdone. Thatiswhyitiscriticalthatyouhavegoodgraspofhowbothtransactionsandlocksworkandhow theyrelatetothevariousAPIfunctionsusedtoperformqueries.Ideally,youshouldbeabletolookatthe codeyouwriteandtellwhattransactionstatesitwillbeinoratleastbeabletospotpotentialproblems. Inthissection,wewillexplorethemechanicsbehindtransactionsandlocksandinthenextsection observethematworkinactualcode. TransactionLifeCycles Thereareacoupleofthingstoconsiderwithcodeandtransactions.Firstthereistheissueofknowing whichobjectsrununderwhichtransactions.Nextthereisthequestionofduration—whendoesa transactionstartandwhendoesitend,andatwhatpointdoesitstarttoaffectotherconnections?The firstquestionrelatesdirectlytotheAPI.ThesecondrelatestoSQLingeneralandSQLite’s implementationinparticular. 138 CHAPTER5■SQLITEDESIGNANDCONCEPTS Asyouknow,multiplestatementhandlescanbeallocatedfromasingleconnection.Asshownin Figure5-2,eachconnectionhasexactlyoneB-treeandonepagerobjectassociatedwithitperdatabase. Thepagerplaysabiggerrolethantheconnectioninthisdiscussionbecauseitmanagestransactions, locks,thememorycache,andcrashrecovery—allofwhichwillbecoveredinthenextfewsections.You couldjustaseasilysaythattheconnectionobjecthandlesallofthis,butinrealityitisthepagerwithinit. Theimportantthingtorememberisthatwhenyouwritetothedatabase,youdosowithone connection,onetransactionatatime.Thus,allstatementobjectsrunwithinthesingletransaction contextoftheconnectionsfromwhichtheyarederived.Thisanswersthefirstquestion. Asforthesecondquestion,transactionduration(orthetransactionlifecycle)isasshortasasingle statement,oraslongasyoulike—untilyousaystop.Bydefault,aconnectionoperatesinautocommit mode,whichmeansthateverycommandyouissuerunsunderaseparatetransaction.Conversely,when youissueabegin,thetransactionenduresuntilyoucalleitheraCOMMITorarollback,oruntiloneofyour SQLcommandscausesaconstraintviolationthatresultsinarollback.Thenextquestionishow transactionsrelatetolocks. LockStates Forthemostpart,lockdurationshadowstransactionduration.Althoughthetwodon’talwaysstart together,theydoalwaysfinishtogether.Whenyouconcludeatransaction,youfreeitsassociatedlock.A betterwayofsayingthisisthatalockisneverreleaseduntilitsassociatedtransactionconcludesor,in theworsecase,theprogramcrashes.Andiftheprogramorsystemcrashes,thetransactiondoesn’t concludeinwhichcasethereisstillanimplicitlockonthedatabasethatwillberesolvedbythenext connectiontoaccessit.Thisiscoveredlaterinthesidebar“LockingandCrashRecovery.” TherearefivedifferentlocksstatesinSQLite,andaconnectionisalwaysinoneofthemnomatter whatit’sdoing.Figure5-3showsSQLite’slockstatesandtransitions.Thisdiagramdetailseverypossible lockstateaconnectioncanbeinaswellaseverypathitcantakethroughthelifeofatransaction.The diagramisrepresentedintermsoflockstates,locktransitions,andtransactionlifecycles.Whatyouare reallylookingatinthefigurearethelivesoftransactionsintermsoflocks. 139 CHAPTER5■SQLITEDESIGNANDCONCEPTS Figure5-3.SQLitelocktransitions EachstatehasacorrespondinglockwiththeexceptionofUNLOCKED.So,youcansayaconnection “hasaRESERVEDlock”or“isintheRESERVEDstate”orjust“isinRESERVED,”anditallmeansthesamething. WiththeexceptionofUNLOCKED,foraconnectiontobeinagivenstateitmustfirstobtaintheassociated lock. EverytransactionstartsatUNLOCKED,RESERVED,orEXCLUSIVE.Bydefault,everythingbeginsin UNLOCKED,asyoucanseeinFigure5-3.Thelocksstatesinwhite—UNLOCKED,PENDING,SHARED,and RESERVED—canallexistatthesametimebetweenconnectionsinadatabase.StartingwithPENDINGin gray,however,thingsbecomemorerestrictive.ThegrayPENDINGstaterepresentsthelockbeingheldbya singleconnection,namely,awriterthatwantstogettoEXCLUSIVE.Conversely,thewhitePENDINGstate representsapathwhereconnectionsacquireandreleasethelockontheirwaytoSHARED.Despiteallof thesedifferentlockstates,everytransactioninSQLiteboilsdowntooneoftwotypes:transactionsthat 140 CHAPTER5■SQLITEDESIGNANDCONCEPTS readandtransactionsthatwrite.Thatultimatelyiswhatpaintsthelockingpicture:readersversus writersandhowtheygetalongwitheachother. ReadTransactions Tostartwith,let’sgothroughthelockprocessofaselectstatement.Itspathisverysimple.A connectionthatexecutesaselectstatementstartsatransaction,whichgoesfromUNLOCKEDtoSHARED anduponcommitbacktoUNLOCKED.Endofstory. Now,outofcuriosity,whathappenswhenyouexecutetwostatements?Whatisthelockpaththen? Well,itdependsonwhetheryouarerunninginautocommitornot.Considerthefollowingexample: db = open('foods.db') db.exec('begin') db.exec('select * from episodes') db.exec('select * from episodes') db.exec('commit') db.close() Here,withanexplicitbegin,thetwoselectcommandsexecutewithinasingletransactionandtherefore areexecutedinthesameSHAREDstate.Thefirstexec()runs,leavingtheconnectioninSHARED,andthen thesecondexec()runs.Finally,themanualcommittakestheconnectionfromSHAREDbacktoUNLOCKED. Thecode’slockpathwouldbeasfollows: UNLOCKED→PENDING→SHARED→UNLOCKED Nowconsiderthecasewheretherearenobeginandcommitlinesintheexample.Thenthetwo selectcommandsruninautocommitmode.Theywillthereforegothroughtheentirepath independently.Thelockpathforthecodenowwouldbeasfollows: UNLOCKED→PENDING→SHARED→UNLOCKED→PENDING→SHARED→UNLOCKED Sincethecodeisjustreadingdata,itmaynotmakemuchofadifference,butitdoeshavetogo throughtwicethefilelocksinautocommitmodethanitdoesotherwise.And,asyouwillsee,awriter couldsneakinbetweenthetwoselectcommandsandmodifythedatabasebetweenexec()calls,soyou can’tbesurethatthetwocommandswillreturnthesameresults.Withbegin..commit,ontheother hand,theyareguaranteedtobeidenticalintheirresults. WriteTransactions Nowlet’sconsiderastatementthatwritestothedatabase,suchasanupdate.First,theconnectionhas tofollowthesamepathasselectandgettoSHARED.Everyoperation—readorwrite—hastostartby goingthroughUNLOCKED→PENDING→SHARED,PENDING,asyouwillsoonsee,isagatewaylock. The Reserved State Themomenttheconnectiontriestowriteanythingtothedatabase,ithastogofromSHAREDtoRESERVED. IfitgetstheRESERVEDlock,thenitisreadytostartmakingmodifications.Eventhoughtheconnection 141 CHAPTER5■SQLITEDESIGNANDCONCEPTS cannotactuallymodifythedatabaseatthispoint,itcanstoremodificationsinalocalizedmemorycache insidethepager,calledthepagecache,mentionedearlier.Thiscacheisthesamecacheyouconfigure withthecache_sizepragma,asdescribedinChapter4. WhentheconnectionentersRESERVED,thepagerinitializestherollbackjournal.Thisisafile(shown inFigure5-1)thatisusedinrollbacksandcrashrecovery.Specifically,itholdsthedatabasepages neededtorestorethedatabasetoitsoriginalstatebeforethetransaction.Thesedatabasepagesareput therebythepagerwhentheB-treemodifiesapage.Inthisexample,foreveryrecordtheupdate commandmodifies,thepagertakesthedatabasepageassociatedwiththeoriginalrecordandcopiesit outtothejournal.Thejournalthenholdssomeofthecontentsofthedatabasebeforethetransaction. Therefore,allthepagerhastodoinordertoundoanytransactionistosimplycopythecontentsinthe journalbackintothedatabasefile.Thenthedatabaseisrestoredtoitsstatebeforethetransaction. IntheRESERVEDstate,thereareactuallythreesetsofpagesthatthepagermanages:modifiedpages, unmodifiedpages,andjournalpages.Modifiedpagesarejustthat—pagescontainingrecordsthattheBtreehaschanged.Thesearestoredinthepagecache.UnmodifiedpagesarepagestheB-treereadbut didnotchange.Theseareaproductofcommandssuchasselect.Finally,therearejournalpages,which aretheoriginalversionsofmodifiedpages.Thesearenotstoredinthepagecachebutratherwrittento thejournalbeforetheB-treemodifiesapage. Becauseofthepagecache,awritingconnectioncanindeedgetrealworkdoneintheRESERVEDstate withoutinterferingwithother(reading)connections.Thus,SQLitecaneffectivelyhavemultiplereaders andonewriterbothworkingonthesamedatabaseatthesametime.Theonlycatchisthatthewriting connectionhastostoreitsmodificationsinitspagecache,notinthedatabasefile.Notealsothatthere canbeonlyoneconnectioninRESERVEDorEXCLUSIVEforagivendatabaseatagiventime—multiple readersbutonlyonewriter. The Pending State Whentheconnectionfinishesmakingchangesfortheupdateandthetimecomestocommitthe transaction,thepagerbeginstheprocessofenteringtheEXCLUSIVEstate.Youalreadyknowhowthis worksfromChapter4,butwewillrepeatitforthesakeofcompleteness.FromtheRESERVEDstate,the pagertriestogetaPENDINGlock.Onceitdoes,itholdsontoit,preventinganyotherconnectionsfrom gettingaPENDINGlock.LookatFigure5-3andseewhateffectthishas.Rememberwetoldyouthat PENDINGwasagatewaylock.Nowyouseewhy.SincethewriterisholdingontothePENDINGlock,nobody elsecangettoSHAREDfromUNLOCKEDanymore.Theresultisthatnonewconnectionscanenterthe database:nonewreaders,nonewwriters.ThisPENDINGstateistheattritionphase.Thewriteris guaranteedthatitcanwaitinlineforthedatabaseand—aslongaseveryonebehavesproperly—getit. OnlyothersessionsthatalreadyhaveSHAREDlockscancontinuetoworkasnormal.InPENDING,the writerwaitsfortheseconnectionstofinishandreleasetheirlocks.What’sinvolvedwithwaitingforlocks isaseparateissue,whichwillbeaddressedshortlyinthesection“WaitingforLocks.” Whentheotherconnectionsreleasetheirlocks,thedatabasethenbelongstothewriter.Then,the pagermovesfromPENDINGtoEXCLUSIVE. The Exclusive State DuringEXCLUSIVE,themainjobistoflushthemodifiedpagesfromthepagecachetothedatabasefile. Thisiswhenthingsgetserious,becausethepagerisgoingtoactuallymodifythedatabase.Itgoesabout thiswithextremecaution. Beforethepagerbeginswritingthemodifiedpages,itfirsttendstothejournal.Itchecksthatthe completecontentsofthejournalhavebeenwrittentodisk.Atthispoint,itisverylikelythateventhough thepagerhaswrittenpagestothejournalfile,theoperatingsystemhasbufferedmanyifnotallofthem 142 CHAPTER5■SQLITEDESIGNANDCONCEPTS inmemory.Thepagertellstheoperatingsystemtoliterallywriteallofthesepagestothedisk.Thisis wherethesynchronouspragmacomesintoplay,asdescribedinChapter4.Themethodspecifiedby synchronousdetermineshowcarefulthepageristoensurethattheoperatingsystemcommitsjournal pagestodisk.Thenormalsettingistoperformasingle“sync”beforecontinuing,tellingtheoperating systemtoconfirmthatallbufferedjournalpagesarewrittentothedisksurface.Ifsynchronousissetto FULL,thenthepagerdoestwofull“syncs”beforeproceeding.IfsynchronousissettoNONE,thepager doesn’tbotherwiththejournalatall(andwhileitcanbe50timesfaster,youcankisstransaction durabilitygoodbye). Thereasonthatcommittingthejournaltodiskissoimportantisthatiftheprogramorsystem crasheswhilethepageriswritingtothedatabasefile,thejournalistheonlywaytorestorethedatabase filelater.Ifthejournal’spagesweren’tcompletelywrittentodiskbeforeasystemcrash,thenthe databasecannotberestoredfullytoitsoriginalstate,becausethejournalpagesthatwereinmemory werelostinthecrash.Inthiscase,youhaveaninconsistentdatabaseatbestandacorruptedoneat worse. ■CautionEvenifyouusethemostconservativesettingforthesynchronouspragma,youstillmaynotbe guaranteedthatthejournalistrulycommittedtodisk.ThisisnofaultofSQLite,butratherofcertaintypesof hardwareandoperatingsystems.SQLiteusesthefsync()systemcallonUnixandFlushFileBuffers()on Windowstoforcejournalpagestodisk.Butithasbeenreportedthatthesefunctionsdon’talwayswork,especially withcheapIDEdisks.Apparently,somemanufacturersofIDEdisksusecontrollerchipsthattendtobendthetruth aboutactuallycommittingdatatodisk.Insomecases,thechipscachethedatainvolatilememorywhilereporting thattheywroteittothedrivesurface.Also,therehavebeen(unconfirmed)reportsthatWindowsoccasionally ignoresFlushFileBuffers().Ifyouhavehardwareorsoftwarethatliestoyou,yourtransactionsmaynotbeas durableasyoumightthink. Oncethejournalistakencareof,thepagerthencopiesallofthemodifiedpagestothedatabasefile. Whathappensnextdependsonthetransactionmode.If,asinthiscase,thetransactionautocommits, thenthepagercleansupthejournal,clearsthepagecache,andproceedsfromEXCLUSIVEtoUNLOCKED.If thetransactiondoesnotcommit,thenthepagercontinuestoholdtheEXCLUSIVElock,andthejournal staysinplayuntileitheraCOMMITorROLLBACKisissued. Autocommit and Efficiency Withallthisinmind,considerwhathappenswithUPDATEsthatruninanexplicittransactionversusones thatruninautocommit.Inautocommit,everycommandthatmodifiesthedatabaserunsinaseparate transactionandtravelsthroughthefollowingpath: UNLOCKED→PENDING→SHARED→RESERVED→PENDING→EXCLUSIVE→UNLOCKED Additionally,eachtripthroughthispathinvolvescreating,committing,andclearingoutthe rollbackjournal.Thisalladdsup.AlthoughrunningmultipleSELECTsinautocommitmodeisperhaps notthatbigofadealperformance-wise,youshouldreallyrethinkautocommitmodeforfrequentwrites. And,asmentionedintheSELECTcase,whenrunningmultiplecommandsinautocommit,thereis 143 CHAPTER5■SQLITEDESIGNANDCONCEPTS nothingstoppinganotherconnectionfromcomingalongandmodifyingthedatabaseinbetween commands.Ifyouhavetwoupdatesthatdependonspecificvaluesinthedatabase,youshouldalways runtheminthesametransactionforthisreason. LOCKING AND CRASH RECOVERY SQLite’slockimplementationisbasedonstandardfilelocking.SQLitekeepsthreedifferentfilelockson thedatabasefile:areservedbyte,apendingbyte,andasharedregion. Everythingstartsatthependingbyte.TomovefromUNLOCKEDtoSHARED,aconnectionfirstattemptstoget aread-lockonthependingbyte.Ifsuccessful,itgetsareadlockonarandombyteinthesharedregion andreleasesthereadlockonthependingbyte.TomovefromSHAREDtoRESERVED,aconnectionattempts toobtainawritelockonthereservedbyte.TogetfromRESERVEDtoEXCLUSIVE,aconnectionattemptsto getawritelockonthependingbyte.Ifsuccessful,thisiswhatcausestheattritionprocess,becauseitis nolongerpossibleforotherconnectionstogetareadlockonthependingbytetoenterSHARED.Finally,to gettheEXCLUSIVElock,theconnectionattemptstogetawritelockontheentiresharedregion.Sincethe sharedregionholdsreadlocksbyallotheractiveconnections,thisstepguaranteesthatanEXCLUSIVE lockisgrantedonlyafterallotherSHAREDlocksarefirstreleased. SQLite’scrashrecoverymechanismusesthereservedbytetodeterminewhenadatabaseneedstobe restored.SincethejournalfileandtheRESERVEDlockgohandinhand,ifthepagerseestheformer withoutthelatter,thensomethingiswrong.Everytimethepageropensadatabasefileortriestofetcha pagefromthedatabase,itdoesasimpleconsistencycheck.IfitfindsajournalfilebutnoRESERVEDlock onthedatabase,thentheprocessthatcreatedthejournalfilemusthavecrashed,orthesystemwent down.Inthiscase,thejournaliscalledahotjournal,andthedatabaseispotentiallyinaninconsistent state.Tomakethingsright,thejournalneedstobe“playedback”torestorethedatabasetoitsoriginal statebeforetheinterruptedtransaction. Tostarttheplayback,thepagerputsthedatabaseintorecoverymode.Todothis,itgoesdirectlyfrom SHAREDtoPENDINGasshownbythegraylineintheillustration(andalsoinFigure5-3).Thisistheonly timeitevermakesthistransition.Thereasonitskipsthereservedlockistwofold.First,bylockingthe pendingbyte,itkeepsallnewconnectionsoutofthedatabase.Second,connectionsthatarealreadyinthe database(inSHARED)willalsoseethehotjournalthenexttimetheytrytoaccessapage.Those connectionswillattempttogointorecoverymodeandreplaythejournalaswell.However,theywon’tbe abletobecausethefirstconnectionalreadyhasthePENDINGlock.Thus,bygoingstraightfromSHAREDto PENDING,thefirstconnectionensuresthat(1)nonewconnectionscanenterthedatabaseand(2)active 144 CHAPTER5■SQLITEDESIGNANDCONCEPTS connectionsinSHAREDcannotgointorecoverymode.Everyonebuttherestoringconnectionistemporarily suspended. Basically,ahotjournalisanimplicitEXCLUSIVElock.Ifawritercrashes,nofurtheractivitycantranspirein thedatabaseuntilsomeconnectionrestoresit.Thenextpagertoaccessapagewillseethehotjournal, lockeveryoneout,andstartrecovery.Iftherearenootheractiveconnections,thenthefirstprogramto connecttothedatabasewilldetectthehotjournalandstartrecovery. Tuning the Page Cache Ifwechangethepreviousexampleandsaythatitstartedwithabegin,followedbytheupdate,andinthe middleofmakingallthosemodificationsthepagecachefillsup(runsoutofmemory),howshould SQLiterespond?Thatis,theupdateresultsinmoremodifiedpagesthanwillfitinthepagecache.What happensnow? TransitioningtoExclusive Therealquestionis,whenexactlydoesthepagermovefromRESERVEDtoEXCLUSIVEandwhy?Thereare twoscenarios,andyou’vejustseenthemboth.Eithertheconnectionreachesthecommitpointand deliberatelyentersEXCLUSIVEorthepagecachefillsupandithasnootheroption.Wejustlookedatthe commitpointscenario.So,whathappenswhenthepagecachefillsup?Putsimply,thepagercanno longerstoreanymoremodifiedpagesandthereforecannolongerdoanywork.Itisforcedtomoveinto EXCLUSIVEinordertocontinue.Inreality,thisisnotentirelytruebecausethereisasoftlimitandahard limit. Thesoftlimitcorrespondstothefirsttimethepagecachefillsup.Atthispoint,thecacheisamixed bagofmodifiedandunmodifiedpages.Inthiscase,thepagertriestocleanoutthepagecache.Itgoes throughthecachepagebypagelookingforunmodifiedpagesandclearingthemout.Onceitdoesthat, itcansputteralongwithwhatmemoryhasfreedupuntilthecachefillsupagain.Itrepeatstheprocess untilthecacheiscompletelymadeupofmodifiedpages.Andthatisthathardlimit.Atthispoint,the pagerhasnootherrecoursebuttoproceedintoEXCLUSIVE. TheRESERVEDstate,then,iswherethecache_sizepragmamakesadifference.Justasexplainedin Chapter4,cache_sizecontrolsthesizeofthepagecache.Thebiggerthepagecache,themoremodified pagesthepagercanstore,andthemoreworktheconnectioncandobeforehavingtoenterEXCLUSIVE. Also,asmentioned,bydoingallthedatabaseworkinRESERVED,youminimizethetimeinEXCLUSIVE.If yougetallyourworkdoneinRESERVED,thenEXCLUSIVEisheldonlylongenoughtoflushmodifiedpages todisk—notcompilemorequeriesandprocessmoreresultsandthenwritetodisk.Doingtheprocessing inRESERVEDcansignificantlyincreaseoverallconcurrency.Ideally,ifyouhavealargetransactionora congesteddatabaseandyoucansparethememory,trytoensurethatyourcachesizeislargeenoughto holdyourconnectioninRESERVEDaslongaspossible. SizingthePageCache So,howdoyoudeterminewhatthecachesizeshouldbe?Itdependsonwhatyouaredoing.Saythatyou wanttoupdateeveryrecordintheepisodestable.Inthiscase,youknowthateverypageinthetablewill bemodified.Therefore,youfigureouthowmanypagesareinepisodesandadjustthecachesize accordingly.Youcangetalltheinformationyouneedonepisodesusingsqlite3_analyzer.Foreach 145 CHAPTER5■SQLITEDESIGNANDCONCEPTS table,itwilldumpdetailedstatistics,includingthetotalpagecount.Forexample,ifyourunitonthe foodsdatabase,yougetthefollowinginformationaboutepisodes: *** Table EPISODES *************************************************** Percentage of total database.......... Number of entries..................... Bytes of storage consumed............. Bytes of payload...................... Average payload per entry............. Average unused bytes per entry........ Average fanout........................ Maximum payload per entry............. Entries that use overflow............. Index pages used...................... Primary pages used.................... Overflow pages used................... Total pages used...................... Unused bytes on index pages........... Unused bytes on primary pages......... Unused bytes on overflow pages........ Unused bytes on all pages............. 20.0% 181 5120 3229 17.84 5.79 4.00 38 0 1 4 0 5 990 58 0 1048 63.1% 0.0% 96.7% 1.4% 20.5% Thetotalpagecountis5.Butofthose,only4pagesofactualtableareused—1pageisanindex. Sincethedefaultcachesizeis2,000pages,youhavenothingtoworryabout.Thereareabout400records inepisodes,whichmeansthereareabout100recordsperpage.Youwouldn’thavetoworryabout adjustingthepagecachebeforeupdatingeveryrecordunlesstherewereatleast196,000rowsin episodes.Andremember,youwouldonlyneedtodothisinenvironmentswherethereareother connectionsusingthedatabaseandconcurrencyisanissue.Ifyouaretheonlyoneusingthedatabase, thenitreallywouldn’tmatter. Waiting for Locks WetalkedearlieraboutthepagerwaitingtogofromPENDINGtoEXCLUSIVE.Whatexactlyisinvolvedwith waitingonalock?First,anycalltoexec()orstep()caninvolvewaitingonalock.WheneverSQLite encountersasituationwhereitcan’tgetalock,thedefaultbehavioristoreturnDelete SQLITE_BUSYto thefunctionthatcausedittoseekthelock.Regardlessofthecommandyouexecute,youcanpotentially encounterSQLITE_BUSY.SELECTcommands,asyouknowbynow,canfailtogetaSHAREDlockifawriteris pendingorwriting.ThesimplethingtodowhenyougetSQLITE_BUSYistojustretrythecall.However, wewillseeshortlythatthisisnotalwaysthebestcourseofaction. UsingaBusyHandler Insteadofjustretryingthecalloverandover,youcanuseabusyhandler.RatherthanhavingtheAPI returnSQLITE_BUSYifaconnectioncannotgetalock,youcangetittocallthebusyhandlerinstead. Abusyhandlerisafunctionyoucreatethatkillstimeordoeswhateverelseyouwantittodo—itcan sendspamtoyourmother-in-lawforallSQLitecares.It’sjustgoingtogetcalledwhenSQLitecan’tgeta lock.Theonlythingthebusyhandlerhastodoisprovideareturnvalue,tellingSQLitewhattodonext. 146 CHAPTER5■SQLITEDESIGNANDCONCEPTS Byconvention,ifthehandlerreturnstrue,thenSQLitewillcontinuetotryforthelock.Ifitreturnsfalse, SQLitewillthenreturnSQLITE_BUSYtothefunctionrequestingthelock.Considerthefollowingexample: counter = 1 def busy() counter = counter + 1 if counter == 2 return 0 end end spam_mother_in_law(100) return 1 db.busy_handler(busy) stmt = db.prepare('select * from episodes;') stmt.step() stmt.finalize() Theimplementationofspam_mother_in_law()isleftasanexerciseforthereader. Thestep()functionhastogetaSHAREDlockonthedatabasetoperformtheselect.However,say thereisawriteractive.Normally,step()wouldreturnSQLITE_BUSY.However,inthiscaseitdoesn’t.The pager(whichisonethatdealswithlocks)callsthebusy()functioninstead,becauseithasbeen registeredasthebusyhandler.busy()incrementsacounter,forwardsyourmother-in-law100random messagesfromyourspamfolder,andreturns1,whichthepagerinterpretsastrue—keeptryingtoget thelock.ThepagerthentriesagaintogettheSHAREDlock.Saythedatabaseisstilllocked.Thepagercalls thebusyhandleragain.Onlythistime,busy()returns0,whichthepagerinterpretsasfalse.Inthiscase, ratherthanretryingthelock,thepagersendsSQLITE_BUSYupthestack,andthat’swhatstep()endsup returning. Ifyoujustwanttokilltimewaitingforalock,youdon’thavetowriteyourownbusyhandler.The SQLiteAPIhasoneforyou.Itisasimplebusyhandlerthatsleepsforagivenperiodoftimewaitingfora lock.IntheAPI,thefunctioniscalledsqlite3_busy_timeout(),anditissupportedbysomeextension libraries.Youcanessentiallysay“trysleepingfor10secondswhenyoucan’tgetalock,”andthepager willdothatforyou.Ifitsleepsfor10secondsandstillcan’tgetthelock,thenitwillreturnSQLITE_BUSY. UsingtheRightTransaction Let’sconsiderthepreviousexampleagain,butthistimethecommandisanupdateratherthanaselect. WhatdoesSQLITE_BUSYactuallymeannow?Inselect,itjustmeans,“Ican’tgetaSHAREDlock.”Butwhat doesismeanforanupdate?Thetruthis,youdon’treallyknowwhatitmeans.SQLITE_BUSYcouldmean thattheconnectionfailedtogetaSHAREDlockbecausethereisawriterpending.Itcouldalsomeanthat itgotaSHAREDlockbutcouldn’tgettoRESERVED.Thepointisyoudon’tknowthestateofthedatabaseor thestateofyourconnectionforthatmatter.Inautocommitmode,SQLITE_BUSYforawriteoperationis completelyindeterminate.So,whatdoyoudonext?Shouldyoujustkeepcallingstep()overandover untilthecommandgoesthrough? Here’sthethingtothinkabout.SupposeSQLITE_BUSYwastheresultofyougettingaSHAREDlockbut notRESERVED,andnowyouareholdingupaconnectioninRESERVEDfromgettingtoEXCLUSIVE.Again, youdon’tknowthestateofthedatabase.Andjustusingabrute-forcemethodtopushyourtransaction throughisnotnecessarilygoingtowork,foryouoranyotherconnection.Ifyoujustkeepcallingstep(), 147 CHAPTER5■SQLITEDESIGNANDCONCEPTS youarejustgoingtobuttheadswiththeconnectionthathastheRESERVEDlock,andifneitherofyou backsdown,you’lldeadlock. ■NoteSQLitetriestohelpwithdeadlockpreventioninthisparticularscenariobyignoringthebusyhandlerofthe offendingconnection.TheSHAREDconnection’sbusyhandlerwillnotbeinvokedifitispreventingaRESERVED connectionfromproceeding.However,itisuptothecodetogetthehint.Thecodecanstilljustrepeatedlycall step()overandover,inwhichcasethereisnothingmoreSQLitecandotohelp. Sinceyouknowyouwanttowritetothedatabase,thenyouneedtostartbyissuingbegin IMMEDIATE.IfyougetaSQLITE_BUSY,thenatleastyouknowwhatstateyou’rein.Youknowyoucansafely keeptryingwithoutholdingupanotherconnection.Andonceyoufinallydosucceed,youknowwhat stateyouareinthenaswell—RESERVED.Nowyoucanusebruteforceifyouhavetobecauseyouarethe oneintheright.Ifyoustartwithabegin exclusive,ontheotherhand,thenyouareassuredthatyou won’thaveanybusyconditionstodealwithatall.Justrememberthatinthiscaseyouaredoingyour workinEXCLUSIVE,whichisnotasgoodforconcurrencyasdoingtheworkinRESERVED. LOCKS AND NETWORK FILE SYSTEMS Atthispoint,youshouldhaveagoodappreciationforwhatcangowrongwhenadatabaseissharedover anetworkfilesystem.SQLitehandlesconcurrencybyplacingfilelocksonthedatabasefile.Itisvery importantthattheselocksbebothsetandreleasedattherighttimes.SQLiteiscompletelydependenton thefilesystemtomanagelockscorrectlyforconcurrentuse.SQLiteusesthesamelockingmechanisms regardlessofwhetheritisrunningonanormalfilesystemornetworkfilesystem.ItusesPOSIXadvisory locksonUnix,Linux,andOSX,andtheLockFile(),LockFileEx(),andUnlockFile()systemcallson Windows.Thesecallsarestandardsystemcallsandworkcorrectlyonnormalfilesystems.Itisthe networkfilesystem’sjobtoemulateanormalfilesystem.Andunfortunately,thisdoesn’talwayswork correctlywithsomeimplementations.Andevenifthenetworkfilesystemworkscorrectly,therestillother thingstoconsider. TakeNFS,forexample.It’sagreatnetworkfilesystem.However,manyoriginalNFSimplementations wereknowntohavebuggyorinsomecasesunimplementedlocking.AndwithaSQLitedatabase,thiscan causeseriousproblems.Withoutlocking,twoconnectionscangetanEXCLUSIVElockonthesame databaseandwritetoitatthesametime,leadingtoanalmostcertaindatabasecorruption.Thisisnota problemwiththeNFSprotocolingeneral,butwithsomeimplementationsofitinparticular.Thankfully, mostmodernimplementationsofNFShaveovercometheseissues,andsomeimplementations—suchas thosefromSun—arenowrock-solid. NFScanstillhaveissueswithlockingifoneoftheclientsgoesdown(takingtheirdatabaselockwithit) anddoesnotcomebackup.ForNFSv3,alockedfilewouldneedadministrativeinterventiontoclearit.For NFSv4,therewouldbeatimeoutperiod.Buthowlongisthetimeout?Thirtyseconds?Aminute?Thereal issueisnotNFSbutspecificapplicationsofit.Networkfilesystems,evenifperfectlyimplemented,arenot necessarilygoingtoworkexactlylikealocalfilesystem. 148 CHAPTER5■SQLITEDESIGNANDCONCEPTS Thebottomlineis,ifyouaregoingtomixconcurrencyandnetworkfilesystems,therearemanyissuesto consider,evenifyouareusingthebestnetworkfilesystemoutthere.It’snotassimpleasrunningona localfilesystem. Code Bynow,youhaveaprettygoodpictureoftheAPI,transactions,andlocks.Tofinishup,let’sputallthree ofthesethingstogetherinthecontextofyourcodeandconsiderafewscenariosforwhichyoumight wanttowatch. UsingMultipleConnections Ifyouhavewrittencodethatusesotherrelationaldatabases,youmayhavewrittencodethatused multipleconnectionswithinasingleblockofcode.Theclassicexampleishavingoneconnectioniterate overatablewhileanotherconnectionmodifiesrecordsinplace. InSQLite,usingmultipleconnectionsinthesameblockofcodecancauseproblems.Youhavetobe carefulofhowyougoaboutit.Considerthefollowingexample: c1 = open('foods.db') c2 = open('foods.db') stmt = c1.prepare('select * from episodes') while stmt.step() print stmt.column('name') c2.exec('update episodes set ) end stmt.finalize() c1.close() c2.close() Webetyoucaneasilyspottheproblemhere.Inthewhileloop,c2attemptsanupdate,whilec1hasa SHAREDlockopen.ThatSHAREDlockwon’tbereleaseduntilstmtisfinalizedafterthewhileloop. Therefore,itisimpossibletowritetothedatabasewithinthewhileloop.Eithertheupdateswillsilently fail,orifyouhaveabusyhandler,thenitwillonlydelaytheprogram.Thebestthingtodohereistouse oneconnectionforthejobandtorunitunderasinglebegin immediatetransaction.Thenewversion mightbeasfollows: c1 = open('foods.db') # Keep trying until we get it while c1.exec('begin immediate') != SQLITE_SUCCESS end stmt = c1.prepare('select * from episodes') 149 CHAPTER5■SQLITEDESIGNANDCONCEPTS while stmt.step() print stmt.column('name') c1.exec('update episodes set ) end stmt.finalize() c1.exec('commit') c1.close() Incaseslikethis,youshouldusestatementsfromasingleconnectionforreadingorwriting.Then youwon’thavetoworryaboutdatabaselockscausingproblems.However,asitturnsout,thisparticular examplestillwon’twork.Ifyouareiteratingoveratablewithonestatementandupdatingitwith another,thereisanadditionallockingissuethatyouneedtoknowaboutaswell,whichwe’llcovernext. TheImportanceofFinalizing AcommongotchainprocessingselectstatementsisthefailuretorealizethattheSHAREDlockisnot necessarilyreleaseduntilfinalize()(orreset())iscalled—well,mostofthetime.Considerthe followingexample: stmt = c1.prepare('select * from episodes') while stmt.step() print stmt.column('name') end c2.exec('begin immediate; update episodes set …; commit;') stmt.finalize() Althoughyoushouldneverdothisinpractice,youmightendupdoingitanywaybyaccidentsimply becauseyoucangetawaywithit.IfyouwritetheequivalentofthisprogramintheCAPI,itwillactually work.Eventhoughfinalize()hasnotbeencalled,thesecondconnectioncanmodifythedatabase withoutanyproblem.Beforewetellyouwhy,takealookatthenextexample: c1 = open('foods.db') c2 = open('foods.db') stmt = c1.prepare('select * from episodes') stmt.step() stmt.step() stmt.step() c2.exec('begin immediate; update episodes set …; commit;') stmt.finalize() 150 CHAPTER5■SQLITEDESIGNANDCONCEPTS Let’ssaythatepisodeshas100records.Andtheprogramsteppedthroughonlythreeofthem.What happenshere?ThesecondconnectionwillgetSQLITE_BUSY. Inthefirstexample,SQLitereleasedtheSHAREDlockwhenthestatementreachedtheendofthe resultset.Thatis,inthefinalcalltostep(),wheretheAPIreturnsSQLITE_DONE,theVDBEencountered theCloseinstruction,andSQLiteclosedthecursoranddroppedtheSHAREDlock.Thus,c2wasableto pushitsinsertthrougheventhoughc1hadnotcalledfinalize(). Inthesecondcase,thestatementhadnotreachedtheendoftheset.Thenextcalltostep()would havereturnedSQLITE_RESULT,whichmeanstherearemorerowsintheresultssetandthattheSHARED lockisstillactive.Thus,c2couldnotgettheinsertthroughthistimebecauseoftheSHAREDlockfromc1. Themoralofthestoryisdon’tdothis,eventhoughsometimesyoucan.Alwayscallfinalize()or reset()beforeyouwritewithanotherconnection.Theotherthingtorememberisthatinautocommit modestep()andfinalize()aremoreorlesstransactionandlockboundaries.Theystartandend transactions.Theyacquireandreleaselocks.Youshouldbeverycarefulaboutwhatyoudowithother connectionsinbetweenthesefunctions. SharedCacheMode Nowthatyouareclearontheconcurrencyrules,it’stimeforsomenewconfusion.SQLiteoffersan alternativeconcurrencymodelcalledsharedcachemode,whichrelatestohowconnectionscanoperate withinindividualthreads. Insharedcachemode,athreadcancreatemultipleconnectionsthatsharethesamepagecache. Furthermore,thisgroupofconnectionscanhavemultiplereadersandasinglewriter(inEXCLUSIVE) workingonthesamedatabaseatthesametime.Thecatchisthattheseconnectionscannotbeshared acrossthreads—theyarestrictlylimitedtothethread(runningspecificallyinsharedcachemode)that createdthem.Furthermore,writersandreadershavetobepreparedtohandleaspecialcondition involvingtablelocks. Whenreadersreadtables,SQLiteautomaticallyputstablelocksonthem.Thispreventswritersfrom modifyingthosetables.Ifawritertriestomodifyaread-lockedtable,itwillgetSQLITE_LOCKED.Thesame logicappliestoreaderstryingtoreadfromwrite-lockedtables.However,inthislattercase,readerscan stillgoaheadandreadtablesthatarebeingmodifiedbyawriteriftheyruninread-uncommittedmode, whichisenabledbytheread_uncommittedpragma.Inthiscase,SQLitedoesnotplacereadlocksonthe tablesreadbythesereaders.Asaresult,thesereadersdon’tinterferewithwritersatall.However,these readerscangetinconsistentqueryresults,becauseawritercanmodifytablesasthereadersreadthem. Thisissimilartothe“dirtyread”conceptyoumighthaveseeninotherrelationaldatabases. Sharedcachemodeisdesignedforembeddedserversthatneedtoconservememoryandhave slightlyhigherconcurrencyundercertainconditions.MoreinformationonusingitwiththeCAPIcan befoundinChapter6. Summary TheSQLiteAPIisflexible,intuitive,andeasytouse.Ithastwobasicparts:thecoreAPIandtheextension API.ThecoreAPIrevolvesaroundtwobasicdatastructuresusedtoexecuteSQLcommands:the connectionandthestatement.Commandsareexecutedinthreesteps:compilation,execution,and finalization.SQLite’swrapperfunctionsexec()andget_table()wrapthesestepsintoasinglefunction call,automaticallyhandlingtheassociatedstatementobjectforyou.TheextensionAPIprovidesyou withthemeanstocustomizeSQLiteinthreedifferenceways:user-definedfunctions,user-defined aggregates,anduser-definedcollations. 151 CHAPTER5■SQLITEDESIGNANDCONCEPTS BecauseSQLite’sconcurrencymodelissomewhatdifferentfromotherdatabases,itisimportant thatyouunderstandabitabouthowitmanagestransactionsandlocks,howtheyworkbehindthe scenes,andhowtheyworkwithinyourcode.Overall,theconceptsarenotdifficulttounderstand,and therearejustafewsimplerulestokeepinmindwhenyouwritecodethatusesSQLite. Thefollowingchapterswilldrawheavilyonwhatyou’vehavelearnedhere,becausetheseconcepts applynotonlytotheCAPIbuttolanguageextensionsaswellastheyarebuiltontopoftheCAPI. 152 CHAPTER 6 ■■■ The Core C API ThischaptercoversthepartoftheSQLiteAPIusedtoworkwithdatabases.Youalreadysawanoverview ofhowtheAPIworksinChapter5.Nowlet’sconcentrateonthespecifics. Startingwithafeweasilyunderstoodexamples,wewilltakeanin-depthtourthroughtheCAPIand expandupontheexamples,fillinginvariousdetailswithavarietyofusefulfunctions.Aswegoalong, youshouldseetheCequivalentsofthemodelallfallintoplace,withsomeadditionalfeaturesyoumay nothaveseenbefore—featuresthatprimarilyexistonlyintheCAPI.Bythetimewereachtheendofthis chapter,youshouldhaveagoodfeelforalloftheAPIfunctionsrelatedtorunningcommands,managing transactions,fetchingrecords,handlingerrors,andperformingmanyothertasksrelatedtogeneral databasework. TheSQLiteversion3APIconsistsofdozensanddozensoffunctions.Onlyabouteightfunctions, however,areneededtoactuallyconnect,processqueries,anddisconnectfromadatabase.The remainingfunctionscanbearrangedintosmallgroupsthatspecializeinaccomplishingspecifictasks. Althoughitisbesttoreadthechapterstraightthrough,ifatanypointyouwantmoredetailed informationonaparticularfunction,youcanconsulttheCAPIreferenceatwww.sqlite.org/ c3ref/intro.html. Youcanfindalltheexamplesinthischapterinself-containedexampleprogramsintheexamples zipfile,availableontheApresswebsiteatwww.apress.com.Foreveryexamplepresented,wespecifically identifythenameofthecorrespondingsourcefilefromwhichtheexamplewastaken. Wrapped Queries YouarealreadyfamiliarwiththewaythatSQLiteexecutesqueries,aswellasitsvariouswrapper functionsforexecutingSQLcommandsinasinglefunctioncall.WewillstartwiththeCAPIversionsof thesewrappersbecausetheyaresimple,self-contained,andeasytouse.Theyareagoodstartingpoint, whichwillletyouhavesomefunandnotgettooboggeddownwithdetails.Alongtheway,I’llintroduce someotherhandyfunctionsthatgohandinhandwithqueryprocessing.Bytheendofthissection,you willbeableconnect,disconnect,andqueryadatabaseusingthewrappedqueries. ConnectingandDisconnecting BeforeyoucanexecuteSQLcommands,youfirsthavetoconnecttoadatabase.Connectingtoa databaseisperhapsbestdescribedasopeningadatabase,becauseSQLitedatabasesarecontainedin singleoperatingsystemfiles(onefiletoonedatabase).Similarly,thepreferredtermfordisconnectingis closingthedatabase. 153 CHAPTER6■THECORECAPI Youopenadatabasewiththesqlite3_open_v2(),sqlite3_open(),orsqlite3_open16()functions, whichhavethefollowingdeclaration(s): int sqlite3_open_v2( const char *filename, sqlite3 **ppDb int flags, const char *zVfs ); /* /* /* /* int sqlite3_open ( const void *filename, sqlite3 **ppDb ); /* Database filename (UTF-8) */ /* OUT: SQLite db handle */ int sqlite3_open16( const void *filename, sqlite3 **ppDb ); /* Database filename (UTF-16) */ /* OUT: SQLite db handle */ Database filename (UTF-8) */ OUT: SQLite db handle */ Flags */ Name of VFS module to use */ Typically,you’llusesqlite3_open_v2(),becausethisisthelatestandgreatestfunctioninSQLitefor openingyourdatabase,anditaccommodatesmoreoptionsandcapabilitiesovertheold sqlite3_open().Regardlessofthefunctionchosen,thefilenameargumentcanbethenameofan operatingsystemfile,thetextstring':memory:',oranemptystringoraNULLpointer.Ifyouuse ':memory:',sqlite3_open_v2()willcreateanin-memorydatabaseinRAMthatlastsonlyforthe durationofthesession.IffilenameisanemptystringoraNULL,sqlite3_open_v2() opensatemporary diskfilethatisautomaticallydeletedwhentheconnectioncloses.Otherwise,sqlite3_open_v2() attemptstoopenthedatabasefilebyusingitsvalue.Ifnofilebythatnameexists,sqlite3_open_v2() willopenanewdatabasefilebythatnameiftheSQLITE_OPEN_CREATEflagisincludedinthethird parameter,oritwillreturnanerroriftheSQLITE_OPEN_CREATEflagisomitted. ■NoteHerewehaveincludedboththeUTF-8andUTF-16declarationsforsqlite3_open(),aswellasthemore modernsqlite3_open_v2().Fromhereonout,wewillrefertotheUTF-8declarationsonlyforthesakeofbrevity, andwheretheyexist,we’lldealwiththelatestfunctionsignaturesthatincorporateSQLite’slatestfunctionality, ratherthancoverallthelegacyfunctionsaswell.Therefore,pleasekeepinmindthattherearemanyfunctionsin theAPIthathaveUTF-16forms,aswellasolderUTF-8formsforbackwardcompatibility.ThecompleteCAPI referenceisavailableontheSQLitewebsiteatwww.sqlite.org/c3ref/intro.html. Theflagsparameterisabitvectorthatcanincludethefollowingvalues:SQLITE_OPEN_READONLY, SQLITE_OPEN_READWRITE,andSQLITE_OPEN_CREATE.Thenamesarereasonableself-explanatory,butafew subtletiesareworthnoting.SQLITE_OPEN_READONLYandSQLITE_OPEN_READWRITEopenaSQLitedatabase inread-onlyorread/writemodeastheirnamessuggest.Bothoptionsrequirethatthedatabasefile alreadyexist;otherwise,anerrorwillbereturned.SQLITE_OPEN_CREATEcombinedwith SQLITE_OPEN_READWRITEexhibitsthebehaviorwe’veseeninthefirstfivechapters,whichisthelegacy sqlite3_open()behavior.Whereadatabasealreadyexists,itisopenedforreadingandwriting.Ifthe 154 CHAPTER6■ THECORECAPI databasespecifieddoesn’texist,itiscreated(thoughaswe’vepointedoutquiteafewtimes,theactof persistingthedatabasetodiskwillbependingthecreationofthefirstobject). TheflagsparametercanalsobecombinedwiththeSQLITE_OPEN_NOMUTEX,SQLITE_OPEN_FULLMUTEX, SQLITE_OPEN_SHAREDCACHE,orSQLITE_OPEN_PRIVATECACHEflagstofurthercontroltransactionalbehavior forthedatabasehandle.Thefinalparameter,zVfs,allowsthecallertooverridethedefaultsqlite3_vfs operatingsysteminterface. Uponcompletion,sqlite3_open_v2()willinitializethesqlite3structurepassedintoitbytheppDb argument.Thisstructureshouldbeconsideredasanopaquehandlerepresentingasingleconnectionto adatabase.Thisismoreofaconnectionhandlethanadatabasehandlesinceitispossibletoattach multipledatabasestoasingleconnection.However,thisconnectionstillrepresentsexactlyone transactioncontextregardlessofhowmanydatabasesareattached. Youcloseaconnectionbyusingthesqlite3_close()function,whichisdeclaredasfollows: int sqlite3_close(sqlite3*); Forsqlite3_close()tocompletesuccessfully,allpreparedqueriesassociatedwiththeconnection mustbefinalized.Ifanyqueriesremainthathavenotbeenfinalized,sqlite3_close()willreturn SQLITE_BUSYwiththeerrormessage“Unabletocloseduetounfinalizedstatements.” ■NoteIfthereisatransactionopenonaconnectionwhenitisclosedbysqlite3_close(),thetransactionwill automaticallyberolledback. TheexecQuery Thesqlite3_exec()functionprovidesaquick,easywaytoexecuteSQLcommandsandisespecially handyforcommandsthatmodifythedatabase(thatis,don’treturnanydata).Thisisoftenalsoreferred toasaconveniencefunction,whichnicelywrapsupalotofothertasksinoneeasyAPIcall.Thisfunction hasthefollowingdeclaration: int sqlite3_exec( sqlite3*, const char *sql, sqlite_callback, void *data char **errmsg ); /* /* /* /* /* An open database */ SQL to be executed */ Callback function */ 1st argument to callback function */ Error msg written here */ TheSQLprovidedinthesqlargumentcanconsistofmorethanoneSQLcommand.sqlite3_exec() willparseandexecuteeverycommandinthesqlstringuntilitreachestheendofthestringor encountersanerror.Listing6-1(takenfromcreate.c)illustrateshowtousesqlite3_exec().The exampleopensadatabasecalledtest.dbandcreateswithinitasingletablecalledepisodes.Afterthat,it insertsonerecord.Thecreate tablecommandwillphysicallycreatethedatabasefileifitdoesnot alreadyexist. 155 CHAPTER6■THECORECAPI Listing6-1.Usingsqlite3_exec()forSimpleCommands int main(int argc, char **argv) { sqlite3 *db; char *zErr; int rc; char *sql; rc = sqlite3_open_v2("test.db", &db); if(rc) { fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db)); sqlite3_close(db); exit(1); } sql = "create table episodes(id int, name text)"; rc = sqlite3_exec(db, sql, NULL, NULL, &zErr); if(rc != SQLITE_OK) { if (zErr != NULL) { fprintf(stderr, "SQL error: %s\n", zErr); sqlite3_free(zErr); } } sql = "insert into episodes values (10, 'The Dinner Party')"; rc = sqlite3_exec(db, sql, NULL, NULL, &zErr); } sqlite3_close(db); return 0; AsmentionedinChapter5,itisactuallypossibletogetrecordsfromsqlite3_exec(),althoughyoudon’t seeitimplementedmuchoutsideoftheCAPI.sqlite3_exec()containsacallbackmechanismthat providesawaytoobtainresultsfromselectstatements.Thismechanismisimplementedbythethird andfourthargumentsofthefunction.Thethirdargumentisapointertoacallbackfunction.Ifit’s provided,SQLitewillcallthefunctionforeachrecordprocessedineachselectstatementexecuted withinthesqlargument.Thecallbackfunctionhasthefollowingdeclaration: typedef int (*sqlite3_callback)( void*, /* Data provided in the 4th argument of sqlite3_exec() int, /* The number of columns in row char**, /* An array of strings representing fields in the row char** /* An array of strings representing column names ); */ */ */ */ Thefourthargumenttosqlite3_exec()isavoidpointertoanyapplication-specificdatayouwant tosupplytothecallbackfunction.SQLitewillpassthisdataasthefirstargumentofthecallback function. 156 CHAPTER6■ THECORECAPI Thefinalargument(errmsg)isapointertoastringtowhichanerrormessagecanbewrittenshould anerroroccurduringprocessing.Thus,sqlite3_exec()hastwosourcesoferrorinformation.Thefirstis thereturnvalue.Theotheristhehuman-readablestring,assignedtoerrmsg.IfyoupassinaNULLfor errmsg,thenSQLitewillnotprovideanyerrormessage.Notethatifyoudoprovideapointerforerrmsg, thememoryusedtocreatethemessageisallocatedontheheap.YoushouldthereforecheckforanonNULLvalueafterthecallandusesqlite3_free()tofreethememoryusedtoholdtheerrmsgstringifan erroroccurs. ■NoteNotethatyoucanpassaNULLintosqlite3_free().Theresultisaharmlessno-op.So,youcan,ifyou want,callsqlite3_free(errmsg)withouthavingtochecktoseewhethererrmsgisnotNULL.Itmainlydepends onwhereandhowyouwanttointerrogateanyactualerrorsandrespondaccordingly. Puttingitalltogether,sqlite3_exec()allowsyoutoissueabatchofcommands,andyoucancollect allthereturneddatabyusingthecallbackinterface.Forexample,let’sinsertarecordintotheepisodes tableandthenselectallofitsrecords,allinasinglecalltosqlite3_exec().Thecompletecode,shownin Listing6-2,istakenfromexec.c. Listing6-2.Usingsqlite3_exec()forRecordProcessing int callback(void* data, int ncols, char** values, char** headers); int main(int argc, char **argv) { sqlite3 *db; int rc; char *sql; char *zErr; rc = sqlite3_open_v2("test.db", &db); if(rc) { fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db)); sqlite3_close(db); exit(1); } const char* data = "Callback function called"; sql = "insert into episodes (id, name) values (11,'Mackinaw Peaches');" "select * from episodes;"; rc = sqlite3_exec(db, sql, callback, data, &zErr); 157 CHAPTER6■THECORECAPI if(rc != SQLITE_OK) { if (zErr != NULL) { fprintf(stderr, "SQL error: %s\n", zErr); sqlite3_free(zErr); } } } sqlite3_close(db); return 0; int callback(void* data, int ncols, char** values, char** headers) { int i; fprintf(stderr, "%s: ", (const char*)data); for(i=0; i < ncols; i++) { fprintf(stderr, "%s=%s ", headers[i], values[i]); } } fprintf(stderr, "\n"); return 0; SQLiteparsesthesqlstring;runsthefirstcommand,whichinsertsarecord;andthenrunsthe secondcommand,consistingoftheselectstatement.Forthesecondcommand,SQLitecallsthe callbackfunctionforeachrecordreturned.Runningtheprogramproducesthefollowingoutput: Callback function called: id=10 name=The Dinner Party Callback function called: id=11 name=Mackinaw Peaches Noticethatthecallbackfunctionreturns0.Thisreturnvalueactuallyexertssomecontrolover sqlite3_exec().Ifthecallbackfunctionreturnsanonzerovalue,thensqlite3_exec()willabort(in otherwords,itwillterminateallprocessingofthisandsubsequentcommandsinthesqlstring). So,sqlite3_exec()providesaneasywaytomodifythedatabaseandalsoprovidesaninterfacewith whichtoprocessrecords.Whythenshouldyoubotherwithpreparedqueries?Well,asyouwillseeinthe nextsection,therearequiteafewadvantages: • Preparedqueriesdon’trequireacallbackinterface,whichmakescodingsimple andmorelinear. • Preparedquerieshaveassociatedfunctionsthatprovidebettercolumn information.Youcanobtainacolumn’sstoragetype,declaredtype,schemaname (ifitisaliased),tablename,anddatabasename.sqlite3_exec()’scallback interfaceprovidesjustthecolumnnames. • Preparedqueriesprovideawaytoobtainfield/columnvaluesinotherdatatypes besidestextandinnativeCdatatypessuchasintanddouble,whereas sqlite3_exec()’scallbackinterfaceonlyprovidesfieldsasstringvalues. 158 CHAPTER6■ THECORECAPI • Preparedqueriescanbererun,allowingyoutoreusethecompiledSQL. • PreparedqueriessupportparameterizedSQLstatements. EXAMINING CHANGES Ifyouareperforminganupdateoradelete,youmaywanttoknowhowmanyrecordswereaffected.You cangetthisinformationfromsqlite3_changes().Itprovidesthenumberofaffectedrecordsforthelast executedupdate,insert,ordeletestatement.Obviously,ifyouarerunningabatchofqueries(multiple commandsinthesqlargumentofsqlite3_exec()),thisfunctionwillbegoodonlyforthelastcommand inthebatch.Notealsothatsqlite3_changes()doesnotincludechangesactivatedfromtheresultof triggersfiredfromyouroriginalcommand. Ifyouareperforminganinsertonatablewithanautoincrementcolumn,oddsareyouwilleventuallywant toknowtheprimarykeyvalueofaninsertedrecord.Insuchcases,youcanusesqlite3_last_ insert_rowid()toobtainthisvalue.YoucanalsodothisfromwithinSQLaswellviathelast_insert_ rowid()SQLfunction. TheGetTableQuery Thesqlite3_get_table()functionreturnsanentireresultsetofacommandinasinglefunctioncall. Justassqlite3_exec()wrapsthepreparedqueryAPIfunctions,allowingyoutorunthemallatonce, sqlite3_get_table()wrapssqlite3_exec()forcommandsthatreturndatawithjustasmuch convenience.Usingsqlite3_get_table(),youdon’thavetobotherwiththesqlite3_exec()callback function,thusmakingiteasiertofetchrecords.sqlite3_get_table()hasthefollowingdeclaration: int sqlite3_get_table( sqlite3*, const char *sql, char ***resultp, int *nrow, int *ncolumn, char **errmsg ); /* /* /* /* /* /* An open database */ SQL to be executed */ Result written to a char *[] that this points to */ Number of result rows written here */ Number of result columns written here */ Error msg written here */ ThisfunctiontakesalltherecordsreturnedfromtheSQLstatementinsqlandstorestheminthe resultpargumentusingmemorydeclaredontheheap(usingsqlite3_malloc()).Thememorymustbe freedusingsqlite3_free_table(),whichtakestheresultppointerasitssoleargument.Thefirstrecord inresultpisactuallynotarecordbutcontainsthenamesofthecolumnsintheresultset.Examinethe codefragmentinListing6-3(takenfromget_table.c). 159 CHAPTER6■THECORECAPI Listing6-3.Usingsqlite3_get_table int main(int argc, char **argv) { /* Connect to database, etc. */ char *result[]; sql = "select * from episodes;"; rc = sqlite3_get_table(db, sql, &result, &nrows, &ncols, &zErr); /* Do something with data */ } /* Free memory */ sqlite3_free_table(result) If,forexample,theresultsetreturnedisofthefollowingform: name | id ----------------------The Junior Mint | 43 The Smelly Car | 28 The Fusilli Jerry | 21 thentheformatoftheresultarraywillbestructuredasfollows: result result result result result result result result [0] [1] [2] [3] [4] [5] [6] [7] = = = = = = = = "name"; "id"; "The Junior Mint"; "43"; "The Smelly Car"; "28"; "The Fusilli Jerry"; "21"; Thefirsttwoelementscontainthecolumnheadingsoftheresultset.Therefore,youcanthinkofthe resultsetindexingas1-basedwithrespecttorowsbut0-basedwithrespecttocolumns.Anexample mayhelpclarifythis.Listing6-4showsthecodetoprintouteachcolumnofeachrowintheresultset. Listing6-4.IteratingThroughsqlite3_get_table()Results rc = sqlite3_get_table(db, sql, &result, &nrows, &ncols, &zErr); for(i=0; i < nrows; i++) { for(j=0; j < ncols; j++) { /* the i+1 term skips over the first record, which is the column headers */ fprintf(stdout, "%s", result[(i+1)*ncols + j]); } } 160 CHAPTER6■ THECORECAPI Prepared Queries OurChapter5overviewofSQLite’sAPIintroducedtheconceptsoftheprepare,step,andfinalize functions.Thissectioncoversallaspectsofthisprocess,includingsteppingthroughresultsets,fetching records,andusingparameterizedqueries.Wetoldyoupreparedstatementswereinfinitelypreferableto theconveniencewrapperfunctions,andthisiswhereweprovethepoint. Thewrapperfunctionssimplywrapallthesestepsintoasinglefunctioncall,makingitmore convenientinsomesituationstorunspecificcommands.Eachqueryfunctionprovidesitsownwayof gettingatrowsandcolumns.Asageneralrule,themorepackagedthemethodis,thelesscontrolyou haveoverexecutionandresults.Therefore,preparedqueriesofferthemostfeatures,themostcontrol, andthemostinformation,withsqlite3_exec()offeringslightlyfewerfeaturesandsqlite3_get_table() offeringfewerstill. Preparedqueriesuseaspecialgroupoffunctionstoaccessfieldandcolumninformationfroma row.Yougetcolumnvaluesusingsqlite3_column_xxx(),wherexxxrepresentsthedatatypeofthevalue tobereturned(forexample,int,double,blob).Youcanretrievedatainwhateverformatyoulike.You canalsoobtainthedeclaredtypesofcolumns(astheyaredefinedinthecreate tablestatement)and othermiscellaneousmetadatasuchasstorageformatandbothassociatedtableanddatabasenames. sqlite3_exec(),bycomparison,providesonlyafractionofthisinformationthroughitscallback function.Thesameistruewithsqlite3_get_table(),whichonlyincludestheresultset’scolumn headerswiththedata. Inpractice,youwillfindthateachquerymethodhasitsuses.sqlite3_exec()isespeciallygoodfor runningcommandsthatmodifythedatabase(create,drop,insert,update,anddelete).Onefunction call,andit’sdone.Preparedqueriesaretypicallybetterforselectstatementsbecausetheyofferso muchmoreinformation,morelinearcoding(nocallbackfunctions),andmorecontrolbyusingcursors toiterateoverresults. Asyou’llrecallfromChapter5,preparedqueriesareperformedinthreebasicsteps:compilation, execution,andfinalization.Youcompilethequerywithsqlite3_prepare_v2(),executeitstep-by-step usingsqlite3_step(),andcloseitusingsqlite3_finalize(),oryoucanreuseitusingsqlite3_reset(). Thisprocessandtheindividualstepsareallexplainedindetailinthefollowingsections. Compilation Compilation,orpreparation,takesaSQLstatementandcompilesitintobytecodereadablebythe virtualdatabaseengine(VDBE).Itisperformedbysqlite3_prepare_v2(),whichisdeclaredasfollows: int sqlite3_prepare_v2( sqlite3 *db, const char *zSql, int nBytes, sqlite3_stmt **ppStmt, const char **pzTail ); /* /* /* /* /* Database handle */ SQL text, UTF-8 encoded */ Length of zSql in bytes. */ OUT: Statement handle */ OUT: Pointer to unused portion of zSql */ sqlite3_prepare_v2()compilesthefirstSQLstatementinthezSQLstring(whichcancontain multipleSQLstatements).Itallocatesalltheresourcesnecessarytoexecutethestatementand associatesitalongwiththebytecodeintoasinglestatementhandle(alsoreferredtoassimplya statement),designatedbytheoutparameterppStmt,whichisasqlite3_stmtstructure.Fromthe programmer’sperspective,thisstructureislittlemorethananopaquehandleusedtoexecuteaSQL statementandobtainitsassociatedrecords.However,thisdatastructurecontainsthecommand’sbyte 161 CHAPTER6■THECORECAPI code,boundparameters,B-treecursors,executioncontext,andanyotherdatasqlite3_step()needsto managethestateofthequeryduringexecution. sqlite3_prepare_v2()doesnotaffecttheconnectionordatabaseinanyway.Itdoesnotstarta transactionorgetalock.Itworksdirectlywiththecompiler,whichsimplypreparesthequeryfor execution.Statementhandlesarehighlydependentonthedatabaseschemawithwhichtheywere compiled.Ifanotherconnectionaltersthedatabaseschema,betweenthetimeyouprepareastatement andthetimeyouactuallyrunit,yourpreparedstatementwillexpire.However,sqlite3_prepare_v2()is builttoautomaticallyattempttorecompile(re-prepare)yourstatementifpossibleandwilldothis silentlyifaschemachangehasinvalidatedyourexistingstatement.Iftheschemahaschangedinsucha wayastomakerecompilationimpossible,yourcalltosqlite3_step()withthestatementwillleadtoa SQLITE_SCHEMAerror,whichisdiscussedlaterinthesection“ErrorsandtheUnexpected.”Atthispoint, youwouldneedtoexaminetheerrorassociatedwithSQLITE_SCHEMAbyusingthesqlite3_errmsg() function. Execution Onceyoupreparethequery,thenextstepistoexecuteitusingsqlite3_step(),declaredasfollows: int sqlite3_step(sqlite3_stmt *pStmt); sqlite3_step()takesthestatementhandleandtalksdirectlytotheVDBE,whichstepsthroughits byte-codeinstructionsonebyonetocarryouttheSQLstatement.Onthefirstcalltosqlite3_step(),the VDBEobtainstherequisitedatabaselockneededtoperformthecommand.Ifitcan’tgetthelock, sqlite3_step()willreturnSQLITE_BUSY,ifthereisnobusyhandlerinstalled.Ifoneisinstalled,itwillcall thathandlerinstead. ForSQLstatementsthatdon’treturndata,thefirstcalltosqlite3_step()executesthecommandin itsentirety,returningaresultcodeindicatingtheoutcome.ForSQLstatementsthatdoreturndata,such asselect,thefirstcalltosqlite3_step()positionsthestatement’sB-treecursoronthefirstrecord. Subsequentcallstosqlite3_step()positionthecursoronsubsequentrecordsintheresultset. sqlite3_step()returnsSQLITE_ROWforeachrecordinthesetuntilitreachestheend,whereuponit returnsSQLITE_DONE,indicatingthatthecursorhasreachedtheendoftheset. ■NoteForthoseofyoufamiliarwitholderversionsofSQLite,theseresultcodesarepartofthemoreadvanced— andsomewouldsaymorecorrect—setofresultcodesthatreplacethelegacysimplereturnvalueslike SQLITE_ERROR.Afulllistofresultcodesandextendedresultcodesisavailableatwww.sqlite.org/c3ref/ c_abort.html AllotherAPIfunctionsrelatedtodataaccessusethestatement’scursortoobtaininformationabout thecurrentrecord.Forexample,thesqlite3_column_xxx()functionsallusethestatementhandle, specificallyitscursor,tofetchthecurrentrecord’sfields. 162 CHAPTER6■ THECORECAPI FinalizationandReset Oncethestatementhasreachedtheendofexecution,itmustbefinalized.Youcaneitherfinalizeor resetthestatementusingoneofthefollowingfunctions: int sqlite3_finalize(sqlite3_stmt *pStmt); int sqlite3_reset(sqlite3_stmt *pStmt); sqlite3_finalize()willcloseoutthestatement.Itfreesresourcesandcommitsorrollsbackany implicittransactions(iftheconnectionisinautocommitmode),clearingthejournalfileandfreeingthe associatedlock. Ifyouwanttoreusethestatement,youcandosousingsqlite3_reset().Itwillkeepthecompiled SQLstatement(andanyboundparameters)butcommitsanychangesrelatedtothecurrentstatement tothedatabase.Italsoreleasesitslockandclearsthejournalfileifautocommitisenabled.Theprimary differencebetweensqlite3_finalize()andsqlite3_reset()isthatthelatterpreservestheresources associatedwiththestatementsothatitcanbeexecutedagain,avoidingtheneedtocallsqlite3_ prepare()tocompiletheSQLcommand. Let’sgothroughanexample.Listing6-5showsasimple,completeprogramusingapreparedquery. Itistakenfromselect.cintheexamples. Listing6-5.UsingPreparedQueries int main(int argc, char **argv) { int rc, i, ncols; sqlite3 *db; sqlite3_stmt *stmt; char *sql; const char *tail; rc = sqlite3_open_v2("foods.db", &db); if(rc) { fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db)); sqlite3_close(db); exit(1); } sql = "select * from episodes;"; rc = sqlite3_prepare_v2(db, sql, -1, &stmt, &tail); if(rc != SQLITE_OK) { fprintf(stderr, "SQL error: %s\n", sqlite3_errmsg(db)); } rc = sqlite3_step(stmt); ncols = sqlite3_column_count(stmt); 163 CHAPTER6■THECORECAPI while(rc == SQLITE_ROW) { for(i=0; i < ncols; i++) { fprintf(stderr, "'%s' ", sqlite3_column_text(stmt, i)); } fprintf(stderr, "\n"); } rc = sqlite3_step(stmt); sqlite3_finalize(stmt); sqlite3_close(db); } return 0; Thisexampleconnectstothefoods.dbdatabase,queriestheepisodestable,andprintsoutall columnsofallrecordswithinit.Keepinmindthisisasimplifiedexample—thereareafewotherthings weneedtocheckforwhencallingsqlite3_step(),suchaserrorsandbusyconditions,butwewill addressthemlater. Likesqlite3_exec(),sqlite3_prepare_v2()canacceptastringcontainingmultipleSQLstatements. However,unlikesqlite3_exec(),itwillprocessonlythefirststatementinthestring.Butitdoesmakeit easyforyoutoprocesssubsequentSQLstatementsinthestringbyprovidingthepzTailoutparameter. Afteryoucallsqlite3_prepare(),itwillpointthisparameter(ifprovided)tothestartingpositionofthe nextstatementinthezSQLstring.UsingpzTail,processingabatchofSQLcommandsinagivenstring canbeexecutedinaloopasfollows: while(sqlite3_complete(sql) ){ rc = sqlite3_prepare(db, sql, -1, &stmt, &tail); /* Process query results */ } /* Skip to next command in string. */ sql = tail; ThisexampleusesanotherAPIfunctionnotyetcovered—sqlite3_complete(),whichdoesasits namesuggests.Ittakesastringandreturnstrueifthereisatleastonecomplete(butnotnecessarily valid)SQLstatementinit,anditreturnsfalseotherwise.Inreality,sqlite_complete()looksfora semicolonterminatorforthestring(andaccountingforliteralsintheSQL).So,althoughitsname suggestssomekindofinfallibleobservercheckingyourstatements,it’sreallyjustahandytoolforthings suchasshowingyouthecontinuationpromptinthesqlitecommandlinewhenwritingmultiline statementsanddoingothersimilarusefultasks. Fetching Records Sofar,youhaveseenhowtoobtainrecordsandcolumnsfromsqlite3_exec()and sqlite3_get_table().Preparedqueries,bycomparison,offermanymoreoptionswhenitcomesto gettinginformationfromrecordsinthedatabase. 164 CHAPTER6■ THECORECAPI Forastatementthatreturnsrecords,thenumberofcolumnsintheresultsetcanbeobtainedusing sqlite3_column_count()andsqlite3_data_count(),whicharedeclaredasfollows: int sqlite3_column_count(sqlite3_stmt *pStmt); int sqlite3_data_count(sqlite3_stmt *pStmt); sqlite3_column_count()returnsthenumberofcolumnsassociatedwithastatementhandle.Youcan callitonastatementhandlebeforeitisactuallyexecuted.Ifthequeryinquestionisnotaselect statement,sqlite3_column_count()willreturn0.Similarly,sqlite3_data_count()returnsthenumberof columnsforthecurrentrecord,aftersqlite3_step()returnsSQLITE_ROW.Thisfunctionwillworkonlyif thestatementhandlehasanactivecursor. GettingColumnInformation Youcanobtainthenameofeachcolumninthecurrentrecordusingsqlite3_column_name(),whichis declaredasfollows: const char *sqlite3_column_name( sqlite3_stmt*, /* statement handle */ int iCol /* column ordinal */); Similarly,youcangettheassociatedstorageclassforeachcolumnusingsqlite3_column_type(), whichisdeclaredasfollows: int sqlite3_column_type( sqlite3_stmt*, /* statement handle */ int iCol /* column ordinal */); Thisfunctionreturnsanintegervaluethatcorrespondstooneoffivestorageclasscodes,definedas follows: #define #define #define #define #define SQLITE_INTEGER SQLITE_FLOAT SQLITE_TEXT SQLITE_BLOB SQLITE_NULL 1 2 3 4 5 TheseareSQLite’snativedatatypes,orstorageclasses,asdescribedinChapter4.Alldatastoredwithin aSQLitedatabaseisstoredinoneofthesefiveforms,dependingonitsinitialrepresentationandthe affinityofthecolumn.Forourpurposes,thetermsstorageclassanddatatypearesynonymous.Formore informationonstorageclasses,seethesections“StorageClasses”and“TypeAffinity”inChapter4. Youcanobtainthedeclareddatatypeofacolumnasitisdefinedinthetable’sschemausingthe sqlite3_column_decltype()function,whichisdeclaredasfollows: const char *sqlite3_column_decltype( sqlite3_stmt*, /* statement handle */ int /* column ordinal */); Ifacolumninaresultsetdoesnotcorrespondtoanactualtablecolumn(say,forexample,thecolumnis theresultofaliteralvalue,expression,function,oraggregate),thisfunctionwillreturnNULLasthe declaredtypeofthatcolumn.Forexample,supposeyouhaveatableinyourdatabasedefinedas follows: 165 CHAPTER6■THECORECAPI CREATE TABLE t1(c1 INTEGER); Thenyouexecutethefollowingquery: SELECT c1 + 1, 0 FROM t1; Inthiscase,sqlite3_column_decltype()willreturnINTEGERforthefirstcolumnandNULLforthesecond. Inadditiontothedeclaredtype,youcanobtainotherinformationonacolumnusingthefollowing functions: const char *sqlite3_column_database_name(sqlite3_stmt *pStmt, int iCol); const char *sqlite3_column_table_name(sqlite3_stmt *pStmt, int iCol); const char *sqlite3_column_origin_name(sqlite3_stmt *pStmt, int iCol); Thefirstfunctionwillreturnthedatabaseassociatedwithacolumn,thesecondwillreturnitstable,and thelastfunctionwillreturnthecolumn’sactualnameasdefinedintheschema.Thatis,ifyouassigned thecolumnanaliasintheSQLstatement,sqlite3_column_origin_name()willreturnitsactualnameas definedintheschema.NotethatthesefunctionsareavailableonlyifyoucompileSQLitewiththe SQLITE_ENABLE_COLUMN_METADATApreprocessordirective. GettingColumnValues Youcanobtainthevaluesforeachcolumninthecurrentrecordusingthesqlite3_column_xxx() functions,whichareofthefollowinggeneralform: xxx sqlite3_column_xxx( sqlite3_stmt*, /* statement handle */ int iCol /* column ordinal */); Herexxxisthedatatypeyouwantthedatarepresentedin(forexample,int,blob,double,andso on).Thesearethemostcommonlyusedofthesqlite3_column_xxx()functions: int sqlite3_column_int(sqlite3_stmt*, int iCol); double sqlite3_column_double(sqlite3_stmt*, int iCol); long long int sqlite3_column_int64(sqlite3_stmt*, int iCol); const void *sqlite3_column_blob(sqlite3_stmt*, int iCol); const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol); const void *sqlite3_column_text16(sqlite3_stmt*, int iCol); Foreachfunction,SQLiteconvertstheinternalrepresentation(storageclassinthecolumn)tothe typespecifiedinthefunctionname.ThereareanumberofrulesSQLiteusestoconverttheinternaldata typerepresentationtothatoftherequestedtype.Table6-1liststheserules. 166 CHAPTER6■ THECORECAPI Table6-1.ColumnTypeConversionRules Internal Type Requested Type Conversion NULL INTEGER Resultis0. NULL FLOAT Resultis0.0. NULL TEXT ResultisaNULLpointer. NULL BLOB ResultisaNULLpointer. INTEGER FLOAT Convertfromintegertofloat. INTEGER TEXT ResultistheASCIIrenderingoftheinteger. INTEGER BLOB ResultistheASCIIrenderingoftheinteger. FLOAT INTEGER Convertfromfloattointeger. FLOAT TEXT ResultistheASCIIrenderingofthefloat. FLOAT BLOB ResultistheASCIIrenderingofthefloat. TEXT INTEGER Useatoi(). TEXT FLOAT Useatof(). TEXT BLOB Nochange. BLOB INTEGER ConverttoTEXTandthenuseatoi(). BLOB FLOAT ConverttoTEXTandthenuseatof(). BLOB TEXT Adda\000terminatorifneeded. Likethesqlite3_bind_xxx()functionsdescribedlater,BLOBsrequirealittlemoreworkinthatyou mustspecifytheirlengthinordertocopythem.ForBLOBcolumns,youcangettheactuallengthofthe datausingsqlite3_column_bytes(),whichisdeclaredasfollows: int sqlite3_column_bytes( sqlite3_stmt*, /* statement handle */ int /* column ordinal */); Onceyougetthelength,youcancopythebinarydatausingsqlite3_column_blob().Forexample, saythefirstcolumnintheresultsetcontainsbinarydata.Onewaytogetacopyofthatdatawouldbeas follows: 167 CHAPTER6■THECORECAPI int len = sqlite3_column_bytes(stmt,0); void* data = malloc(len); memcpy(data, len, sqlite3_column_blob(stmt,0)); APracticalExample Tohelpsolidifyallthesecolumnfunctions,Listing6-6(takenfromcolumns.c)illustratesusingthe functionswe’vedescribedtoretrievecolumninformationandvaluesforasimpleselectstatement. Listing6-6.ObtainingColumnInformation int main(int argc, char **argv) { int rc, i, ncols, id, cid; char *name, *sql; sqlite3 *db; sqlite3_stmt *stmt; sql = "select id, name from episodes"; sqlite3_open_v2("test.db", &db); sqlite3_prepare_v2(db, sql, strlen(sql), &stmt, NULL); ncols = sqlite3_column_count(stmt); rc = sqlite3_step(stmt); /* Print column information */ for(i=0; i < ncols; i++) { fprintf(stdout, "Column: name=%s, storage class=%i, declared=%s\n", sqlite3_column_name(stmt, i), sqlite3_column_type(stmt, i), sqlite3_column_decltype(stmt, i)); } fprintf(stdout, "\n"); while(rc == SQLITE_ROW) { id = sqlite3_column_int(stmt, 0); cid = sqlite3_column_int(stmt, 1); name = sqlite3_column_text(stmt, 2); if(name != NULL){ fprintf(stderr, "Row: id=%i, cid=%i, name='%s'\n", id,cid,name); } else { /* Field is NULL */ fprintf(stderr, "Row: id=%i, cid=%i, name=NULL\n", id,cid); } rc = sqlite3_step(stmt); } 168 CHAPTER6■ THECORECAPI sqlite3_finalize(stmt); sqlite3_close(db); return 0; } Thisexampleconnectstothedatabase,selectsrecordsfromtheepisodestable,andprintsthe columninformationandthefieldsforeachrow(usingtheirinternalstorageclass).Runningtheprogram producesthefollowingoutput: Column: name=id, storage class=1, declared=integer Column: name=name, storage class=3, declared=text Row: Row: Row: id=1, name='The Dinner Party' id=2, name='The Soup Nazi' id=3, name='The Fusilli Jerry' FINDING A STATEMENT'S CONNECTION Inpractice,youmayfindyourselfwritingcodewheresomeofyourfunctionshaveaccessonlytothe statementhandle,nottheconnectionhandle.Ifthesefunctionsencounteranerrorwhileworkingwiththe statementhandle,theywillnothaveawaytogeterrorinformationfromsqlite3_errmsg(),becauseit requiresaconnectionhandletowork.Thisiswheresqlite3_db_handle()comesinhandy.Itisdeclared asfollows: int sqlite3_db_handle(sqlite3_stmt*); Givenastatementhandle,sqlite3_db_handle()returnstheassociatedconnectionhandle.Thisway,you don’tneedtoworryabouthavingtopasstheconnectionhandlealongwiththestatementhandle everywhereyouprocessqueryresults. Parameterized Queries TheAPIincludessupportfordesignatingparametersinaSQLstatement,allowingyoutoprovide(or “bind”)valuesforthematalatertime.Boundparametersareusedinconjunctionwith sqlite3_prepare().Forexample,youcouldcreateaSQLstatementlikethefollowing: insert into foo values (?,?,?); Thenyoucan,forexample,bindtheintegervalue2tothefirstparameter(designatedbythefirst? character),thestringvalue'pi'tothesecondparameter,andthedoublevalue3.14forthethird parameter,asillustratedinthefollowingcode(takenfromparameters.c): const char* sql = "insert into foo values(?,?,?)"; sqlite3_prepare(db, sql, strlen(sql), &stmt, &tail); 169 CHAPTER6■THECORECAPI sqlite3_bind_int(stmt, 1, 2); sqlite3_bind_text(stmt, 2, "pi"); sqlite3_bind_double(stmt, 3, 3.14); sqlite3_step(stmt); sqlite3_finalize(stmt); Thisgeneratesandexecutesthefollowingstatement: insert into foo values (2, 'pi', 3.14) Thisparticularmethodofbindingusespositionalparameters(asdescribedinChapter5)where eachparameterisdesignatedbyaquestionmark(?)characterandlateridentifiedbyitsindexorrelative positionintheSQLstatement. Beforedelvingintotheotherparametermethods,itishelpfultofirstunderstandtheprocessby whichparametersaredefined,bound,andevaluated.Whenyouwriteaparameterizedstatementsuch asthefollowing,theparameterswithinitareidentifiedwhensqlite3_prepare()compilesthequery: insert into episodes (id,name) values (?,?) sqlite3_prepare()recognizesthatthereareparametersinaSQLstatement.Internally,itassigns eachparameteranumbertouniquelyidentifyit.Inthecaseofpositionalparameters,itstartswith1for thefirstparameterfoundandusessequentialintegervaluesforsubsequentparameters.Itstoresthis informationintheresultingstatementhandle(sqlite3_stmtstructure),whichwillthenexpectaspecific numberofvaluestobeboundtothegivenparametersbeforeexecution.Ifyoudonotbindavaluetoa parameter,sqlite3_step()willuseNULLforitsvaluebydefaultwhenthestatementisexecuted. Afteryoupreparethestatement,youthenbindvaluestoit.Youdothisusingthe sqlite3_bind_xxx()functions,whichhavethefollowinggeneralform: sqlite3_bind_xxx( sqlite3_stmt*, /* statement handle */ int i, /* parameter number */ xxx value /* value to be bound */ ); Thexxxinthefunctionnamerepresentsthedatatypeofthevaluetobind.Forexample,tobinda doublevaluetoaparameter,youwouldusesqlite3_bind_double(),whichisdeclaredasfollows: sqlite3_bind_double(sqlite3_stmt* stmt, int i, double value); Thecommonbindfunctionsareasfollows: int int int int int int int int 170 sqlite3_bind_int(sqlite3_stmt*, int, int); sqlite3_bind_double(sqlite3_stmt*, int, double); sqlite3_bind_int64(sqlite3_stmt*, int, long long int); sqlite3_bind_null(sqlite3_stmt*, int); sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*)); sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n); sqlite3_bind_text(sqlite3_stmt*, int, const char*, int n, void(*)(void*)); sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int n, void(*)(void*)); CHAPTER6■ THECORECAPI Ingeneral,thebindfunctionscanbedividedintotwoclasses,oneforscalarvalues(int,double, int64,andNULL)andtheotherforarrays(blob,text,andtext16).Theydifferonlyinthatthearraybind functionsrequirealengthargumentandapointertoacleanupfunction.Also,sqlite3_bind_text() automaticallyescapesquotecharacterslikesqlite3_mprintf().UsingtheBLOBvariant,thearraybind functionhasthefollowingdeclaration: int sqlite3_bind_blob( sqlite3_stmt*, int, const void*, int n, void(*)(void*)); /* /* /* /* /* statement handle ordinal pointer to blob data length (bytes) of data cleanup hander */ */ */ */ */ TherearetwopredefinedvaluesforthecleanuphandlerprovidedbytheAPIthathavespecialmeanings, definedasfollows: #define SQLITE_STATIC #define SQLITE_TRANSIENT ((void(*)(void *))0) ((void(*)(void *))-1) Eachvaluedesignatesaspecificcleanupaction.SQLITE_STATICtellsthearraybindfunctionthatthe arraymemoryresidesinunmanagedspace,soSQLitedoesnotattempttocleanitup.SQLITE_TRANSIENT tellsthebindfunctionthatthearraymemoryissubjecttochange,soSQLitemakesitsownprivatecopy ofthedata,whichitautomaticallycleansupwhenthestatementisfinalized.Thethirdoptionisto provideapointertoyourowncleanupfunction,whichmustbeofthefollowingform: void cleanup_fn(void*) Ifprovided,SQLitewillcallyourcleanupfunction,passinginthearraymemorywhenthestatementis finalized. ■NoteBoundparametersremainboundthroughoutthelifetimeofthestatementhandle.Theyremainboundeven afteracalltosqlite3_reset()andarefreedonlywhenthestatementisfinalized(bycallingsqlite3_ finalize()). Onceyouhaveboundalltheparametersyouwant,youcanthenexecutethestatement.Youdothis usingthenextfunctioninthesequence:sqlite3_step().sqlite3_step()willtaketheboundvalues, substitutethemfortheparametersintheSQLstatement,andthenbeginexecutingthecommand. Nowthatyouunderstandthebindingprocess,thefourparameter-bindingmethodsdifferonlyby thefollowing: • ThewayinwhichparametersarerepresentedintheSQLstatement(usinga positionalparameter,explicitlydefinedparameternumber,oralphanumeric parametername) • Thewayinwhichparametersareassignednumbers 171 CHAPTER6■THECORECAPI Forpositionalparameters,sqlite3_prepare()assignsnumbersusingsequentialintegervalues startingwith1forthefirstparameter.Inthepreviousexample,thefirst?parameterisassigned1,and thesecond?parameterisassigned2.Withpositionalparameters,itisyourjobtokeeptrackofwhich numbercorrespondstowhichparameter(orquestionmark)intheSQLstatementandcorrectlyspecify thatnumberinthebindfunctions. NumberedParameters Numberedparameters,ontheotherhand,allowyoutospecifyyourownnumbersforparameters, ratherthanuseaninternalsequence.Thesyntaxfornumberedparametersusesaquestionmark followedbytheparameternumber.Take,forexample,thefollowingpieceofcode(takenfrom parameters.c): name = "Mackinaw Peaches"; sql = "insert into episodes (id, cid, name) " "values (?100,?100,?101)"; rc = sqlite3_prepare(db, sql, strlen(sql), &stmt, &tail); if(rc != SQLITE_OK) { fprintf(stderr, "sqlite3_prepare() : Error: %s\n", tail); return rc; } sqlite3_bind_int(stmt, 100, 10); sqlite3_bind_text(stmt, 101, name, strlen(name), SQLITE_TRANSIENT); sqlite3_step(stmt); sqlite3_finalize(stmt); Thisexampleuses100and101foritsparameternumbers.Parameternumber100hastheinteger value10boundtoit.Parameter101hasthestringvalue'Mackinaw Peaches'boundtoit.Notehow numberedparameterscomeinhandywhenyouneedtobindasinglevalueinmorethanoneplaceina SQLstatement.ConsiderthevaluespartofthepreviousSQLstatement: insert into episodes (id, cid, name) values (?100,?100,?101)"; Parameter100isbeingusedtwice—onceforidandagainforcid.Thus,numberedparameterssavetime whenyouneedtouseaboundvalueinmorethanoneplace. ■NoteWhenusingnumberedparametersinaSQLstatement,keepinmindthattheallowablerangeconsistsof theintegervalues1–999,andforoptimalperformanceandmemoryutilization,youshouldchoosesmaller numbers. 172 CHAPTER6■ THECORECAPI NamedParameters Thethirdparameterbindingmethodisusingnamedparameters.Whereasyoucanassignyourown numbersusingnumberedparameters,youcanassignalphanumericnameswithnamedparameters. Likewise,becausenumberedparametersareprefixedwithaquestionmark(?),youidentifynamed parametersbyprefixingacolon(:)orat-sign(@)totheparametername.Considerthefollowingcode snippet(takenfromparameters.c): name = "Mackinaw Peaches"; sql = "insert into episodes (id, cid, name) values (:cosmo,:cosmo,@newman)"; rc = sqlite3_prepare(db, sql, strlen(sql), &stmt, &tail); sqlite3_bind_int( stmt, sqlite3_bind_parameter_index(stmt, ":cosmo"), 10); sqlite3_bind_text( stmt, sqlite3_bind_parameter_index(stmt, "@newman"), name, strlen(name), SQLITE_TRANSIENT ); sqlite3_step(stmt); sqlite3_finalize(stmt); Thisexampleisidenticaltothepreviousexampleusingnumberedparameters,exceptitusestwo namedparameterscalled:cosmoand@newmaninstead.Likepositionalparameters,namedparameters areautomaticallyassignednumbersbysqlite3_prepare().Althoughthenumbersassignedtoeach parameterareunknown,youcanresolvethemusingsqlite3_bind_parameter_index(),whichtakes aparameternameandreturnsthecorrespondingparameternumber.Thisisthenumberyouuseto bindthevaluetoitsparameter.Allinall,namedparametersmainlyhelpwithlegibilitymorethan anythingelse. ■NoteWhilethefunctionsqlite3_bind_parameter_index()seemstorefertoaparameternumberasan index,forallintentsandpurposesthetwoterms(numberandindex)aresynonymous. TclParameters ThefinalparameterschemeiscalledTclparametersandisspecificmoretotheTclextensionthanitisto theCAPI.Basically,itworksidenticallytonamedparametersexceptthatratherthanusing alphanumericvaluesforparameternames,itusesTclvariablenames.IntheTclextension,whentheTcl equivalentofsqlite3_prepare()iscalled,theTclextensionautomaticallysearchesforTclvariableswith thegivenparameternamesintheactiveTclprogramenvironmentandbindsthemtotheirrespective parameters.DespiteitscurrentapplicationintheTclinterface,nothingprohibitsthissamemechanism frombeingappliedtootherlanguageinterfaces,whichcaninturnimplementthesamefeature.Inthis respect,referringtothisparametermethodsolelyasTclparametersmaybeabitofamisnomer.TheTcl extensionjusthappenedtobethefirstapplicationthatutilizedthismethod.Basically,theTclparameter 173 CHAPTER6■THECORECAPI syntaxdoeslittlemorethanprovideanalternatesyntaxtonamedparameters—ratherthanprefixingthe parameterswithacolon(:)oranat-sign(@),itusesadollarsign($). Errors and the Unexpected Uptonow,wehavelookedattheAPIfromaratheroptimisticviewpoint,asifnothingcouldevergo wrong.Butthingsdogowrong,andthereispartoftheAPIdevotedtothat.Thethreethingsyoualways havetoguardagainstinyourcodeareerrors,busyconditions,and,mypersonalfavorite,schema changes. HandlingErrors ManyoftheAPIfunctionsreturnintegerresultcodes.Thatmeanstheycanpotentiallyreturnerror codesofsomesort.Themostcommonfunctionstowatcharetypicallythemostfrequentlyused,suchas sqlite3_open_v2(),sqlite3_prepare_v2(),andfriends,aswellassqlite3_exec().Youshouldalways programdefensivelyandrevieweveryAPIfunctionbeforeyouuseittoensurethatyoudealwitherror conditionsthatcanarise.OfalltheerrorresultsdefinedinSQLite,onlyafractionofthemwillreally mattertoyourapplicationinpractice.AlloftheSQLiteresultcodesarelistedinTable6-2.APIfunctions thatcanreturnthemincludethefollowing: sqlite3_bind_xxx() sqlite3_close() sqlite3_create_collation() sqlite3_collation_needed() sqlite3_create_function() sqlite3_prepare_v2() sqlite3_exec() sqlite3_finalize() sqlite3_get_table() sqlite3_open_v2() sqlite3_reset() sqlite3_step() Youcangetextendedinformationonagivenerrorusingsqlite3_errmsg(),whichisdeclaredasfollows: const char *sqlite3_errmsg(sqlite3*); IttakesaconnectionhandleasitsonlyargumentandreturnsthemostrecenterrorresultingfromanAPI callonthatconnection.Ifnoerrorhasbeenencountered,itreturnsthestring“notanerror.” 174 CHAPTER6■ THECORECAPI Table6-2.SQLiteResultCodes Code Description SQLITE_OK Theoperationwassuccessful. SQLITE_ERROR GeneralSQLerrorormissingdatabase.Itmaybepossibletoobtainmore errorinformationdependingontheerrorcondition(SQLITE_SCHEMA,for example). SQLITE_INTERNAL Internallogicerror. SQLITE_PERM Accesspermissiondenied. SQLITE_ABORT Acallbackroutinerequestedanabort. SQLITE_BUSY Thedatabasefileislocked. SQLITE_LOCKED Atableinthedatabaseislocked. SQLITE_NOMEM Acalltomalloc()hasfailedwithinadatabaseoperation. SQLITE_READONLY Anattemptwasmadetowritetoaread-onlydatabase. SQLITE_INTERRUPT Operationwasterminatedbysqlite3_interrupt(). SQLITE_IOERR SomekindofdiskI/Oerroroccurred. SQLITE_CORRUPT Thedatabasediskimageismalformed.Thiswillalsooccurifanattemptis madetoopenanon-SQLitedatabasefileasaSQLitedatabase. SQLITE_FULL Insertionfailedbecausethedatabaseisfull.Thereisnomorespaceonthe filesystemorthedatabasefilecannotbeexpanded. SQLITE_CANTOPEN SQLitewasunabletoopenthedatabasefile. SQLITE_PROTOCOL Thedatabaseislockedortherehasbeenaprotocolerror. SQLITE_EMPTY (Internalonly.)Thedatabasetableisempty. SQLITE_SCHEMA Thedatabaseschemahaschanged. SQLITE_CONSTRAINT Abortduetoconstraintviolation. 175 CHAPTER6■THECORECAPI Continued Code Description SQLITE_MISMATCH Datatypemismatch.Anexampleofthisisanattempttoinsert nonintegerdataintoacolumnlabeledINTEGER PRIMARY KEY.Formost columns,SQLiteignoresthedatatypeandallowsanykindofdatatobe stored.ButanINTEGER PRIMARY KEYcolumnisallowedtostoreinteger dataonly. SQLITE_MISUSE Librarywasusedincorrectly.Thiserrormightoccurifoneormoreofthe SQLiteAPIroutinesisusedincorrectly. SQLITE_NOLFS UsesOSfeaturesnotsupportedonhost.Thisvalueisreturnedifthe SQLitelibrarywascompiledwithlargefilesupport(LFS)enabledbutLFS isn’tsupportedonthehostoperatingsystem. SQLITE_AUTH Authorizationdenied.Thisoccurswhenacallbackfunctioninstalled usingsqlite3_set_authorizer()returnsSQLITE_DENY. SQLITE_FORMAT Auxiliarydatabaseformaterror. SQLITE_RANGE Secondparametertosqlite3_bind()outofrange. SQLITE_NOTADB FileopenedisnotaSQLitedatabasefile. SQLITE_ROW sqlite3_step()hasanotherrowready. SQLITE_DONE sqlite3_step()hasfinishedexecuting. Althoughitisveryuncommonoutsideofembeddedsystems,oneofthemostcriticalerrorsyoucan encounterisSQLITE_NOMEM,whichmeansthatnomemorycanbeallocatedontheheap(forexample, malloc()failed).SQLiteisquiterobustinthisregard,recoveringgracefullyfromout-of-memoryerror conditions.Itwillcontinuetoworkassumingtheunderlyingoperatingsystemcompletesmemory allocationsystemcallslikemalloc(). HandlingBusyConditions Twoimportantfunctionsrelatedtoprocessingqueriesaresqlite3_busy_handler()and sqlite3_busy_timeout().Ifyourprogramusesadatabaseonwhichthereareotheractiveconnections, oddsareitwilleventuallyhavetowaitforalockandthereforewillhavetodealwithSQLITE_BUSY. WheneveryoucallanAPIfunctionthatcausesSQLitetoseekalockandSQLiteisunabletogetit,the functionwillreturnSQLITE_BUSY.Therearethreewaystodealwiththis: 176 CHAPTER6■ THECORECAPI • HandleSQLITE_BUSYyourself,eitherbyrerunningthestatementorbytakingsome otheraction • HaveSQLitecallabusyhandler • AskSQLitetowait(blockorsleep)forsomeperiodoftimeforthelocktoclear Thelastoptioninvolvesusingsqlite3_busy_timeout().ThisfunctiontellsSQLitehowlongtowaitfora locktoclearbeforereturningSQLITE_BUSY.Althoughitcanultimatelyresultinyoustillhavingtohandle SQLITE_BUSY,inpracticesettingthisvaluetoasufficientperiodoftime(say30seconds)usuallyprovides enoughtimeforeventhemostintensivetransactiontocomplete.Nevertheless,youshouldstillhave somecontingencyplaninplacetohandleSQLITE_BUSY. User-Defined Busy Handlers Thesecondoptionentailsusingsqlite3_busy_handler().ThisfunctionprovidesawaytocallauserdefinedfunctionratherthanblockingorreturningSQLITE_BUSYrightaway.It’sdeclaredasfollows: int sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*); Thesecondargumentisapointertoafunctiontobecalledasthebusyhandler,andthethird argumentisapointertoapplication-specificdatatobepassedasthefirstargumenttothehandler.The secondargumenttothebusyhandleristhenumberofpriorcallsmadetothehandlerforthesamelock. Suchahandlermightcallsleep()foraperiodtowaitoutthelock,oritmaysendsomekindof notification.Itmaydowhateveryoulike,becauseitisyourstoimplement.Bewarned,though,that registeringabusyhandlerdoesnotguaranteethatitwillalwaysbecalled.AsmentionedinChapter5, SQLitewillforegocallingabusyhandlerforaconnectionifitperceivesadeadlockmightresult. Specifically,ifyourconnectioninSHAREDisinterferingwithanotherconnectioninRESERVED,SQLitewill notinvokeyourbusyhandler,hopingyouwilltakethehint.Inthiscase,youaretryingtowritetothe databasefromSHARED(startingthetransactionwithBEGIN)whenyoureallyshouldbestartingfrom RESERVED(startingthetransactionwithBEGIN IMMEDIATE). Theonlyrestrictiononbusyhandlersisthattheymaynotclosethedatabase.Closingthedatabase fromwithinabusyhandlercandeletecriticaldatastructuresoutfromundertheexecutingqueryand resultincrashingyourprogram. Advice Allthingsconsidered,thebestroutemaybetosetthetimeouttoareasonablevalueandthentakesome precautionsifandwhenyoureceiveaSQLITE_BUSYvalue.Ingeneral,ifyouaregoingtowritetothe database,startinRESERVED.Ifyoudon’tdothis,thenthenextbestthingistoinstallabusyhandler,set thetimeouttoaknownvalue,andifSQLitereturnsSQLITE_BUSY,checktheresponsetime.Ifthetimeis lessthanthebusyhandler’sdelay,thenSQLiteistellingyouthatyourquery(andconnection)is preventingawriterfromproceeding.Ifyouwanttowritetothedatabaseatthispoint,youshould finalizeorresetandthenreexecutethestatement,thistimestartingwithBEGIN IMMEDIATE. HandlingSchemaChanges Wheneveraconnectionchangesthedatabaseschema,allotherpreparedstatementsthatwerecompiled beforethechangeareinvalidated.Theresultisthatthefirstcalltosqlite3_step()forsuchstatements 177 CHAPTER6■THECORECAPI willattempttorecompiletherelevantSQLandproceednormallyfromthereifpossible.Ifrecompilation isimpossible(forexample,ifanobjecthasbeendroppedentirely),thesqlite3_step()returns SQLITE_SCHEMA.Fromalockingstandpoint,theschemachangeoccursbetweenthetimeareadercalls sqlite3_prepare()tocompileastatementandcallingsqlite3_step()toexecuteit. Whenthishappens,theonlycourseofactionforyouistohandlethechangeincircumstancesand startover.SeveraleventscancauseSQLITE_SCHEMAerrors: • Detachingdatabases • Modifyingorinstallinguser-definedfunctionsoraggregates • Modifyingorinstallinguser-definedcollations • Modifyingorinstallingauthorizationfunctions • Vacuumingthedatabase ThereasontheSQLITE_SCHEMAconditionexistsultimatelyrelatestotheVDBE.Whenaconnection changestheschema,othercompiledqueriesmayhaveVDBEcodethatpointstodatabaseobjectsthat nolongerexistorareinadifferentlocationinthedatabase.Ratherthanrunningtheriskofabizarre runtimeerrorlater,SQLiteinvalidatesallstatementsthathavebeencompiledbutnotexecuted.They mustberecompiled. TRACING SQL Ifyouarehavingahardtimefiguringoutexactlywhatyourprogramisdoingwiththedatabase,youcan trackwhatSQLstatementsithasexecutedusingsqlite3_trace().Itsdeclarationisasfollows: void *sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*); Thisfunctionisanalogoustoputtingawiretaponaconnection.Youcanuseittogeneratealogfileofall SQLexecutedonagivenconnectionaswellprovidehelpfuldebugginginformation.EverySQLstatement thatisprocessedispassedtothecallbackfunctionspecifiedinthesecondargument.SQLitepassesthe dataprovidedinthethirdargumentofsqlite3_trace()tothefirstargumentofthecallbackfunction. Operational Control TheAPIprovidesseveralfunctionsyoucanusetomonitorand/ormanageSQLcommandsatcompile timeandruntime.Thesefunctionsallowyoutoinstallcallbackfunctionswithwhichtomonitorand controlvariousdatabaseeventsastheyhappen. CommitHooks Thesqlite3_commit_hook()functionallowsyoutomonitorwhentransactionscommitonagiven connection.Itisdeclaredasfollows: 178 CHAPTER6■ THECORECAPI void *sqlite3_commit_hook( sqlite3 *cnx, /* database handle */ int(*xCallback)(void *data), /* callback function */ void *data); /* application data */ ThisfunctionregistersthecallbackfunctionxCallback,whichwillbeinvokedwhenevera transactioncommitsontheconnectiongivenbycnx.Thethirdargument(data)isapointerto application-specificdata,whichSQLitepassestothecallbackfunction.Ifthecallbackfunctionreturnsa nonzerovalue,thenthecommitisconvertedintoarollback. PassingaNULLvalueinforthecallbackfunctioneffectivelydisablesthecurrentlyregisteredcallback (ifany).Also,onlyonecallbackcanberegisteredatatimeforagivenconnection.Thereturnvaluefor sqlite3_commit_hook()isNULLunlessanothercallbackfunctionwaspreviouslyregistered,inwhichcase thepreviousdatavalueisreturned. RollbackHooks Rollbackhooksaresimilartocommithooksexceptthattheywatchforrollbacksforagivenconnection. Rollbackhooksareregisteredwiththefollowingfunction: void *sqlite3_rollback_hook(sqlite3 *cnx, void(*xCallback)(void *data), void *data); ThisfunctionregistersthecallbackfunctionxCallback,whichwillbeinvokedintheeventofa rollbackoncnx,whetherbyanexplicitROLLBACKcommandorbyanimpliciterrororconstraintviolation. Thecallbackisnotinvokedifatransactionisautomaticallyrolledbackbecauseofthedatabase connectionbeingclosed.Thethirdargument(data)isapointertoapplication-specificdata,which SQLitepassestothecallbackfunction. Asinsqlite3_commit_hook(),eachtimeyoucallsqlite3_rollback_hook(),thenewcallback functionyouprovidewillreplaceanycurrentlyregisteredcallbackfunction.Ifacallbackfunctionwas previouslyregistered,sqlite3_rollback_hook()returnsthepreviousdataargument. UpdateHooks Thesqlite3_update_hook()isusedtomonitorallupdate,insert,anddeleteoperationsonrowsfora givendatabaseconnection.Ithasthefollowingform: void *sqlite3_update_hook( sqlite3 *cnx, void(*)(void *, int, char const*, char const*, sqlite_int64), void *data); Thefirstargumentofthecallbackfunctionisapointertoapplication-specificdata,whichyouprovidein thethirdargument.Thecallbackfunctionhasthefollowingform: void callback ( void * data, int operation_code, char const *db_name, char const *table_name, sqlite_int64 rowid), 179 CHAPTER6■THECORECAPI Theoperation_codeargumentcorrespondstoSQLITE_INSERT,SQLITE_UPDATE,andSQLITE_DELETEfor insert,update,anddeleteoperations,respectively.Thethirdandfourthargumentscorrespondtothe databasenameandtablenametheoperationtookplaceon.Thefinalargumentistherowidofthe affectedrow.Thecallbackisnotinvokedforoperationsonsystemtables(forexample,sqlite_master andsqlite_sequence).Thereturnvalueisapointertothepreviouslyregisteredcallbackfunction’sdata argument,ifitexists. AuthorizerFunctions Perhapsthemostpowerfuleventfilterissqlite3_set_authorizer().Itallowsyoutomonitorandcontrol queriesastheyarecompiled.Thisfunctionisdeclaredasfollows: int sqlite3_set_authorizer( sqlite3*, int (*xAuth)( void*,int, const char*, const char*, const char*,const char*), void *pUserData ); Thisroutineregistersacallbackfunctionthatservesasanauthorizationfunction.SQLitewillinvoke thecallbackfunctionatstatementcompiletime(notatexecutiontime)forvariousdatabaseevents.The intentofthefunctionistoallowapplicationstosafelyexecuteuser-suppliedSQL.Itprovidesawayto restrictsuchSQLfromcertainoperations(forexample,anythingthatchangesthedatabase)ortodeny accesstospecifictablesorcolumnswithinthedatabase. Forclarity,theformoftheauthorizationcallbackfunctionisasfollows: int auth( void*, int, const char*, const char*, const char*, const char* /* /* /* /* /* /* user data */ event code */ event specific */ event specific */ database name */ trigger or view name */ ); Thefirstargumentisapointertoapplication-specificdata,whichispassedinonthefourth argumentofsqlite3_set_authorizer().Thesecondargumenttotheauthorizationfunctionwillbeone ofthedefinedconstantslistedinTable6-3.Thesevaluessignifywhatkindofoperationistobe authorized.Thethirdandfourthargumentstotheauthorizationfunctionarespecifictotheeventcode. TheseargumentsarelistedwiththeirrespectiveeventcodesshownearlierinTable6-2. Thefifthargumentisthenameofthedatabase(main,temp,andsoon)ifapplicable.Thesixth argumentisthenameoftheinnermosttriggerorviewthatisresponsiblefortheaccessattemptorNULLif thisaccessattemptisdirectlyfromtop-levelSQL. ThereturnvalueoftheauthorizationfunctionshouldbeoneoftheconstantsSQLITE_OK, SQLITE_DENY,orSQLITE_IGNORE.Themeaningofthefirsttwovaluesisconsistentforallevents—permitor denytheSQLstatement.SQLITE_DENYwillaborttheentireSQLstatementandgenerateanerror. ThemeaningofSQLITE_IGNOREisspecifictotheeventinquestion.Statementsthatreadormodify recordsgenerateSQLITE_READorSQLITE_UPDATEeventsforeachcolumnthestatementattemptsto operateon.Inthiscase,ifthecallbackreturnsSQLITE_IGNORE,thecolumninquestionwillbeexcluded fromtheoperation.Specifically,attemptstoreaddatafromthiscolumnyieldonlyNULLvalues,and attemptstoupdateitwillsilentlyfail. 180 CHAPTER6■ THECORECAPI Table6-3.SQLiteAuthorizationEvents Event Code Argument 3 Argument 4 SQLITE_CREATE_INDEX Indexname Tablename SQLITE_CREATE_TABLE Tablename NULL SQLITE_CREATE_TEMP_INDEX Indexname Tablename SQLITE_CREATE_TEMP_TABLE Tablename NULL SQLITE_CREATE_TEMP_TRIGGER Triggername Tablename SQLITE_CREATE_TEMP_VIEW Viewname NULL SQLITE_CREATE_TRIGGER Triggername Tablename SQLITE_CREATE_VIEW Viewname NULL SQLITE_DELETE Tablename NULL SQLITE_DROP_INDEX Indexname Tablename SQLITE_DROP_TABLE Tablename NULL SQLITE_DROP_TEMP_INDEX Indexname Tablename SQLITE_DROP_TEMP_TABLE Tablename NULL SQLITE_DROP_TEMP_TRIGGER Triggername Tablename SQLITE_DROP_TEMP_VIEW Viewname NULL SQLITE_DROP_TRIGGER Triggername Tablename SQLITE_DROP_VIEW Viewname NULL SQLITE_INSERT Tablename NULL SQLITE_PRAGMA Pragmaname FirstargumentorNULL SQLITE_READ Tablename Columnname SQLITE_SELECT NULL NULL 181 CHAPTER6■THECORECAPI Continued Event Code Argument 3 SQLITE_TRANSACTION NULL Argument 4 NULL SQLITE_UPDATE Tablename Columnname SQLITE_ATTACH Filename NULL SQLITE_DETACH Databasename NULL Toillustratethis,thefollowingexample(thecompletesourceofwhichisinauthorizer.c)willcreate atablefoo,definedasfollows: create table foo(x int, y int, z int) Itregistersanauthorizerfunction,whichwilldothefollowing: • Blockreadsofcolumnz • Blockupdatestocolumnx • MonitorATTACHandDETACHdatabaseevents • Logdatabaseeventsastheyhappen Thisisaratherlongexample,whichusestheauthorizerfunctiontofiltermanydifferentdatabase events,soforclarityIamgoingtobreakthecodeintopieces.Theauthorizerfunctionhasthegeneral formshowninListing6-7. Listing6-7.ExampleAuthorizerFunction int auth( void* const const { const char* printf( " /* ** ** ** */ x, int type, char* a, const char* b, char* c, const char* d ) operation = a; %s ", event_description(type)); Filter for different database events from SQLITE_TRANSACTION to SQLITE_INSERT, UPDATE, DELETE, ATTACH, etc. and either allow or deny them. return SQLITE_OK; } 182 CHAPTER6■ THECORECAPI Thefirstthingtheauthorizerlooksforisachangeintransactionstate.Ifitfindsachange,itprintsa message: if((a != NULL) && (type == SQLITE_TRANSACTION)) { printf(": %s Transaction", operation); } Nexttheauthorizerfilterseventsthatresultinaschemachange: switch(type) { case SQLITE_CREATE_INDEX: case SQLITE_CREATE_TABLE: case SQLITE_CREATE_TRIGGER: case SQLITE_CREATE_VIEW: case SQLITE_DROP_INDEX: case SQLITE_DROP_TABLE: case SQLITE_DROP_TRIGGER: case SQLITE_DROP_VIEW: { // Schema has been modified somehow. printf(": Schema modified"); } Thenextfilterlooksforreadattempts(whicharefiredonacolumn-by-columnbasis).Here,allread attemptsareallowedunlessthecolumnnameisz,inwhichcasethefunctionreturnsSQLITE_IGNORE. ThiswillcauseSQLitetoreturnNULLforanyfieldincolumnz,effectivelyblockingaccesstoitsdata. if(type == SQLITE_READ) { printf(": Read of %s.%s ", a, b); } /* Block attempts to read column z */ if(strcmp(b,"z")==0) { printf("-> DENIED\n"); return SQLITE_IGNORE; } Nextcomeinsertandupdatefilters.Allinsertstatementsareallowed.However,updatestatements thatattempttomodifycolumnxaredenied.Thiswillnotblocktheupdatestatementfromexecuting; rather,itwillsimplyfilteroutanyattempttoupdatecolumnx. if(type == SQLITE_INSERT) { printf(": Insert records into %s ", a); } if(type == SQLITE_UPDATE) { printf(": Update of %s.%s ", a, b); 183 CHAPTER6■THECORECAPI } /* Block updates of column x */ if(strcmp(b,"x")==0) { printf("-> DENIED\n"); return SQLITE_IGNORE; } Finally,theauthorizerfiltersdelete,attach,anddetachstatementsandsimplyissuesnotifications whenitencountersthem: if(type == SQLITE_DELETE) { printf(": Delete from %s ", a); } if(type == SQLITE_ATTACH) { printf(": %s", a); } if(type == SQLITE_DETACH) { printf("-> %s", a); } } printf("\n"); return SQLITE_OK; The(abbreviated)programisimplementedasfollows.Aswiththeauthorizerfunction,Iwillbreakit intopieces.Thefirstpartoftheprogramconnectstothedatabaseandregisterstheauthorization function: int main(int argc, char **argv) { sqlite3 *db, *db2; char *zErr, *sql; int rc; /** Setup */ /* Connect to test.db */ rc = sqlite3_open_v2("test.db", &db); /** Authorize and test /* 1. Register the authorizer function */ sqlite3_set_authorizer(db, auth, NULL); 184 CHAPTER6■ THECORECAPI Step2illustratesthetransactionfilter: /* 2. Test transactions events */ printf("program : Starting transaction\n"); sqlite3_exec(db, "BEGIN", NULL, NULL, &zErr); printf("program : Committing transaction\n"); sqlite3_exec(db, "COMMIT", NULL, NULL, &zErr); Step3testsschemamodificationsbycreatingthetesttablefoo: /* 3. Test table events */ printf("program : Creating table\n"); sqlite3_exec(db, "create table foo(x int, y int, z int)", NULL, NULL, &zErr); Step4testsread(select)andwrite(insert/update)control.Itinsertsatestrecord,selectsit,updatesit, andselectsitagaintoobservetheresultsoftheupdate. /* 4. Test read/write access */ printf("program : Inserting record\n"); sqlite3_exec(db, "insert into foo values (1,2,3)", NULL, NULL, &zErr); printf("program : Selecting record (value for z should be NULL)\n"); print_sql_result(db, "select * from foo"); printf("program : Updating record (update of x should be denied)\n"); sqlite3_exec(db, "update foo set x=4, y=5, z=6", NULL, NULL, &zErr); printf("program : Selecting record (notice x was not updated)\n"); print_sql_result (db, "select * from foo"); printf("program : Deleting record\n"); sqlite3_exec(db, "delete from foo", NULL, NULL, &zErr); printf("program : Dropping table\n"); sqlite3_exec(db, "drop table foo", NULL, NULL, &zErr); Severalthingsaregoingonhere.Theprogramselectsallrecordsinthetable,oneofwhichiscolumnz. Weshouldseeintheoutputthatcolumnz’svalueisNULL.Allotherfieldsshouldcontaindatafromthe table.Next,theprogramattemptstoupdateallfields,themostimportantofwhichiscolumnx.The updateshouldsucceed,butthevalueincolumnxshouldbeunchanged,becausetheauthorizerdenies it.Thisisconfirmedonthefollowingselectstatement,whichshowsthatallcolumnswereupdated exceptforcolumnx,whichisunchanged.Theprogramthendropsthefootable,whichshouldissuea schemachangenotificationfromthepreviousfilter. Step5teststheattachanddetachdatabasecommands.Thethingtonoticehereishowthe authorizerfunctionisprovidedwiththenameofthedatabaseandthatyoucandistinguishthe operationsbeingperformedundertheattacheddatabaseasopposedtothemaindatabase. 185 CHAPTER6■THECORECAPI /* 5. Test attach/detach */ /* Connect to test2.db */ rc = sqlite3_open_v2("test2.db", &db2); if(rc) { fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db2)); sqlite3_close(db2); exit(1); } sqlite3_exec(db2, "drop table foo2", NULL, NULL, &zErr); sqlite3_exec(db2, "create table foo2(x int, y int, z int)", NULL, NULL, &zErr); printf("program : Attaching database test2.db\n"); sqlite3_exec(db, "attach 'test2.db' as test2", NULL, NULL, &zErr); printf("program : Selecting record from attached database test2.db\n"); sqlite3_exec(db, "select * from foo2", NULL, NULL, &zErr); printf("program : Detaching table\n"); sqlite3_exec(db, "detach test2", NULL, NULL, &zErr); Againforclarity,Iwillbreakuptheprogramoutputintopieces.Uponexecutingit,thefirstthingwe seeisthetransactionfiltercatchingchangesintransactionstate: program : Starting transaction SQLITE_TRANSACTION : BEGIN Transaction program : Committing transaction SQLITE_TRANSACTION : COMMIT Transaction program : Starting transaction SQLITE_TRANSACTION : BEGIN Transaction program : Aborting transaction SQLITE_TRANSACTION : ROLLBACK Transaction Nextweseeaschemachangenotificationastheresultofcreatingthetesttablefoo.Theinteresting thingtonoticehereisalltheothereventsthattranspireinthesqlite_mastertableasaresultofcreating thetable: program : Creating table SQLITE_INSERT : Insert records into sqlite_master SQLITE_CREATE_TABLE : Schema modified SQLITE_READ : Read of sqlite_master.name SQLITE_READ : Read of sqlite_master.rootpage SQLITE_READ : Read of sqlite_master.sql SQLITE_UPDATE : Update of sqlite_master.type SQLITE_UPDATE : Update of sqlite_master.name SQLITE_UPDATE : Update of sqlite_master.tbl_name 186 CHAPTER6■ THECORECAPI SQLITE_UPDATE SQLITE_UPDATE SQLITE_READ : SQLITE_READ : SQLITE_READ : SQLITE_READ : SQLITE_READ : : Update of sqlite_master.rootpage : Update of sqlite_master.sql Read of sqlite_master.ROWID Read of sqlite_master.name Read of sqlite_master.rootpage Read of sqlite_master.sql Read of sqlite_master.tbl_name Nexttheprograminsertsarecord,whichtheauthorizerdetects: program : Inserting record SQLITE_INSERT : Insert records into foo Thisiswherethingsgetmoreinteresting.Wearegoingtobeabletoseetheauthorizerblockaccess toindividualcolumns.Theprogramselectsallrecordsfromthefootable.WeseetheSQLITE_SELECT eventtakeplace,followedbythesubsequentSQLITE_READeventsgeneratedforeachattemptedaccessof eachcolumnintheselectstatement.Whenitcomestocolumnz,theauthorizerdeniesaccess. Immediatelyfollowingthat,SQLiteexecutesthestatement,andprint_sql_result()printsthecolumn informationandrowsfortheresultset: program : Selecting record (value for z should be NULL) SQLITE_SELECT SQLITE_READ : Read of foo.x SQLITE_READ : Read of foo.y SQLITE_READ : Read of foo.z -> DENIED Column: x (1/int) Column: y (1/int) Column: z (5/(null)) Record: '1' '2' '(null)' Lookatwhatgoesonwithcolumnz.ItsvalueisNULL,whichconfirmsthattheauthorizerblocked access.Butalsolookatthecolumninformation.AlthoughSQLiterevealedthestorageclassofcolumnz, itdeniedaccesstoitsdeclaredtypeintheschema. Nextcomestheupdate.Hereweareinterestedincolumnx.Theupdatestatementwillattemptto changeeveryvalueintherecord.Butanupdateofcolumnxwillbedenied: program : Updating record (update of x should be denied) SQLITE_UPDATE : Update of foo.x -> DENIED SQLITE_UPDATE : Update of foo.y SQLITE_UPDATE : Update of foo.z Toconfirmthis,theprogramthenselectstherecordtoshowwhathappened.Theupdatedid execute,butcolumnxwasnotchanged.Evenmoreinterestingly,whilezwasupdated(trustme,itwas), theauthorizerwillnotletusseeitsvalue: 187 CHAPTER6■THECORECAPI program : Selecting record (notice x was not updated) SQLITE_SELECT SQLITE_READ : Read of foo.x SQLITE_READ : Read of foo.y SQLITE_READ : Read of foo.z -> DENIED Column: x (1/int) Column: y (1/int) Column: z (5/(null)) Record: '1' '5' '(null)' Nexttheprogramdeletestherecordanddropsthetable.Thelatteroperationgeneratesallsortsof eventsonthesqlite_mastertable,justlikewhenthetablewascreated: program : Deleting record SQLITE_DELETE : Delete from foo program : Dropping table SQLITE_DELETE : Delete from sqlite_master SQLITE_DROP_TABLE : Schema modified SQLITE_DELETE : Delete from foo SQLITE_DELETE : Delete from sqlite_master SQLITE_READ : Read of sqlite_master.tbl_name SQLITE_READ : Read of sqlite_master.type SQLITE_UPDATE : Update of sqlite_master.rootpage SQLITE_READ : Read of sqlite_master.rootpage Finally,theprogramcreatesanotherdatabaseonaseparateconnectionandthenattachesitonthe mainconnection.Themainconnectionthenselectsrecordsfromatableintheattacheddatabase,and wecanseehowtheauthorizerreportstheseoperationsashappeningintheattacheddatabase: program : Attaching database test2.db SQLITE_ATTACH : test2.db SQLITE_READ : Read of sqlite_master.name SQLITE_READ : Read of sqlite_master.rootpage SQLITE_READ : Read of sqlite_master.sql program : Selecting record from attached database test2.db SQLITE_SELECT SQLITE_READ : Read of foo2.x SQLITE_READ : Read of foo2.y SQLITE_READ : Read of foo2.z -> DENIED program : Detaching table SQLITE_DETACH -> test2 Asyoucansee,sqlite3_set_authorizer()anditsevent-filteringcapabilitiesarequitepowerful.It givesyouagreatdealofcontroloverwhattheusercanandcannotdoonagivendatabase.Youcan monitoreventsand,ifyouwant,stopthembeforetheyhappen.Or,youcanallowthemtoproceedbut imposespecificrestrictionsonthem.sqlite3_set_authorizer()canbeahelpfultoolfordealingwith 188 CHAPTER6■ THECORECAPI SQLITE_SCHEMAconditions.Ifyouknowyoudon’tneedanychangestoyourdatabaseschemainyour application,youcansimplyinstallanauthorizerfunctiontodenyanyoperationsthatattempttomodify theschemaincertainways. ■CautionKeepinmindthatdenyingschemachangesinanauthorizerisbynomeansacure-allfor SQLITE_SCHEMAevents.Youneedtobecarefulaboutalltheimplicationsofdenyingvariouschangestothe schema.Justblindlyblockingalleventsresultinginaschemachangecanrestrictotherseeminglylegitimate operationssuchasVACUUM. HELP FOR INTERACTIVE PROGRAMS SQLiteprovidestwofunctionsthatmakeiteasiertoworkwithinteractiveprograms.Thefirstis sqlite3_interrupt(),whichisdeclaredasfollows: void sqlite3_interrupt(sqlite3* /* connection handle */); sqlite3_interrupt()causesanypendingdatabaseoperationonthegivenconnectiontoabortand returnatitsearliestopportunity.Thisroutineisdesigntobecalledinresponsetoauserinterruptaction suchasclickingaCancelbuttoninagraphicalapplicationorpressingCtrl+Cinacommand-lineprogram. Itisintendedtomakeiteasiertoaccommodatecaseswheretheuserwantsalongqueryoperationtohalt immediately.Foracommand-lineprogram,youmightputthisfunctioninasignalhandleroranevent handlerinagraphicalapplication. Anotherfunctionthatcanbeusefulforinteractiveprogramsissqlite3_progress_handler().Itis somewhatrelatedinfunctionalitytothesqlite3_interrupt()function,butwithafewtwists.Itis declaredasfollows: void sqlite3_progress_handler( sqlite3*, int frq, int(*)(void*), void*); /* /* /* /* connection handle frequency of callback callback function application data */ */ */ */ Thisfunctioninstallsacallbackfunctionthatwillbeinvokedduringcallstosqlite3_exec(), sqlite3_step(),andsqlite3_get_table().Theintentofthisfunctionistogiveapplicationsawayto providefeedbacktotheuserduringlong-runningqueries. Thesecondargument(frq)specifiesthefrequencyofthecallbackintermsofVDBEinstructions.Thatis, theprogresscallback(providedinthethirdargument)willbecalledforeveryfrqVDBEinstruction performedinqueryexecution.Ifacalltosqlite3_exec(),sqlite3_step(),orsqlite3_get_table() requireslessthanfrqinstructionstobeexecuted,thentheprogresscallbackwillnotbeinvoked.The fourthargumentisapointertoapplication-specificdata,whichispassedbacktotheprogresshandler(as itsoneandonlyargument).IfNULLisprovidedforthecallbackfunctionargument,thenthecurrently installedprogresshandler(ifany)isdisabled. 189 CHAPTER6■THECORECAPI Iftheprogresscallbackreturnsanonzerovalue,thecurrentquerywillbeimmediatelyterminated,andany databasechangeswillberolledback.Ifthequerywaspartofalargertransaction,thenthetransactionis notrolledbackandremainsactive.Thesqlite3_exec()callinthatcasewillreturnSQLITE_ABORT. Threads SQLitehasenjoyedthreadingsupportformanyreleases.Althoughnormaldefensivecodingtechniques inmultithreadedcodeapplytoSQLiteaswell,thereareafewadditionalprecautionstotake. Onelimitationthatissomewhatthread-relatedpertainstothefork()systemcallonUnix.You shouldnevertrytopassaconnectionacrossafork()calltoachildprocess.Itwillnotworkcorrectly. SharedCacheMode StartingwithSQLiteversion3.3.0,SQLitesupportssomethingcalledsharedcachemode,whichallows multipleconnectionsinasingleprocesstouseacommonpagecache,asshowninFigure6-1.This featureisdesignedforembeddedserverswhereasinglethreadcanefficientlymanagemultipledatabase connectionsonbehalfofotherthreads.Theconnectionsinthiscaseshareasinglepagecacheaswellas adifferentconcurrencymodel.Becauseofthesharedcache,theserverthreadcanoperatewith significantlylowermemoryusageandbetterconcurrencythanifeachthreadweretomanageitsown connection.Normally,eachconnectionallocatesenoughmemorytohold2,000pagesinthepagecache. Ratherthaneachthreadconsumingthatmuchmemorywithitsownconnection,itsharesthatmemory withotherthreadsusingasinglepagecache. Inthismodel,threadsrelyonaserverthreadtomanagetheirdatabaseconnectionsforthem.A threadsendsSQLstatementstotheserverthroughsomecommunicationmechanism;theserver executesthemusingthethread’sassignedconnectionandthensendstheresultsback.Thethreadcan stillissuecommandsandcontrolitsowntransactions;onlyitsactualconnectionexistsin,andis managedby,anotherthread. 190 CHAPTER6■ THECORECAPI Thread Thread Thread Server Thread con con con Page Cache Database Figure6-1.Thesharedcachemodel Connectionsinsharedcachemodeuseadifferentconcurrencymodelandisolationlevel. Furthermore,anoptionexiststoallowconnectionsinasharedcachecanseewhattheirkindred connectionshavechanged.Ifthepragmaread_committedissettotrue,thiskindofchangeinspectionis possible.Thatis,therecanbebothmultiplereadersandanactivewriterinthedatabaseatthesame time.Thatwritercanwritetothedatabase—performingcompletewritetransactions—withouthavingto waitforotherreaderstoclear.Therefore,datacanchangeinthedatabasewithinareader’stransaction. AlthoughSQLitenormallyrunsinaserializedisolationlevel,meaningthatreadersandwritersalways seeaconsistentviewofthedatabase,insharedcachemode,readersaresubjecttothedatabase changingunderneaththem. Therearesomecontrolmeasuresinplacetokeepconnectionsoutofoneanother’sway.Bydefault, sharedcachemodeusestablelockstokeepreaderconnectionsandwriterconnectionsseparated.Table locksarenotthesameasdatabaselocksandexistonlywithinconnectionsofthesharedcache. Wheneveraconnectionreadsatable,SQLitefirsttriestogetareadlockonit.Thesameistruefor writingtoatable.Aconnectionmaynotwritetoatablethatanotherconnectionhasareadlockon,and viceversa.Furthermore,tablelocksaretiedtotheirrespectiveconnectionandlastforthedurationofits transaction. Read Uncommitted Isolation Level Althoughtablelockshelpkeepconnectionsinsharedcachemodeoutofoneanother’sway,itispossible forconnectionstoelectnottobeinthewayatall.Thatis,aconnectioncanchoosetohaveareaduncommittedisolationlevelbyusingtheread_uncommittedpragma.Ifitissettotrue,thenthe 191 CHAPTER6■THECORECAPI connectionwillnotputreadlocksonthetablesitreads.Therefore,anotherwritercanactuallychangea tableastheconnectionreadsit.Thiscanleadtoinconsistentqueryresults,butitalsomeansthata connectioninread-uncommittedmodecanneitherblocknorbeblockedbyanyotherconnections. Somelargechangeshavehappenedasofversion3.7ofSQLite,withtheintroductionofWrite-Ahead Logmode.We’llcoverWrite-AheadLoggingindetailinChapter11. SCHEMA CHANGES IN SHARED CACHE MODE Thereareadditionalthingstoconsiderinsharedcachemodewhenathreadwantstomodifythedatabase schema.Asitturnsout,beforeSQLiteissuesatablelock,itfirstgetsareadtablelockonthe sqlite_mastertable.Forathreadtoaltertheschema,itmustfirstgetawritetablelockon sqlite_master.Itcandothisonlyiftherearenoreadlocksonitfromothertables.Whenathreaddoesget awritelockonsqlite_master,thennootherthreadsareallowedtocompileSQLstatementsduringthat time.TheywillgetSQLITE_SCHEMAerrors. Unlock Notification Ifthethoughtofoperatinginthewildsofread-uncommittedisolationdoesn’tappealtoyou,SQLite providesforanalternativewheresharedcachemodeisinuse.RecentversionsofSQLitehaveincluded thesqlite3_unlock_notify()functiontoprovideadditionalflexibilityinlockingsituations.Thefunction profilelooksasfollows: int sqlite3_unlock_notify( sqlite3 *pBlocked, void (*xNotify)(void **apArg, int nArg), void *pNotifyArg ) /* Waiting connection */ /* Callback function to invoke */ /* Argument to pass to xNotify */ Ifyourcodeencountersafailuretogainasharedlockbecauseofacontendinglock,SQLITE_LOCKED willbereturned.Atthispoint,youcancallsqlite3_unlock_notify()toallowregisteringofyourcallback functionxNotify(thesecondparameter)withanydesiredparameterstothatfunction(accessviathe pNotifyArgpointerasthethirdparameter)againstyourblockedconnection(thefirstparameter). TheconnectionthatholdstheblockinglockwilltriggerthexNotifycallbackaspartofthe sqlite3_step()orsqlite3_close() callthatcompletesitstransaction.Itisalsopossible,particularly withinamultithreadedapplication,thatinthetimeittakesyoutoinvokesqlite3_unlock_notify(),the competingtransactionwillhavecompleted.Inthiscase,yourcallbackfunctionwillbeinitiated immediatelyfromwithinsqlite3_unlock_notify(). Therearesomecaveatstotheuseofsqlite3_unlock_notify(),includingthefollowing: 192 • Youcanregisteronlyoneunlock/notifycallbackperblockedconnection(newer callsreplaceanyexistingcallback). • sqlite3_unlock_notify()isnotreentrant,meaningyoushouldnotincludeother SQLitefunctioncallsinyourcallbackfunction.You’relikelytocrashyour application. CHAPTER6■ THECORECAPI • Specialcaremustbetakenifyouplantousewithdrop tableordrop index commands.Becausethesecanbe“blocked”byselect statements,thereisno realblockingtransactiontoincludeasthepBlockedparameter.Refertothedetails ontheSQLitewebsiteforusingtheextendedreturncodestodetectandhandle thisscenarioatwww.sqlite.org/c3ref/unlock_notify.html. ThreadsandMemoryManagement Sincesharedcachemodeisaboutconservingmemory,SQLitehasseveralfunctionsassociatedwith threadsandmemorymanagement.Theyallowyoutospecifyanadvisoryheaplimit—asoftheaplimit— aswellasmanuallyinitiatememorycleanups.Thesefunctionsareasfollows: void sqlite3_soft_heap_limit(int N); int sqlite3_release_memory(int N); Thesqlite3_soft_heap_limit()functionsetsthecurrentsoftheaplimitofthecallingthreadtoN bytes.Ifthethread’sheapusageexceedsN,thenSQLiteautomaticallycallssqlite3_release_memory(), whichattemptstofreeatleastNbytesofmemoryfromthecachesofalldatabaseconnections associatedwiththecallingthread.Thereturnvalueofsqlite3_release_memory()isthenumberofbytes actuallyfreed. Theseroutinesareno-opsunlessyouhaveenabledmemorymanagementbycompilingSQLitewith theSQLITE_ENABLE_MEMORY_MANAGEMENTpreprocessordirective. Summary ThecoreCAPIcontainseverythingyouneedtoprocessSQLcommandsandthensome.Itcontainsa varietyofconvenientquerymethodsthatareusefulindifferentways.Theseincludesqlite3_exec()and sqlite3_get_table(),whichallowyoutoexecutecommandsinasinglefunctioncall.TheAPIincludes manyutilityfunctionsaswell,allowingyoutodeterminethenumberofaffectedrecordsinaquery,get thelastinsertedROWIDofanINSERTstatement,traceSQLcommandsrunonaconnection,and convenientlyformatstringsforSQLstatements. Thesqlite3_prepare_v2(),sqlite3_step(),andsqlite3_finalize()methodsprovideyouwithalot offlexibilityandcontroloverstatementexecutionthroughtheuseofstatementhandles.Statement handlesprovidemoredetailedrowandcolumninformation,theconvenienceofboundparameters,and theabilitytoreusepreparedstatements,avoidingtheoverheadofquerycompilation. SQLiteprovidesavarietyofwaystomanageruntimeeventsthroughtheuseofeventfilters.Its commit,rollback,andupdatehooksallowyoutomonitorandcontrolspecificchangesindatabasestate. Youcanwatchchangestorowsandcolumnsastheyhappenanduseanauthorizerfunctiontomonitor andrestrictwhatqueriescandoastheyarecompiled. Andbelieveitornot,you’veseenonlyhalfoftheAPI!Actually,you’veseenmorelikethree-quarters, butyouarelikelytofindthatwhatisinthenextchapter—user-definedfunctions,aggregates,and collations—iseverybitasusefulandinterestingaswhatisinthisone. 193 CHAPTER 7 ■■■ The Extension C API ThischapterisaboutteachingSQLitenewtricks.Thepreviouschapterdealtwithgenericdatabasework; thischapterisaboutbeingcreative.TheExtensionAPIoffersseveralbasicwaystoextendorcustomize SQLite,throughthecreationofuser-definedfunctions,aggregates,collationsequences,andvirtualtables. Atalowerlevel,manymoreoptionspresentthemselves,includinginterchangeableVFSs,start-time changeablepagecache,andmallocandmuteximplementation.We’llcoverthefirstthreeoptionsinthis chapter:functions,aggregates,andcollationsequences. User-definedfunctionsareSQLfunctionsthatmaptosomeimplementationthatyouwrite.They arecallablefromwithinSQL.Forexample,youcouldcreateafunctionhello_newman()thatreturnsthe string'Hello Jerry'and,onceitisregistered,callitfromSQLasfollows: sqlite > select hello_newman() as reply; reply -----------------'Hello Jerry' ThisisaspecialversionoftheSQLitecommand-lineprogramwe’vecustomizedthatincludes hello_newman(). Aggregatesareaspecialformoffunctionandworkinmuchthesamewayexceptthattheyoperate onsetsofrecordsandreturnaggregatedvaluesorexpressionscomputedoveraparticularcolumninthe set.Ortheymaybecomputedfrommultiplecolumns.StandardaggregatesthatarebuiltintoSQLite includeSUM(),COUNT(),andAVG(),forexample. Collationsaremethodsofcomparingandsortingtext.Thatis,giventwostrings,acollationwould decidewhichoneisgreaterorwhetherthetwoareequal.ThedefaultcollationinSQLiteisBINARY—it comparesstringsbytebybyteusingmemcmp().Althoughthiscollationhappenstoworkwellforwordsin theEnglishlanguage(andotherlanguagesthatuseUTF-8encoding),itdoesn’tnecessarilyworksowell forotherlanguagesthatusedifferentencodings.Thus,SQLiteincludestheabilitytobuildyourown user-definedcollationstobetterhandlethosealternativelanguages. Thischaptercoverseachofthesethreeuser-definedextensionfacilitiesandtheirassociatedAPI functions.Asyouwillsee,theuser-definedextensionsAPIcanprovetobeapowerfultoolforcreating nontrivialfeaturesthatextendSQLite. AllofthecodeinthischapterisincludedinexamplesthatyoucanobtainonlinefromtheApress website(www.apress.com).Theexamplesforthisparticularchapterarelocatedinthech7subdirectoryof theexamplesfolder.Wewillspecificallypointoutallthesourcefilescorrespondingtotheexamplesas theyareintroducedinthetext.Someoftheerror-checkingcodeinthefigureshasbeentakenoutforthe sakeofclarity. 195 CHAPTER7■THEEXTENSIONCAPI Also,manyexamplesinthischapterusesimpleconveniencefunctionsfromacommonlibrary writtentohelpsimplifytheexamples.Wewillpointoutthesefunctionsandexplainwhattheydoasthey areintroducedinthetext.Thecommoncodeislocatedinthecommonsubdirectoryoftheexamplesfolder andmustfirstbebuiltbeforetheexamplesarebuilt.PleaserefertotheREADMEfileintheexamplesfolder fordetailsonbuildingthecommonlibrary. Finally,toclearupanyconfusion,thetermsstorageclassanddatatypeareinterchangeable.You knowthatSQLitestoresdatainternallyusingfivedifferentdatatypes,orstorageclasses.Theseclasses areINTEGER,FLOAT,TEXT,BLOB,andNULL,asdescribedinChapter4.Throughoutthechapter,we’llusethe termthatbestfitsthecontext.You’llgenerallyseethetermdatatype,becauseit’smostbroadly applicableandeasierforreadersfromdifferentbackgroundstofollow.Whenspeakingabouthow SQLitehandlesaspecificvalueinternally,thetermstorageclassseemstoworkbetter.Ineithercase,you canequateeithertermasdescribingaspecificformorrepresentationofdata. The API Thebasicmethodforimplementingfunctions,aggregates,andcollationsconsistsofimplementinga callbackfunctionandthenregisteringitinyourprogram.Onceregistered,yourfunctionscanbeused fromSQL.Functionsandaggregatesusethesameregistrationfunctionandsimilarcallbackfunctions. Collationsequences,whileusingaseparateregistrationfunction,arealmostidenticalandcanbe thoughtofasaparticularclassofuser-definedfunction. Thelifetimeofuser-definedaggregates,functions,andcollationsistransient.Theyareregisteredon aconnection-by-connectionbasis;theyarenotstoredinthedatabase.Itisuptoyoutoensurethatyour applicationloadsyourcustomextensionsandregistersthemoneachconnection.Sometimesyoumay findyourselfthinkingofyourextensionsintermsofstoredproceduresandcompletelyforgetaboutthe factthattheydon’tactuallyresideinthedatabase.Extensionsexistinlibraries,notindatabases,andare restrictedtothelifeofyourprogram.Ifyoudon’tgraspthisconcept,youmaydosomethingliketryto createatrigger(whichisstoredinthedatabase)thatreferencesyourextensions(whicharen’tstoredin thedatabase)andthenturnaroundandtrytocallitfromtheSQLiteshellorfromanapplicationthat knowsnothingofyourextensions.Inthiscase,youwillfindthateitherittriggersanerrorornothing happens.Extensionsrequireyourprogramtoregisterthemoneachandeveryconnection;otherwise, thatconnection’sSQLsyntaxwillknownothingaboutthem. RegisteringFunctions Youcanregisterfunctionsandaggregatesonaconnectionusingsqlite3_create_function(),whichis declaredasfollows: int sqlite3_create_function( sqlite3 *cnx, /* connection handle const char *zFunctionName, /* function/aggregate name in SQL int nArg, /* number of arguments. -1 = unlimited. int eTextRep, /* encoding (UTF8, 16, etc.) void *pUserData, /* application data, passed to callback void (*xFunc)(sqlite3_context*,int,sqlite3_value**), void (*xStep)(sqlite3_context*,int,sqlite3_value**), void (*xFinal)(sqlite3_context*) ); 196 */ */ */ */ */ CHAPTER7■THEEXTENSIONCAPI int sqlite3_create_function16( sqlite3 *cnx, const void *zFunctionName, int nArg, int eTextRep, void *pUserData, void (*xFunc)(sqlite3_context*, int args, sqlite3_value**), void (*xStep)(sqlite3_context*, int args, sqlite3_value**), void (*xFinal)(sqlite3_context*) ); Aswithourexamplesinthepreviouschapter,we’veincludedboththeUTF-8andUTF-16versions ofthisfunctiontounderscorethattheSQLiteAPIhasfunctionsthatsupportbothencodings.Fromnow on,wewillonlyrefertotheUTF-8versionsforthesakeofbrevity. Theargumentsforsqlite3_create_function()aredefinedasfollows: • cnx:Thedatabaseconnectionhandle.Functionsandaggregatesareconnection specific.Theymustberegisteredontheconnectionasitisopenedinordertobe used. • zFunctionName:ThefunctionnameasitwillbecalledinSQL.Upto255bytesin length. • nArg:Thenumberofargumentsexpectedbyyourfunction.SQLitewillenforce thisastheexactnumberofargumentsthatmustbeprovidedtothefunction.If youspecify-1,SQLitewillallowavariablenumberofarguments. • eTextRep:Thepreferredtextencoding.AllowablevaluesareSQLITE_UTF8, SQLITE_UTF16,SQLITE_UTF16BE,SQLITE_UTF16LE,andSQLITE_ANY.Thisfieldisahint toSQLiteusedonlytohelpitchoosebetweenmultipleimplementationsofthe samefunction.SQLITE_ANYmeans“nopreference.”Inotherwords,the implementationworksequallyaswellwithanytextencoding.Whenindoubt,use SQLITE_ANYhere. • pUserData:Application-specificdata.Thisdataismadeavailablethroughthe callbackfunctionsspecifiedinxFunc,xStep,andxFinalbelow.Unlikeother functions,whichreceivethedataasavoidpointerintheargumentlist,these functionsmustuseaspecialAPIfunctiontoobtainthisdata. • xFunc:Thefunctioncallback.ThisistheactualimplementationoftheSQL function.FunctionsonlyprovidethiscallbackandleavethexStepandxFinal functionpointersNULL.Theselattertwocallbacksareexclusivelyforaggregate implementations. • xStep:Theaggregatestepfunction.EachtimeSQLiteprocessesarowinan aggregatedresultset,itcallsxSteptoallowtheaggregatetoprocesstherelevant fieldvalue(s)ofthatrowandincludetheresultinitsaggregatecomputation. • xFinal:Theaggregatefinalizefunction.Whenallrowshavebeenprocessed, SQLitecallsthisfunctiontoallowtheaggregatetoconcludeitsprocessing,which usuallyconsistsofcomputingthefinalvalueandoptionallycleaningup. 197 CHAPTER7■THEEXTENSIONCAPI Youcanregistermultipleversionsofthesamefunctiondifferingonlyintheencoding(eTextRep argument)and/orthenumberofarguments(nArgargument),andSQLitewillautomaticallyselectthe bestversionofthefunctionforthecaseinhand. TheStepFunction Thefunction(callback)andaggregatestepfunctionsareidenticalandaredeclaredasfollows: void fn(sqlite3_context* ctx, int nargs, sqlite3_value** values) Thectxargumentisthefunction/aggregatecontext.Itholdsstateforaparticularfunctioncall instanceandisthemeansthroughwhichyouobtaintheapplicationdata(pUserData)argument providedinsqlite3_create_function().Theuserdataisobtainedfromthecontextusing sqlite3_user_data(),whichisdeclaredasfollows: void *sqlite3_user_data(sqlite3_context*); Forfunctions,thisdataissharedamongallcallstolikefunctions,soitisnotreallyuniquetoa particularinstanceoffunctioncall.Thatis,thesamepUserDataispassedorsharedamongallinstances ofagivenfunction.Aggregates,however,canallocatetheirownstateforeachparticularinstanceusing sqlite3_aggregate_context(),declaredasfollows: void *sqlite3_aggregate_context(sqlite3_context*, int nBytes); Thefirsttimethisroutineiscalledforaparticularaggregate,achunkofmemoryofsizenBytesis allocated,zeroed,andassociatedwiththatcontext.Onsubsequentcallswiththesamecontext(forthe sameaggregateinstance),thisallocatedmemoryisreturned.Usingthis,aggregateshaveawaytostore stateinbetweencallsinordertoaccumulatedata(which,whenyouthinkaboutit,isthegeneral purposeforaggregatingsomething).Whentheaggregatecompletesthefinal()callback,thememoryis automaticallyfreedbySQLite. ■NoteOneofthethingsyouwillseethroughouttheAPIistheuseofuserdatainvoidpointers.Sincemanyparts oftheAPIinvolvecallbackfunctions,thesesimplyserveasaconvenientwaytomaintainstatewhenimplementing saidcallbackfunctions. Thenargsargumentofthecallbackfunctioncontainsthenumberofargumentspassedtothe function. ReturnValues ThevaluesargumentisanarrayofSQLitevaluestructuresthatarehandlestotheactualargument values.Theactualdataforthesevaluesisobtainedusingthefamilyofsqlite3_value_xxx()functions, whichhavethefollowingform: 198 CHAPTER7■THEEXTENSIONCAPI xxx sqlite3_value_xxx(sqlite3_value* value); wherexxxistheCdatatypetobereturnedfromthevalueargument.IfyoureadChapter6,youmaybe thinkingthatthesefunctionshaveastrikingresemblancetothesqlite3_column_xxx()familyof functions—andyou’dberight.Theyworkinthesameway,evendowntothedifferencebetweentheway scalarandarrayvaluesareobtained.Thefunctionsforobtainingscalarvaluesareasfollows: int sqlite3_value_int(sqlite3_value*); sqlite3_int64 sqlite3_value_int64(sqlite3_value*); double sqlite3_value_double(sqlite3_value*); Thefunctionsusedtoobtainarrayvaluesareasfollows: int sqlite3_value_bytes(sqlite3_value*); const void *sqlite3_value_blob(sqlite3_value*); const unsigned char *sqlite3_value_text(sqlite3_value*); Thesqlite3_value_bytes()functionreturnstheamountofdatainthevaluebufferforaBLOB.The sqlite3_value_blob()functionreturnsapointertothatdata.Usingthesizeandthepointer,youcan thencopyoutthedata.Forexample,ifthefirstargumentinyourfunctionwasaBLOBandyouwantedto makeacopy,youwoulddosomethinglikethis: int len; void* data; len = sqlite3_value_bytes(values[0]); data = sqlite3_malloc(len); memcpy(data, sqlite3_value_blob(values[0]), len); Justasthesqlite3_column_xxx()functionshavesqlite_column_type()toprovidethecolumntypes, thesqlite3_value_xxx()functionslikewisehavesqlite3_value_type(),whichworksinthesameway.It isdeclaredasfollows: int sqlite3_value_type(sqlite3_value*); Thisfunctionreturnsoneofthefollowingvalues,whichcorrespondtoSQLite’sinternal,storageclasses (datatypes),definedasfollows: #define #define #define #define #define SQLITE_INTEGER SQLITE_FLOAT SQLITE_TEXT SQLITE_BLOB SQLITE_NULL 1 2 3 4 5 Thiscoversthebasicworkingsofthefunction/aggregateinterface.Wecannowdiveintosome examplesandpracticalapplications.TheCollationinterfaceissosimilarthatitwillbeimmediately understandabletoyounowthatyou’vereviewedtheinterfaceforfunctionsandaggregates. 199 CHAPTER7■THEEXTENSIONCAPI Functions Let’sstartourcustomfunctiondevelopmentwithatrivialexample,onethatisveryeasytofollow.Let’s implementhello_newman(),butwithaslighttwist.Wewanttoincludeusingfunctionargumentsinthe example,sohello_newman()willtakeoneargument:thenameofthepersonaddressinghim.Itwillwork asfollows: sqlite > select hello_newman('Jerry') as reply; reply -----------------Hello Jerry sqlite > select hello_newman('Kramer') as reply; reply -----------------Hello Kramer sqlite > select hello_newman('George') as reply; reply -----------------Hello George Listing7-1showsthebasicprogram(takenfromhello_newman.c).Someoftheerror-checkingcodehas beenremovedforclarity. Listing7-1.Thehello_newman()TestProgram int main(int argc, char **argv) { int rc; sqlite3 *db; sqlite3_open_v2("test.db", &db); sqlite3_create_function( db, "hello_newman", 1, SQLITE_UTF8, NULL, hello_newman, NULL, NULL); /* Log SQL as it is executed. */ log_sql(db,1); /* Call function with one text argument. */ fprintf(stdout, "Calling with one argument.\n"); print_sql_result(db, "select hello_newman('Jerry')"); /* Call function with two arguments. ** It will fail as we registered the function as taking only one argument.*/ fprintf(stdout, "\nCalling with two arguments.\n"); print_sql_result(db, "select hello_newman ('Jerry', 'Elaine')"); 200 CHAPTER7■THEEXTENSIONCAPI /* Call function with no arguments. This will fail too */ fprintf(stdout, "\nCalling with no arguments.\n"); print_sql_result(db, "select hello_newman()"); /* Done */ sqlite3_close(db); } return 0; Thisprogramconnectstothedatabase,registersthefunction,andthencallsitthreetimes.The callbackfunctionisimplementedasfollows: void hello_newman(sqlite3_context* ctx, int nargs, sqlite3_value** values) { const char *msg; /* Generate Newman's reply */ msg = sqlite3_mprintf("Hello %s", sqlite3_value_text(values[0])); } /* Set the return value. Have sqlite clean up msg w/ sqlite_free(). */ sqlite3_result_text(ctx, msg, strlen(msg), sqlite3_free); Runningtheprogramyieldsthefollowingoutput: Calling with one argument. TRACE: select hello_newman('Jerry') hello_newman('Jerry') --------------------Hello Jerry Calling with two arguments. execute() Error: wrong number of arguments to function hello_newman() Calling with no arguments. execute() Error: wrong number of arguments to function hello_newman() Thefirstcallconsistsofjustoneargument.Sincetheexampleregisteredthefunctionastakingexactly oneargument,itsucceeds.Thesecondcallattemptstousetwoarguments,whichfails.Thethirdcall usesnoargumentsandalsofails. Andthereyouhaveit:aSQLiteextensionfunction.Thisdoesbringupafewnewfunctionsthatwe havenotaddressedyet.We’vecreatedseveralhelperfunctionsforusewiththebookandtoaidyouin yourSQLitework.You’llfindtheseincludedfordownloadontheApresswebsite.Manyofthese functions’definitionscanbefoundinthesourcefileutil.c.Thefunctionlog_sql()simplycalls sqlite3_trace(),passinginatracingfunctionthatprefixesthetracedSQLwiththewordTRACE.Weuse thissoyoucanseewhatishappeningintheexampleastheSQLisexecuted.Thesecondfunctionis print_sql_result(),whichhasthefollowingdeclaration: int print_sql_result(sqlite3 *db, const char* sql, ...) 201 CHAPTER7■THEEXTENSIONCAPI Thisisasimplewrapperaroundsqlite3_prepare_v2()andfriendsthatexecutesaSQLstatementand printstheresults. ReturnValues Ourhello_newman()exampleintroducesanewSQLitefunction:sqlite3_result_text().Thisfunctionis justoneofafamilyofsqlite_result_xxx()functionsusedtosetreturnvaluesforuser-definedfunctions andaggregates.Thescalarfunctionsareasfollows: void void void void sqlite3_result_double(sqlite3_context*, double); sqlite3_result_int(sqlite3_context*, int); sqlite3_result_int64(sqlite3_context*, long long int); sqlite3_result_null(sqlite3_context*); Thesefunctionssimplytakea(second)argumentofthetypespecifiedinthefunctionnameandsetitas thereturnvalueofthefunction.Thearrayfunctionsareasfollows: void sqlite3_result_text(sqlite3_context*, const char*, int n, void(*)(void*)); void sqlite3_result_blob(sqlite3_context*, const void*, int n, void(*)(void*)); Thesefunctionstakearraydataandsetthatdataasthereturnvalueforthefunction.Theyhavethe followinggeneralform: void sqlite3_result_xxx( sqlite3_context *ctx, const xxx* value, int len, void(*free)(void*)); /* /* /* /* function context */ array value */ array length */ array cleanup function */ Herexxxistheparticulararraytype—voidforBLOBsorcharforTEXT.Again,ifyoureadChapter6, youmayfindthesefunctionssuspiciouslysimilartothesqlite3_bind_xxx()functions,whichtheyare. Settingareturnvalueforafunctionis,forallintentsandpurposes,identicaltobindingavaluetoa parameterizedSQLstatement.Youcouldevenperhapsrefertoitas“bindingareturnvalue.” ArraysandCleanupHandlers JustasinbindingarrayvaluestoSQLstatements,thesefunctionsworkinthesamewayas sqlite3_bind_xxx().Theyrequireapointertothearray,thelength(orsize)ofthearray,andafunction pointertoacleanupfunction.Thiscleanupfunctionpointercanbeassignedthesamepredefined meaningsasinsqlite3_bind_xxx(): #define SQLITE_STATIC #define SQLITE_TRANSIENT ((void(*)(void *))0) ((void(*)(void *))-1) SQLITE_STATICmeansthatthearraymemoryresidesinunmanagedspace,andthereforeSQLite doesnotneedtomakeacopyofthedataforuse,norshoulditattempttocleanitup.SQLITE_TRANSIENT tellsSQLitethatthearraydataissubjecttochange,andthereforeSQLiteneedstomakeitsowncopy 202 CHAPTER7■THEEXTENSIONCAPI usingsqlite3_malloc().Theallocatedmemorywillbefreedwhenthefunctionreturns.Thethirdoption istopassinanactualfunctionpointertoacleanupfunctionofthefollowingform: void cleanup(void*); Inthiscase,SQLitewillcallthecleanupfunctionaftertheuser-definedfunctioncompletes.Thisisthe methodusedinthepreviousexample.Weusedsqlite3_mprintf()togenerateNewman’sreply,which allocatedastringontheheap.Wethenpassedinsqlite3_free()asthecleanupfunctionto sqlite3_result_text(),whichcouldfreethestringmemorywhentheextensionfunctioncompleted. ErrorConditions Sometimesfunctionsencountererrors,inwhichcasethereturnvalueshouldbesetappropriately.This iswhatsqlite3_result_error()isfor.Itisdeclaredasfollows: void sqlite3_result_error( sqlite3_context *ctx, /* the function context */ const char *msg, /* the error message */ int len); /* length of the error message */ ThistellsSQLitethattherewasanerror,thedetailsofwhicharecontainedinmsg.SQLitewillabortthe commandthatcalledthefunctionandsettheerrormessagetothevaluecontainedinmsg. ReturningInputValues Sometimes,youmaywanttopassbackanargumentasthereturnvalueinthesameform.Ratherthan youhavingtodeterminetheargument’stype,extractitsvaluewiththecorrespondingsqlite3_ column_xxx()function,andthenturnrightaroundandsetthereturnvaluewiththeappropriate sqlite3_result_xxx()function,theAPIofferssqlite3_result_value()soyoucandoallofthisinone fellswoop.Itisdeclaredasfollows: void sqlite3_result_value( sqlite3_context *ctx, sqlite3_value* value); /* the function context */ /* the argument value */ Forexample,sayyouwantedtocreateafunctionecho()thatspitsbackitsfirstargument.The implementationisasfollows: void echo(sqlite3_context* ctx, int nargs, sqlite3_value** values) { sqlite3_result_value(ctx, values[0]); } 203 CHAPTER7■THEEXTENSIONCAPI ItwouldworkfromSQLasfollows: sqlite > select echo('Hello Jerry') as reply; reply -----------------Hello Jerry Evenbetter,echo()worksequallywellwithargumentsofanystorageclassandreturnsthem accordingly: sqlite> select echo(3.14) as reply, typeof(echo(3.14)) as type; reply type ---------- ---------3.14 real sqlite> select echo(X'0128') as reply, typeof(echo(X'0128')) as type; reply type ---------- ---------(? blob sqlite> select echo(NULL) as reply, typeof(echo(NULL)) as type; reply type ---------- ---------null Aggregates Aggregatesareonlyslightlymoreinvolvedthanfunctions.Whereasyouhadtoimplementonlyone callbackfunctiontodotheworkinuser-definedfunctions,youhavetoimplementbothastepfunction tocomputetheongoingvalueaswellasafinalizingfunctiontofinisheverythingoffandcleanup.Figure 7-1showsthegeneralprocess.Itstillisn’thard,though.Likefunctions,onegoodexamplewillbeallyou needtogetthegistofit. 204 CHAPTER7■THEEXTENSIONCAPI Figure7-1.Queryprocessingwithaggregates RegistrationFunction Asmentionedbefore,aggregatesandfunctionsusethesameregistrationfunction, sqlite3_create_function(),whichislistedhereagainforconvenience: int sqlite3_create_function( sqlite3 cnx*, /* connection handle const char *zFunctionName, /* function/aggregate name in SQL int nArg, /* number of arguments. -1 = unlimited. int eTextRep, /* encoding (UTF8, 16, etc.) void *pUserData, /* application data, passed to callback void (*xFunc)(sqlite3_context*,int,sqlite3_value**), void (*xStep)(sqlite3_context*,int,sqlite3_value**), void (*xFinal)(sqlite3_context*) ); */ */ */ */ */ 205 CHAPTER7■THEEXTENSIONCAPI Youdoexactlythesamethinghereasyoudowithfunctions,butratherthanprovingacallbackfor xFunc,youleaveitNULLandprovidefunctionsforxStepandxFinal. APracticalExample Thebestwaytoillustrateimplementingaggregatesisbyexample.Herewewillimplementtheaggregate str_agg().Theideaofstr_agg()istoactmuchlikethestrcat()Cfunction,wheretwostringsare concatenatedtogether(theeagle-eyedwillspotthatnewerversionsofSQLiteincludeafunctionwitha similarpurpose,group_concat()).Butforourpurposes,wewanttoaggregateanynumberofstrings involvedingroupingandaggregationsatthebehestofyourSQLinSQLite.Youmightwellwonder whetheryoureallyneedsuchastringcontatenationaggregationfeatureinSQLite,givenyoucouldwrite yourowninC.Oneadvantageofthestr_agg()approachistoenablesemanticallyclearandeasily understoodSQLtobewritten,ratherthanhavingtoshufflebackandforthbetweenSQLandCto achievethestringaggregation.Theotherbenefitofthisexampleis,ofcourse,toshowyouhowto aggregate.Listing7-2showsourexamplestr_agg()function(takenfromstr_agg.c). Listing7-2.Thestr_agg()TestProgram int main(int argc, char **argv) { int rc; sqlite3 *db; char *sql; sqlite3_open_v2("foods.db", &db); /* Register aggregate. */ fprintf(stdout, "Registering aggregate str_agg()\n"); /* Turn SQL tracing on. */ log_sql(db, 1); /* Register aggregate. */ sqlite3_create_function( db, "str_agg", 1, SQLITE_UTF8, db, NULL, str_agg_step, str_agg_finalize); /* Test. */ fprintf(stdout, "\nRunning query: \n"); sql = "select season, str_agg(name, ', ') from episodes group by season"; print_sql_result(db, sql); sqlite3_close(db); } return 0; Notethatourstepfunctioniscalled str_agg_step(),andourfinalizingfunctioniscalled str_agg_finalize().Also,thisaggregateisregisteredastakingonlyoneargument. 206 CHAPTER7■THEEXTENSIONCAPI The Step Function Listing7-3showsthe str_agg_step()function. Listing7-3.Thestr_agg()StepFunction void str_agg_step(sqlite3_context* ctx, int ncols, sqlite3_value** values) { SAggCtx *p = (SAggCtx *) sqlite3_aggregate_context(ctx, sizeof(*p)); static const char delim [] = ", "; char *txt = sqlite3_value_text(values[0]); int len = strlen(txt); } if (!p->result) { p->result = sqlite_malloc(len + 1); memcpy(p->result, txt, len + 1); p->chrCnt = len; } else { const int delimLen = sizeof(delim); p->result = sqlite_realloc(p->result, p->chrCnt + len + delimLen + 1); memcpy(p->result + p->chrCnt, delim, delimLen); p->chrCnt += delimLen; memcpy(p->result + p->chrCnt, txt, len + 1); p->chrCnt += len; } ThevalueSAggCtxisastructthatisspecifictothisexampleandisdefinedasfollows: typedef struct SAggCtx SAggCtx; struct SAggCtx { int chrCnt; char *result; }; Ourstructureservesasourstatebetweenaggregateiterations(callstothestepfunction), maintainingthegrowingconcatenationoftext,andthecharactercount. The Aggregate Context Thefirstorderofbusinessistoretrievethestructureforthegivenaggregateinstance.Thisisdoneusing sqlite3_aggregate_context().Asmentionedearlier,thefirstcalltothisfunctionallocatesthedatafor thegivencontextandsubsequentcallsretrieveit.Thestructurememoryisautomaticallyfreedwhenthe aggregatecompletes(afterstr_agg_finalize()iscalled).Notethatsqlite3_aggregate_context()might returnNULLifthesystemislowonmemory.Sucherrorcheckingisomittedinthisexample,forbrevity, 207 CHAPTER7■THEEXTENSIONCAPI butarealimplementationshouldalwayschecktheresultofsqlite3_aggregate_context()andinvoke sqlite3_result_error_nomem()iftheresultisNULL.Inthestr_agg_step()function,thetextvaluetobe aggregatedisretrievedfromthefirstargumentusingsqlite3_value_text().Thisvalueisthenaddedto theresultmemberoftheSAggCtxstruct,whichstorestheintermediateconcatenation.Noteagainthat sqlite3_value_text()mightreturnaNULLpointeriftheargumenttotheSQLfunctionisNULLorifthe systemislowonmemory.Arealimplementationshouldcheckforthiscaseinordertoavoidasegfault. The Finalize Function Eachrecordinthematerializedresultsettriggersacalltostr_agg_step().Afterthelastrecordis processed,SQLitecallsstr_agg_finalize(),whichisimplementedasshowninListing7-4. Listing7-4.Thesum_agg()FinalizeFunction void str_agg_finalize(sqlite3_context* ctx) { SAggCtx *p = (SAggCtx *) sqlite3_aggregate_context(ctx, sizeof(*p)); if( p && p->result ) sqlite3_result_text(ctx, p->result, p->chrCnt, sqlite_free); } The str_agg_finalize()functionbasicallyworksjustlikeauser-definedfunctioncallback.It retrievestheSAggCtxstructand,ifitisnotNULL,setstheaggregate’sreturnvaluetothevaluestoredin thestruct’sresultmemberusingsqlite3_result_text().Thesqlite3_aggregate_context()routine mightreturnNULLifthesystemislowonmemory,orthep->zResultfieldmightbeNULLifthestep functionwasnevercalled.Intheformercase,SQLiteisgoingtoreturntheSQLITE_NOMEMerrorsoitdoes notreallymatterwhethersqlite3_result_text()isevercalled.Inthelattercase,sinceno sqlite3_result_xxx()functioniseverinvokedfortheaggregate,theresultoftheaggregatewillbethe SQLNULL. Results Theprogramproducesthefollowingoutput(abbreviatedheretoconservepaper): Registering aggregate str_agg() Running query: TRACE: select season, str_agg(name, ', ') from episodes group by season … season -----0 1 2 3 … 208 str_agg(name, ', ') -----------------------------------------------------------------Good News Bad News Male Unbonding, The Stake Out, The Robbery, The Stock Tip The Ex-Girlfriend, The Pony Remark, The Busboy, The Baby Shower, … The Note, The Truth, The Dog, The Library, The Pen, The Parking Garage … CHAPTER7■THEEXTENSIONCAPI Asyoucansee,theselectstatementpullsbackthedatafromtheepisodetable,andthestr_agg() aggregateconcatenatestheepisodenamesperseason.Youcanthinkofthisassomethingsimilarto cross-tabsorpivotsinspreadsheetsandothertools. Andthatistheconceptofaggregatesinanutshell.Theyaresosimilartofunctionsthatthereisn’t muchtotalkaboutonceyouarefamiliarwithfunctions. Collations Asstatedbefore,thepurposeofcollationsistosortstrings.Butbeforestartingdownthatpath,itis importanttorecallthatSQLite’smanifesttypingschemeallowsvaryingdatatypestocoexistinthesame column.Forexample,considerthefollowingSQL(locatedincollate1.sql): .headers on .m column create table foo(x); insert into foo values insert into foo values insert into foo values insert into foo values insert into foo values (1); (2.71828); ('three'); (X'0004'); (null); select quote(x), typeof(x) from foo; FeedingittotheSQLiteCLPwillproducethefollowing: C:\temp\examples\ch7> sqlite3 < collate.sql quote(x) typeof(x) ---------- ---------1 integer 2.71828 real 'three' text X'0004' blob NULL null YouhaveeveryoneofSQLite’snativestorageclassessittingincolumnx.Naturally,thequestionarises astowhathappenswhenyoutrytosortthiscolumn.Thatis,beforewecantalkabouthowtosort strings,weneedtoreviewhowdifferentdatatypesaresortedfirst. WhenSQLitesortsacolumninaresultset(whenitusesacomparisonoperatorsuchas=on thevalueswithinthatcolumn),thefirstthingitdoesisarrangethecolumn’svaluesaccordingtostorage class.Thenwithineachstorageclass,itsortsthevaluesaccordingtomethodsspecifictothatclass. Storageclassesaresortedinthefollowingorder,fromfirsttolast: 1. NULLvalues 2. INTEGERandREALvalues 3. TEXTvalues 4. BLOBvalues 209 CHAPTER7■THEEXTENSIONCAPI Nowlet’smodifytheSELECTstatementintheprecedingexampletoincludeanORDER BYclausesuchthat theSQLisasfollows: select quote(x), typeof(x) from foo order by x; Rerunningthequery(locatedincollate2.sql)confirmsthisordering: C:\temp\examples\ch7> sqlite3 < collate.sql quote(x) typeof(x) ---------- ---------NULL null 1 integer 2.71828 real 'three' text X'0004' blob NULLsarefirst,INTEGERandREALarenext(innumericalorder),TEXTisnext,andthenBLOBsarelast. SQLiteemploysspecificsortingmethodsforeachstorageclass.NULLsareobvious—thereisnosort order.Numericvaluesaresortednumerically;integersandfloatsalikearecomparedbasedontheir respectivequantitativevalues.BLOBsaresortedbybinaryvalue.Text,finally,iswherecollationscomein. CollationDefined 1 Collationisthemethodbywhichstringsarecompared.Apopular glossaryoftermsdefinesacollation asfollows: Textcomparisonusinglanguage-sensitiverulesasopposedtobitwisecomparisonof numericcharactercodes. Ingeneral,collationhastodowiththeordering,comparison,andarrangementofstringsand characters.Collationmethodsusuallyemploycollationsequences.Acollationsequenceisjustan orderedlistofcharacters,usuallynumberedtomaketheordereasiertorememberanduse.Thelistin turnisusedtodictatehowcharactersareordered,comparedandsorted.Givenanytwocharacters,the collation(list)canresolvewhichwouldcomefirstorwhethertheyarethesame. How Collation Works Normally,acollationmethodcomparestwostringsbybreakingthemdownandcomparingtheir respectivecharactersusingacollation.Theydothisbyliningthestringsupandcomparingcharacters fromlefttoright(Figure7-2).Forexample,thestrings'jerry'and'jello'wouldbecomparedbyfirst 1 Seewww.ibm.com/developerworks/library/glossaries/unicode.html. 210 CHAPTER7■THEEXTENSIONCAPI comparingthefirstletterineachstring(bothjinthiscase).Ifoneletter’snumericalvalueaccordingto thecollationsequenceislargerthantheother,thecomparisonisover:thestringwiththelargerletteris deemedgreater,andnofurthercomparisonisrequired.If,ontheotherhand,thelettershavethesame value,thentheprocesscontinuestothesecondletterineachstring,andtothethird,andsoon,until somedifferenceisfound(ornodifferenceisfound,inwhichcasethestringsareconsideredequal).If onestringrunsoutoflettersbeforetheother,thenitisuptothecollationmethodtodeterminewhat thismeans. Figure7-2.Binarycollation Inthisexample,thecollationistheASCIIcharacterset.Eachcharacter’snumericASCIIvalueinthe figureisdisplayedunderneathit.Usingthecollationmethodjustdescribed,stringcomparison continuestothethirdcharacter,whereupon'jerry'winsout,asithasanrwiththevalue114,whereas 'jello'hastheinferior'l'withthevalue108.BasedonASCIIcollation,'jerry'>'jello'. Had'jerry'been'Jerry',then'jello'wouldhavewonout,becausebigJ’s74palestolittlej’s 106,sothecomparisonwouldhavebeenresolvedonthefirstcharacter,withtheprizegoingto'jello'. Inshort,'jello'>'Jerry'. However,tocontinuetheexample,wecoulduseadifferentcollationwhereinuppercasevaluesare assignedthesamenumbersastheirlowercasecounterparts(acase-insensitivecollationsequence). 211 CHAPTER7■THEEXTENSIONCAPI Thenthecomparisonbetween'Jerry'and'jello'wouldgobackto'Jerry'becauseinthisnew collationJandjarethesame,pullingtherugoutfromunder'jello'’slowercasejsuperiority. Butenoughaboutcollations.Yougetthepicture.Asequenceisasequence.Ultimately,it’snotthe collationsequencethatmattersbutthecollationmethod.Collationmethodsdon’thavetouse sequences.Theycandowhatevertheywant,howeverstrangeormadthatmayseem. Oddsarethatyouarereallyconfusedbynowandarejustreadyforasummary.Sohereitis.Think ofcollationmethodsasthewaythatstringsarecompared.Thinkofcollationsequencesastheway charactersarecompared.Ultimately,allthatmattersinSQLiteishowstringsarecompared,andthetwo termsrefertojustthat.Therefore,thetwotermscollationmethodandcollationsequenceshouldjustbe thoughtofasstringcomparison.Ifyoureadcollation,thinkstringcomparison.Ifyoureadcollation, thinkstringcomparison.Allinall,justthinkstringcomparison.ThatisthewaytheAPIisgeared.When youcreateacustomcollation,SQLitehandsittwostrings,aandb,andthecollationreturnswhether stringaislessthan,equalto,orgreaterthanstringb.That’sit,plainandsimple. Standard Collation Types SQLitecomeswithasinglebuilt-incollationnamedbinary,whichisimplementedbyapplyingthe memcmp()routinefromthestandardClibrarytothetwostringstobecompared.Thebinarycollation happenstoworkwellforEnglishtext.Forotherlanguagesorlocales,alternativecollationmaybe preferred.SQLitealsooffersanalternatecollationcallednocase,whichtreatsupper-andlowercase versionsofthesameletterasequivalents. Collationsareappliedbyassociatingthemwithcolumnsinatableoranindexdefinitionorby specifyingtheminaquery.Forexample,tocreateacase-insensitivecolumnbarinfoo,youwould definefooasfollows: create table foo (bar text collate nocase, baz integer); Fromthatpointon,wheneverSQLitedealswithabar,itwillusethenocasecollation.Ifyouprefernotto attachacollationtoadatabaseobjectbutwouldratherspecifyitasneededonaquery-by-querybasis, youcanspecifythemdirectlyinqueries,asinthefollowing: select * from foo order by bar collate nocase; SQLitecanalsoapplyacollationastheresultofacast()expressionwhereyouconvertnontextdata (thatwouldn’tnormallyhaveatextualcollation)tothetextdatatype.Wecouldcastourbaznumeric valuetotextandapplythenocasecollationlikethis: select cast(baz) collate nocase as baz_as_text from foo order by baz_as_text; Althoughtheexampleisalittlecontrived,thecapabilitywillhelpyouespeciallywhendealingwith dataofmixedstorageclassesbeingconvertedtotext. ASimpleExample Tojumpintocollations,let’sbeginwithasimpleexampletogetthebigpicture.Let’simplementa collationcalledlength_first.Length_firstwilltaketwostringsanddecidewhichoneisgreater dependingonthelengthofthestring.ImageJerryatthedeli,demandingtoonlyeatingredientswith shortnames—orKramerinsistinghehasagreatdealonfoodswithreallylongnames.Whimsical,but verySeinfeld. 212 CHAPTER7■THEEXTENSIONCAPI CollationsareregisteredwithSQLitethroughthesqlite3_create_collation_v2()function,whichis declaredasfollows: int sqlite3_create_collation_v2( sqlite3* db, /* database handle */ const char *zName, /* collation name in SQL */ int pref16, /* encoding */ void* pUserData, /* application data */ int(*xCompare)(void*,int,const void*,int,const void*) void(*xDestroy)(void*) ); Itlooksprettysimilartosqlite3_create_function().Thereisthestandarddatabasehandle,the collationnameasitwillbeaddressedinSQL(similartothefunction/aggregatename),andthe encoding,whichpertainstotheformatofthecomparisonstringswhenpassedtothecomparison function. ■NoteJustasinaggregatesandfunctions,separatecollationcomparisonfunctionscanberegisteredunderthe samecollationnameforeachoftheUTF-8,UTF-16LE,andUTF-16BEencodings.SQLitewillautomaticallyselect thebestcomparisonfunctionforthegivencollationbasedonthestringstobecompared. TheapplicationdatapointerisanotherAPImainstay.Thepointerprovidedthereispassedontothe callbackfunction.Basically,sqlite3_create_collation_v2()isastripped-downversionof sqlite3_create_function(),whichtakesexactlytwoarguments(bothofwhicharetext)andreturnsan integervalue.Italsohastheaggregatecallbackfunctionpointersstrippedout. Oftheremainingtwoparameters,thelastisxDestroypointer.Thisfunctionwillbecalledat destructiontimeofthecollation,whichtypicallywillhappenwhenthedatabaseconnectionis destroyed.Thedestructionfunctionwillalsobecalledifyourcollationisoverriddenbylatercallsto sqlite3_create_collation_v2(). The Compare Function ThexCompareargumentisthekeynewthinghere.Itpointstotheactualcomparisonfunctionthatwill resolvethetextvalues.Thecomparisonfunctionmusthavethefollowingform: int compare( void* data, int len1, const void* str1, int len2, const void* str2) /* /* /* /* /* application data */ length of string 1 */ string 1 */ length of string 2 */ string 2 */ Thefunctionshouldreturnnegative,zero,orpositiveifthefirststringislessthan,equalto,orgreater thanthesecondstring,respectively. Asstated,thelength_firstcollationisabitwishy-washy.Listing7-5showsitsimplementation. 213 i CHAPTER7■THEEXTENSIONCAPI Listing7-5.TheLength_firstCollationFunction int length_first_collation( void* data, int l1, const void* s1, int l2, const void* s2 ) { int result, opinion; /* Compare lengths */ if ( l1 == l2 ) result = 0; if ( l1 < l2 ) result = 1; if ( l1 > l2 ) result = 2; /* Form an opinion: is s1 really < or = to s2 ? */ switch(result) { case 0: /* Equal length, collate alphabetically */ opinion = strcmp(s1,s2); break; case 1: /* String s1 is shorter */ opinion = -result; break; case 2: /* String s2 is shorter */ opinion = result break; default: /* Assume equal length just in case */ opinion = strcmp(s1,s2); } } return opinion; The Test Program Allthatremainsistoillustrateitinaprogram.Listing7-6showstheexampleprogram(length_first.c) implementation. Listing7-6.TheLength_firstCollationTestProgram int main(int argc, char **argv) { char *sql; sqlite3 *db; int rc; sqlite3_open("foods.db", &db); /* Register Collation. */ fprintf(stdout, "1. Register length_first Collation\n\n"); sqlite3_create_collation_v2( db, "LENGTH_FIRST", SQLITE_UTF8, db, length_first_collation, length_first_collation_del ); 214 CHAPTER7■THEEXTENSIONCAPI /* Turn SQL logging on. */ log_sql(db, 1); /* Test default collation. */ fprintf(stdout, "2. Select records using default collation.\n"); sql = "select name from foods order by name"; print_sql_result(db, sql); /* Test Length First collation. */ fprintf(stdout, "\nSelect records using length_first collation. \n"); sql = "select name from foods order by name collate LENGTH_FIRST"; print_sql_result(db, sql); /* Done. */ sqlite3_close(db); } return 0; Results Runningtheprogramyieldsthefollowingresults(abbreviatedheretosavespace): 1. Register length_first Collation 2. Select records using default collation. TRACE: select name from foods order by name name ----------------A1 Sauce All Day Sucker Almond Joy Apple Apple Cider Apple Pie Arabian Mocha Java (beans) Arby's Roast Beef Artichokes Atomic Sub ... 215 CHAPTER7■THEEXTENSIONCAPI Select records using length_first collation. TRACE: select name from foods order by name collate LENGTH_FIRST issue ----------------BLT Gum Kix Pez Pie Tea Bran Duck Dill Life ... Ourprogramstartsbyregisteringthelength_firstcollationsequence.Wethenproceedtoselect recordsusingSQLite’sdefaultbinarycollation,whichreturnsrecordsinalphabeticalorder.Thencomes ouruseofthelength_first collation,whereweselectrecordsagain.Astheresultsindicate,weareright onthemark,sortingfirstbylengthandthenalphabetically. CollationonDemand SQLiteprovidesawaytodefercollationregistrationuntilitisactuallyneeded.Soifyouarenotsureyour applicationisgoingtoneedsomethinglikethelength_firstcollation,youcanusethe sqlite3_collation_needed()functiontodeferregistrationtothelastpossiblemoment(perhapsasthe resultofsomesecretlast-minutefoodrenaming).Yousimplyprovidesqlite3_collation_needed()with acallbackfunction,whichSQLitecanrelyontoregisterunknowncollationsequencesasneeded,given theirname.Thisactslikeacallbackforacallback,sotospeak.It’slikesayingtoSQLite,“Here,ifyouare everaskedtouseacollationthatyoudon’trecognize,callthisfunction,anditwillregistertheunknown sequence;thenyoucancontinueyourwork.” Thesqlite3_collation_needed()functionisdeclaredasfollows: int sqlite3_collation_needed( sqlite3* db, /* connection handle */ void* data, /* application data */ void(*crf)(void*,sqlite3*,int eTextRep,const char*) ); Thecrfargument(thecollationregistrationfunctionaswecallit)pointstothefunctionthatwillregister theunknowncollation.Forclarity,itisdefinedasfollows: void crf( void* data, sqlite3* db, int eTextRep, const char*) /* /* /* /* application data */ database handle */ encoding */ collation name */ Thedbanddataargumentsofcrf()arethevaluespassedintothefirstandsecondargumentsof sqlite3_collation_needed(),respectively. 216 CHAPTER7■THEEXTENSIONCAPI Summary Bynowyou’vediscoveredthatuser-definedfunctions,aggregates,andcollationscanbesurprisingly useful.TheabilitytoaddsuchfunctionsusingtheextensionspartoftheCAPIisagreatcomplementto theopennatureofthecoreSQLitelibrary.So,you’refreetodiginandmodifySQLitetoyourheart’s content.WewouldevengosofartosaythatSQLiteprovidesafriendly,easy-to-userinterfacethatmakes itpossibletoimplementawiderangeofpowerfulextensionsandcustomizations,especiallywhen combinedwithotherfeaturesalreadypresentinSQLite. Inthenextchapter,youwillseehowmanyextensionlanguagestakeadvantageofthis.Theyusethe CAPItomakeitpossibletoimplementallmannerofcapabilitiesandextensionsforagivenlanguage. 217 CHAPTER 8 ■■■ Language Extensions SQLiteiswritteninCandhasitsownCAPI,whichmakesCthe“nativelanguage”tosomedegree.The opensourcecommunity,however,hasprovidedmanyextensionsforSQLitethatmakeitaccessibleto manyprogramminglanguagesandlibrariessuchasPerl,Python,Ruby,Java,.NET/C#,Qt,andODBC.In manycases,therearemultipleextensionstochoosefromforagivenlanguage,developedbydifferent peopletomeetdifferentneeds. ManyextensionsconformtovariousAPIstandards.Forinstance,oneoftheSQLitePerlextensions followsthePerlDBI—Perl’sstandardinterfacefordatabaseaccess.Similarly,oneofthePython extensionsconformstoPython’sDBAPIspecification,asdoesatleastoneoftheJavaextensionsto JDBC.RegardlessoftheirparticularAPIs,internallyallextensionsworkontopofthesameSQLiteCAPI, whichyou’vealreadyexploredinChapters5,6,and7.Tosomedegree,allextensionsreflecttheC foundationoftheSQLitedesign.Someextensionsprovidebothastandardinterfacethatconformsto theirparticularAPIstandardaswellasanalternativeinterfacethatbetterreflectsthedesignofthe SQLiteAPI.Therefore,insuchcases,youcanchoosewhichinterfaceworksbestforyoubasedonyour requirements. Ingeneral,allextensionshavethesamecomparativeanatomyregardlessoftheirparticularAPI. Theyfollowasimilarpattern.Onceyouunderstandthispattern,everyinterfacewillstarttolooksimilar inmanyrespects.Thereissomekindofconnectionobjectrepresentingasingleconnectiontothe database,andsomekindofcursorobjectrepresentingaSQLqueryfromwhichyoucanbothexecute commandsanditerateoverresults.Conceptually,itisquitesimple.Internally,youarelookingata sqlite3structureandasqlite3_stmtstructure,bothwell-knownstructuresfromourearlierexplanation andexamples.ThesamerulesapplyforlanguageextensionsasfortheCAPI. Thischaptercoverslanguageextensionsforsixpopularlanguages:Perl,Python,Ruby,Java,Tcl,and PHP.Theintentistoprovideyouwithaconvenientintroductionwithwhichtoquicklygetstartedusing SQLiteinavarietyofdifferentlanguages.We’llhighlightrightnowthatwewon’tbeteachingyouthose languagesthemselves—sosomeknowledgeofPerl,orPython,orRuby,andsoon,isexpected. Coverageforeachlanguagefollowsacommonoutlinecomposedofthecommontopicsof questionsfrompeoplestartingoutwithlanguageextensionsforSQLite: • Connectingtodatabases • Executingqueries • Usingboundparameters • Implementinguser-definedfunctionsoraggregates 219 CHAPTER8■LANGUAGEEXTENSIONS TogetherthesetopicsconstitutethevastmajorityofwhatyouwilleveruseinanyparticularSQLite extension.Youmightfindsome“developertension”overdevelopinguser-definedfunctionsinSQLite versusimplementingthelogicinyourchosenlanguage.Althoughwecan’tmakethatdecisionforyou, wecangiveyoutheknowledgeandexpertisetohelpmakethatchoiceyourself. Noteveryextensionsupportsallofthesetopics.Forinstance,somedon’tofferboundparameters. Conversely,someextensionsofferuniquefeaturesthatareoutsidethetopicscoveredhere.Theaimhere istoprovideaconsistent,straightforwardprocesswithwhichtoeasilygetstartedusingSQLiteinawide varietyoflanguages.Onceyougetstartedwithanyextension,itisusuallyeasytopickupanyspecial featuresavailableinthatextension. Whereappropriate,thischapteraddresseshowdifferentextensionsusevariouspartsoftheCAPIin ordertohelpyouunderstandwhatisgoingonunderthehood.Ifyouhavenotreadthepreceding chaptersontheCAPI,westronglyrecommendthatyoudoso.Nomatterwhatlanguageyouprogramin, itwillalmostalwaysbehelpfultounderstandhowSQLiteworksinordertomakethemostofitandthus writegoodcode.Itwillhelpyouselectthemostsuitablequerymethods,understandthescopeof transactions,andknowhowtoanticipate,dealwith,oravoidlocks,amongotherthings. Selecting an Extension Formanyoftoday’spopularlanguages,youarespoiltforchoicewhenitcomestolanguagebindingsfor SQLite.Choosingtheextensionthatsuitsyouisoftenmorethanastraighttechnicaldecision.Tohelp, wecovertheinterfacethatbestfitsthefollowingcriteria: • SupportforthelatestSQLite3versions • Gooddocumentation • Stability • Portability Despitethesecriteria,thereweremultiplecandidatesinsomecasesthatmetallthequalifications. Insuchcases,thetiebreakerwasmoreamatterofpersonalpreferencethananythingelse.Butthe purposehereisnottofavoraparticularextension.Itistoteachconceptssothatyoucaneasilypickany extensioninanylanguageandquicklyputitandSQLitetogooduse. Thereasonswechoseaparticularextensionmaynotbethereasonsyouwould.Someadditional pointstoconsiderincludethefollowing: 220 • Licenseandlicensecompatibility:Theextension’slicensecandirectlyaffecthow youcanuseit.Isitopensource,andifso,underwhichlicense?Ifyouarewriting codeforacommercialproduct,youdefinitelyneedtotakethisintoconsideration. • Datatypemapping:HowdoestheextensionmapSQLite’sstorageclassestothe language’snativetypes.Areallvaluesreturnedastext?Issomekindofcrazy castingschemeused?Ifnot,isthereaneasywaytodeterminethemappings?Do youhaveanycontroloverhowthemappingisdone? • Querymethods:ThreedifferentquerymethodsaresupportedintheCAPI.Which onedoestheextensionuse?Ideallyitsupportsallthree. • APIcoverage:Howwelldoestheextensioncoverotherareasthatdon’teasilymap tomanystandarddatabaseinterfaces?Forexample,doesitallowyoutocallthe SQLtracefunctionoroperationalsecurityfunctions?Doyouactuallyneedthese? CHAPTER8■LANGUAGEEXTENSIONS • Linkageanddistribution:Howeasyisittousetheextensionwithaparticular versionofSQLite?DoesitincludeaversionofSQLiteinthedistribution?Doesit useasharedlibrary,orisitstaticallylinkedtoaparticularversion?Whatifyou needtoupgradeSQLite;howeasilycanyoudothiswiththeextension?Will anythingbreak? Thereareotherconsiderationsaswell,suchascommunitysupport,mailinglistactivity,maintainer supportandresponsiveness,regressiontesting,codequality...thelistgoeson.Allofthesethingsmay playanimportantroleinyourdecisiontouseaparticularextension.Onlyyoucananswerthese questionsforyourself. TheSQLitewikihasapagethatprovidesanexhaustivelistoflanguageinterfaces,locatedat www.sqlite.org/cvstrac/wiki?p=SqliteWrappers.Alloftheinterfacescoveredhereweretakenfromthis list.Thesourcecodeforalloftheexamplesinthischapterislocatedinthech8directoryoftheexamples zipfile,availableattheApresswebsite. Perl TherearetwoSQLiteextensionsforPerl.ThefirstisamodeledonthePerlDBIstandardfordatabase connectivity;therefore,ifyouunderstandDBI,youwillhavenotroubleusingtheextension.Forthose unfamiliarwiththePerlDBI,youcanreviewfulldocumentationontheCPANwebsiteat http://search.cpan.org/search?module=DBI.ThesecondextensionisaSWIG-basedwrapperforuse withPerl.We’llexaminetheDBIinterfaceinthefollowingsections. Installation ThecurrentversionoftheSQLiteDBIdriveratthetimeofthiswritingisDBD-SQLite-1.29.Youcaninstall itbyusingCPANorbymanuallybuildingthepackagefromsource.TheprerequisitesfortheSQLiteDBD moduleare,ofcourse,Perl,aCcompiler,andtheDBImodule.ThelatestversionsoftheSQLiteDBI driveralsorequireYAML(“Yetanothermarkuplanguage”or“YAMLAin’tMarkupLanguage,” dependingonwhomyoubelieve),usedforvariousconfigurationfiles.ToinstallDBD::SQLiteusing CPAN,invoketheCPANshellfromthecommandlineasfollows: fuzzy@linux $ cpan cpan> install DBD::SQLite ... lots of CPAN install messages ... ToinstallfromsourceinLinux/Unix,changetoatemporarydirectoryanddothefollowing: fuzzy@linux $ wget http://search.cpan.org/CPAN/authors/id/A/AD/ADAMK/DBD-SQLite-1.29.tar.gz ... lots of wget messages ... fuzzy@linux $ tar xzvf DBD-SQLite-1.29.tar.gz ... lots of tar messages ... fuzzy@linux $ cd DBD-SQLite-1.29 221 CHAPTER8■LANGUAGEEXTENSIONS fuzzy@linux DBD-SQLite-1.29 $ perl Makefile.PL ... lots of perl messages ... Checking installed SQLite version... Looks good fuzzy@linux DBD-SQLite-1.29 $ make install ... more perl messages ... TheSQLitePerlextensionincludesitsowncopyoftheSQLite3binaries,sothereisnoneedto compileandinstallSQLitebeforehand.SQLiteisembeddedintheextension. Connecting TochecktheSQLitedriverisinstalled,usetheDBIfunctionavailable_drivers()withinPerl: use DBI; print "Drivers: " . join(", ", DBI->available_drivers()), "\n"; YouconnecttoadatabaseusingthestandardDBI::connectfunction,asfollows: use DBI; my $dbh = DBI->connect( "dbi:SQLite:dbname=foods.db", "", "", { RaiseError => 1 }); $dbh->disconnect; Thesecondandthirdargumentscorrespondtothedrivernameanddatabasename.Thethirdand fourthcorrespondtousernameandpassword,whicharenotapplicabletoSQLite. Thefunctionreturnsadatabasehandleobjectrepresentingthedatabaseconnection.Internally, thiscorrespondstoasinglesqlite3structure.Youcancreatein-memorydatabasesbypassing:memory: forthenameofthedatabase.Inthiscase,alltablesanddatabaseobjectswillthenresideinmemoryfor thedurationofthesessionandwillbedestroyedwhentheconnectionisclosed.Youclosethedatabase usingthedatabasehandle’sdisconnectmethod. QueryProcessing QueriesareperformedusingthestandardDBIinterfaceaswell.Youcanusetheprepare(),execute(), fetch(),orselectrow()functionsofthedatabaseconnectionhandle.Allofthesearefullydocumented intheDBImanpage.Listing8-1showsanexampleofusingqueries. Listing8-1.ExecutingQueriesinPerl use DBI; # Connect to database my $dbh = DBI->connect( "dbi:SQLite:dbname=foods.db", "", "", { RaiseError => 1 }); 222 CHAPTER8■LANGUAGEEXTENSIONS # Prepare the statment my $sth = $dbh->prepare("select name from foods limit 3"); # Execute $sth->execute; # Print a human-readable header print "\nArray:\n\n"; # Iterate over results and print while($row = $sth->fetchrow_arrayref) { print @$row[0] . "\n"; } # Do the same thing, this time using hashref print "\nHash:\n\n"; $sth->execute; while($row = $sth->fetchrow_hashref) { print @$row{'name'} . "\n"; } # Finalize the statement $sth->finish; #Disconnect $dbh->disconnect; Internally,theprepare()methodcorrespondstothesqlite3_prepare_v2()method.Similarly, execute()callsthefirstsqlite3_step()method.Itautomaticallyfiguresoutwhetherthereisdatatobe returned.Ifthereisnodata(forexample,non-selectstatements),itautomaticallyfinalizesthequery. Thefetchrow_array(),fetchrow_hashref(),andfetch()methodscallsqlite3_step()aswell,returning asinglerowintheresultsetuntiltheresultsareexhausted. Additionally,youcanrunnon-selectstatementsinonestepusingthedatabaseobject’sdo() method.Listing8-2illustratesthisusinganin-memorydatabase. Listing8-2.Thedo()Method use DBI; my $dbh = DBI->connect("dbi:SQLite:dbname=:memory:", "", "", { RaiseError => 1 }); $dbh->do("create table cast (name)"); $dbh->do("insert into cast values ('Elaine')"); $dbh->do("insert into cast values ('Jerry')"); $dbh->do("insert into cast values ('Kramer')"); $dbh->do("insert into cast values ('George')"); $dbh->do("insert into cast values ('Newman')"); my $sth = $dbh->prepare("select * from cast"); $sth->execute; 223 CHAPTER8■LANGUAGEEXTENSIONS while($row = $sth->fetch) { print join(", ", @$row), "\n"; } $sth->finish; $dbh->disconnect; Thestatementhandleobject’sfinish()methodwillcallsqlite3_finalize()onthequeryobject,if ithasnotalreadydoneso.Thisprogramproducesthefollowingoutput: Elaine Jerry Kramer George Newman ParameterBinding ParameterbindingfollowsthemethoddefinedintheDBIspecification.AlthoughSQLitesupportsboth positionalandnamedparameters,thePerlinterfaceusesonlypositionalparameters,demonstratedin Listing8-3. Listing8-3.ParameterBindinginPerl use DBI; my $dbh = DBI->connect( "dbi:SQLite:dbname=foods.db", "", "", { RaiseError => 1 }); my $sth = $dbh->prepare("select * from foods where name like :1"); $sth->execute('C%'); while($row = $sth->fetchrow_hashref) { print @$row{'name'} . "\n"; } $sth->finish; $dbh->disconnect; Theexecute()methodtakestheparametervaluesdefinedinprepare().Runningthisagainstthe evolvingfoodsdatabasewe’veusedformanyofourexamplesreturns73rows(dependingonhowmuch funyouhadplayingwithchocolatebobkainpreviouschapters). User-DefinedFunctions User-definedfunctionsandaggregatesareimplementedusingprivatemethodsofthedriver.They followcloselytotheircounterpartsintheSQLiteCAPI.Functionsareregisteredusingthefollowing privatemethod: 224 CHAPTER8■LANGUAGEEXTENSIONS $dbh->func( $name, $argc, $func_ref, "create_function" ) Here$namespecifiestheSQLfunctionname,$argcspecifiesthenumberofarguments,and $func_refspecifiesareferencetothePerlfunctionthatprovidestheimplementation.Listing8-4 illustratesanimplementationofhello_newman()inPerl. Listing8-4.hello_newman()inPerl use DBI; sub hello_newman { return "Hello Jerry"; } # Connect my $dbh = DBI->connect( "dbi:SQLite:dbname=foods.db", "", "", { RaiseError => 1 }); # Register function $dbh->func('hello_newman', 0, \&hello_newman, 'create_function'); # Call it print $dbh->selectrow_arrayref("select hello_newman()")->[0] . "\n"; $dbh->disconnect; Ifyouprovide-1asthenumberofarguments,thenthefunctionwillacceptavariablenumberof arguments. Aggregates User-definedaggregatesareimplementedaspackages.Eachpackageimplementsastepfunctionanda finalizefunction.Thestepfunctioniscalledforeachrowthatisselected.Thefirstvaluesuppliedtothe functionisthecontext,whichisapersistentvaluemaintainedbetweencallstothefunction.The remainingvaluesaretheargumentstotheaggregatefunctionsuppliedintheSQLstatement.The finalizefunctionisprovidedthesamecontextasthestepfunction.Thefollowingexampleimplementsa simpleSUMaggregatecalledperlsum.Theaggregateisimplementedinapackagecalledperlsum.pm, showninListing8-5. Listing8-5.Theperlsum()Aggregate package perlsum; sub new { bless [], shift; } 225 CHAPTER8■LANGUAGEEXTENSIONS sub step { @_; @$self[0] += $value; } my ( $self, $value ) = sub finalize { my $self = $_[0]; return @$self[0]; } sub init { $dbh = shift; $dbh->func( "perlsum", 1, "perlsum", "create_aggregate" ); } 1; Theinitfunctionisusedtoregistertheaggregateinthedatabaseconnection. Python TherearenumerousapproachestoworkingwithSQLiteinPython.Thesecanbegroupedintotwo camps.ThefirstisthegroupofSQLitewrappers,suchasPySQLiteandAPSW,thatactasstraightforward wrapperinterfacestotheunderlyingSQLiteAPIcalls(thoughwithvaryingdegreesofdepth).Thesecond groupistheall-encompassingframeworkapproach,suchasSQLAlchemy.Thesearetypicallydesigned ascompleteobject-relationalmappingsystems,seekingnotonlytoprovideaccesstotheunderlying databaseAPIbuttoalsofollowobject-orientedphilosophiesinthedesignanduseofdatabase-related code. Atlastcount,therewereatleastninedifferentwrappersorobject-relationalframeworksforSQLite inPython.That’salmostenoughforabookinitsownright.We’llcoveroneofthemorepopular wrappers,PySQLite,principallybecauseithasbeenoneofthemostenduringandalsomapstothe PythonDBAPI. MichaelOwens(theauthorofthefirsteditionofthisbook)wrotetheoriginalversionofPySQLite andstartedtheprojectin2002,whichthenwaswrittenusingtheSQLite2.xAPI.GerhardHäringhas sincetakenovertheprojectandcompletelyrewrittenitforPySQLiteversion2,whichsupportsSQLite version3.Theprojecthasalsoevolvedandmovedseveraltimesandnowreferstoitselfaspysqlite(all lowercase).YoucanfindprojectinformationforPySQLiteonGoogleCodeathttp://code.google. com/p/pysqlite/.BoththesourcecodeandnativeWindowsbinariesareavailablefordownload. Installation FromPython2.5onward,pysqliteisincludedasastandardmoduleforPythonandissimplyreferredto asthesqlite3modulewhenusedfromthestandardlibrary.Therearestillsomeusestoseparately acquiringandcompiling/usingthepysqlitestand-alonemodule,becauseittracksbugfixesandnew featuresmorecloselythanthePythondistributionitself. Tosourceyourownpysqlitepackage,Windowsusersareencouragedtousetheprovidedbinaries ratherthanbuildingthembyhand.OnLinux,Unix,MacOSX,andothersystems,youbuildandinstall pysqliteusingPython’sdistutilspackage,oryousourcetherpmordebfilefromyourlocalpackage 226 x CHAPTER8■LANGUAGEEXTENSIONS repository.TheprerequisitesforcompilingyourownPySQLiteareaCcompiler,Python2.3ornewer, andSQLite3.1ornewer.Afterunpackingthesourcecode,compilethecodewiththefollowing command: python setup.py build distutilsshouldnormallybeabletofigureoutwhereeverythingisonyoursystem.Ifnot,youwillget anerror,inwhichcaseyouneedtoeditthesetup.cfgfileinthemaindirectorytopointoutwherethings are.Ifeverythinggoeswell,youshouldsee“Creatinglibrary...”intheoutput,indicatingasuccessful build.Nextinstallthelibrary: python setup.py install Youshouldnotseeanyerrors.Ifyoudo,reportthemtothecommunitythroughthequiteactivegroupat http://groups.google.com/group/python-sqlite. ForWindowssystems,simplydownloadthebinarydistributionandruntheinstaller.Theonly prerequisiteinthiscaseisthatSQLite3.2ornewerbeinstalledonyoursystem. Connecting Asmentioned,thebuilt-inmoduleinPython2.5andnewerisnamedsqlite3.Ifusingtheseparately sourcedpysqlitepackage,itisinpysqlite2.TheDBAPImoduleislocatedindbapi2.Thisissometimes confusingwhenyouarethinkingofPySQLiteversionnumbersandSQLiteversionnumbers simultaneously.Youconnecttoadatabaseusingthemodule’sconnect()function,passinginthe relativenameorcompletefilepathofthedatabasefileyouwanttoopen. Forthebuilt-inpysqliteinPython2.5+,aconnectionwouldbeasfollows: import sqlite3 db = sqlite3.connect("foods.db") Withtheseparatelysourcedpackageforpysqlite,yourconnectchangestothefollowing: from pysqlite2 import dbapi2 as sqlite3 db = sqlite3.connect("foods.db") Theusualrulesapply:youcanusein-memorydatabasesbypassinginthename:memory:asthe databasename;newdatabasesarecreatedfornewfiles;andsoforth.Youcanseetheonlyrealvariation intheincludedmoduleandseparatelysourcedmoduleforpysqliteisinimportsemantics.Fromhere on,we’llassumeyou’rehappyswitchingtothetechniquethatbestsuitsyourpreferredwayofusing pysqlite. QueryProcessing QueryexecutionisdoneaccordingtothePythonDBAPISpecification2.Youcreateacursorobjectwith whichtorunthequeryandobtainresults.Internally,acursorobjectholdsasqlite3_stmthandle. Listing8-6illustratesexecutingabasicquery. 227 CHAPTER8■LANGUAGEEXTENSIONS Listing8-6.ABasicQueryinPySQLite from pysqlite2 import dbapi2 as sqlite3 # Connect con = sqlite3.connect("foods.db") # Prepare a statement and execute. This calls sqlite3_prepare() and sqlite3_step() cur = con.cursor() cur.execute('select * from foods limit 10') # Iterate over results, print the name field (row[2]) row = cur.fetchone() while row: print row[2] # Get next row row = cur.fetchone() cur.close() con.close() Remember,Pythoncodeiswhite-spacesensitive,sobecarefulnottointroduceadditionalspacesor tabswhencopyingthiscode.Runningthiscodeproducesthefollowingoutput: Bagels Bagels, raisin Bavarian Cream Pie Bear Claws Black and White cookies Bread (with nuts) Butterfingers Carrot Cake Chips Ahoy Cookies Chocolate Bobka Querycompilationandthefirststepofexecutionareperformedtogetherinthecursor’sexecute() method.Itcallssqlite3_prepare()followedbysqlite3_step().Forqueriesthatmodifydataratherthan returnresults,thiscompletesthequery(shortoffinalizingthestatementhandle).Forselectstatements, itfetchesthefirstrowoftheresult.Theclose()methodfinalizesthestatementhandle. PySQLite2supportsiterator-styleresultsets,similartootherPythondatabasewrappers.For example,Listing8-6couldberewrittenasshowninListing8-7. Listing8-7.UsingPythonicIteratorsforaQuery from pysqlite2 import dbapi2 as sqlite3 con = sqlite3.connect("foods.db") cur = con.cursor() cur.execute('select * from foods limit 10') 228 CHAPTER8■LANGUAGEEXTENSIONS for row in cur: print row[2] ParameterBinding PySQLitesupportsparameterbindingbybothpositionandname.Thiscanalsobedoneusingthe cursor’sexecute()method,whichweintroducedinListing8-6.Compilation,binding,andthefirststep ofexecutionareperformedintheonecalltoexecute().Youspecifypositionalparametersbypassinga tupleasthesecondargumenttoexecute().Youspecifynamedparametersbypassingadictionary ratherthanatuple.Listing8-8illustratesbothformsofparameterbinding. Listing8-8.ParameterBindinginPySQLite from pysqlite2 import dbapi2 as sqlite3 con = sqlite3.connect("foods.db") cur = con.cursor() cur.execute('insert into episodes (name) values (?)', ('Soup Nazi')) cur.close() cur = con.cursor() cur.execute('insert into episodes (name) values (:name)', {'name':'Soup Nazi'}) cur.close() Thismodeldoesnotsupportthereuseofcompiledqueries(sqlite3_reset()).Todothis,use Cursor.executemany().WhiletheDBAPIspecifiesthatexecutemanyshouldtakealistofparameters, PySQLiteextendsittoaccommodateiteratorsandgeneratorsaswell.Forexample,thecanonicalformis showninListing8-9. Listing8-9.Theexecutemany()Method from pysqlite2 import dbapi2 as sqlite3 con = sqlite3.connect("foods.db") cur = con.cursor() episodes = ['Soup Nazi', 'The Fusilli Jerry'] cur.executemany('insert into episodes (name) values (?)', episodes) cur.close() con.commit() Butyoucouldjustaseasilyuseagenerator,asshowninListing8-10. 229 CHAPTER8■LANGUAGEEXTENSIONS Listing8-10.Theexecutemany()MethodwithaGenerator from pysqlite2 import dbapi2 as sqlite3 con = sqlite3.connect("foods.db") cur = con.cursor() def episode_generator(): episodes = ['Soup Nazi', 'The Fusilli Jerry'] for episode in episodes: yield (episode,) cur.executemany('INSERT INTO episodes (name) VALUES (?)', episode_generator()) cur.close() con.commit() InbothListing8-9andListing8-10,weusethepowerofparameterbindingwithasingle compilationofthequeryinquestion.Thequeryisreusedforeachiteminthesequenceoriterator, improvingtheoverallperformanceforsuchbatchesofidenticalqueries. TRANSACTION HANDLING IN PYSQLITE Itisimportanttonoticethecon.commit()linesinthepreviousexamples.Don’tforgetthemifyouuse PySQLite.Ifyoudon’tincludethem,thenalltransactionsintheexampleswillberolledback.Thisbehavior differsfromboththeSQLiteCAPIandotherextensions,anditmightsurpriseyou.Bydefault,SQLiteruns inautocommitmode.PySQLite,ontheotherhand,startsandfinishestransactionsbehindthescenes, usingitsownlogicforstartingandcommittingtransactionsbasedonwhatkindofSQLyouexecute. BeforepassingyourSQLstatementtoSQLite,itisanalyzedbyPySQLite.Ifitfindsan insert,update, delete,orreplace,PySQLitewillimplicitlystartatransaction(issueabegin).Then,ifyouissueanyother kindofcommandfollowingit,PySQLitewillautomaticallyissueacommitbeforeexecutingthatcommand. ThistransactionlogicplacesanadditionalconstraintonyourcodeinthatyoucannotuseON CONFLICT ROLLBACK;otherwise,itinterfereswithPySQLite’smonitoringofyourtransactions. ItispossibletoturnoffthisbehaviorandrestorethedefaultSQLitebehavior.Youcanexplicitlyturn autocommitmodebackonbysettingisolation_levelofthedatabaseconnectiontoNone,asfollows: from pysqlite2 import dbapi2 as sqlite3 # Turn on autocommit mode con = sqlite3.connect("foods.db", isolation_level=None) User-DefinedFunctions Youregisteruser-definedfunctionsusingcreate_function(),whichtakesthefollowingform: 230 CHAPTER8■LANGUAGEEXTENSIONS con.create_function(name, args, pyfunc) Here,nameistheSQLnameofthefunction,argsisthenumberofargumentsacceptedbythefunction, andpyfyncisthePythonfunctionthatimplementstheSQLfunction.Listing8-11showsaPython implementationofhello_newman()usingPySQLite. Listing8-11.hello_newman()inPySQLite from pysqlite2 import dbapi2 as sqlite3 # The Python function def hello_newman(): return 'Hello Jerry' con = sqlite3.connect(":memory:") con.create_function("hello_newman", 0, hello_newman) cur = con.cursor() cur.execute("select hello_newman()") print cur.fetchone()[0] Ifyouuse-1asthenumberofarguments,thenthefunctionwillacceptavariablenumberof arguments. Aggregates PySQLiteimplementsuser-definedaggregatesasPythonclasses.Theseclassesmustimplementstep() andfinalize()methods.YouregisteraggregatesusingConnection::create_aggregate(),whichtakes threearguments:thefunction’sSQLname,thenumberofarguments,andtheclassnamethat implementstheaggregate.Listing8-12implementsasimpleSUMaggregatecalledpysum. Listing8-12.Thepysum()AggregateinPySQLite from pysqlite2 import dbapi2 as sqlite3 class pysum: def init(self): self.sum = 0 def step(self, value): self.sum += value def finalize(self): return self.sum 231 CHAPTER8■LANGUAGEEXTENSIONS con = sqlite3.connect("foods.db") con.create_aggregate("pysum", 1, pysum) cur = con.cursor() cur.execute("select pysum(id) from foods") print cur.fetchone()[0] APSWasanAlternativePythonInterface APSWiswrittenandmaintainedbyRogerBinns.DetailedinformationonAPSWcanbefoundat http://code.google.com/p/apsw/.AlthoughAPSWandpysqlitesharesomecommoncapabilitiesanda verysimilarsyntacticalstyle,APSWgoesfurtherinprovidingarangeofadditionalfeaturesandAPI mappingpoints.RatherthanrepeatingverysimilarPythoncodesamples,we’lloutlinethekeybenefits ofAPSWandallowyoutoexplorethemasyouwant. Supportforvirtualtables,VFS,blobI/O,backups,andfilecontrol:APSW providescomprehensivesupportforthelatestfeaturesprovidedbySQLite,as wellasdatabasemanagementtasksthataren’tprovidedthroughpysqlite’s narrowerfocusonDBAPIconformity. APSWPythonShell:APSWincorporatesanextensibleshellthatcanbeusedin placeoftheSQLitecommandinterface.Thisincludesgreatfeaturessuchas color-codedsyntax,CSVformattingandhandling,strictlycorrecterror handling,andadditionalformattingoptionsfordataandmessages. Consistenttransactionhandling:APSWalwaysperformstransactionsasyou wouldexpect,ratherthanmimickingpysqlite’sattempttointuitivelyhandle themwithoutyourinvolvement. Therearealsoahostofothernicelittle(andevenmajor)featuresthatmakeAPSWajoytowork with.Youcanreviewallofthesecapabilitiesathttp://apidoc.apsw.googlecode.com/hg/pysqlite.html. Ruby TheRubyextensionwaswrittenbyJamisBuckof37Signalsandisnowmaintainedbyagroupof developers.Youcanobtaindetailedinformationontheextensionaswellasthesourcecodeat http://rubyforge.org/projects/sqlite-ruby.ThecompletedocumentationfortheSQLite3extension canbefoundathttp://sqlite-ruby.rubyforge.org/sqlite3/,thoughthelayoutisalittledaunting. Installation Theextensioncanbebuiltintwoways:withorwithoutSWIG.TheRubyconfigurationscriptwill automaticallyfigureoutwhetherSWIGisavailableonyoursystem.Youshouldbuildtheextensionwith SWIG(theCextension),becausethatimplementationismorestable.Ifyouroperatingsystemusesa well-developedpackagemanagementandrepositorysystem(likeDebian,Ubuntu,andsoon),you’ll alsofindpackagesavailableforyoursystemthere. Atthetimeofthiswriting,thecurrentversionofsqlite-rubyis1.3.1.Tobuildfromsource,fetchthe tarballfromhttp://rubyforge.org/projects/sqlite-ruby.Unpackthetarball,andrunthreesetup commands: 232 CHAPTER8■LANGUAGEEXTENSIONS fuzzy@linux fuzzy@linux fuzzy@linux fuzzy@linux fuzzy@linux $ $ $ $ $ tar xjvf sqlite3-ruby-1.3.1.tar.bz2 cd sqlite3-ruby-1.3.1 ruby setup.rb config ruby setup.rb setup ruby setup.rb install IfyouhaveRubygemsinstalled,youcangetRubytodoeverythingforyouinonestep: fuzzy@linux $ gem install --remote sqlite3-ruby Ifyouareinstallingfromarepository,ensureyoucheckyourinstalledversionofRubyandmatchthe rightversionfromtherepository.BecauseoldversionsofSQLitealsoenjoysupport,ensureyouinstall thelibsqlite3-rubyorequivalentpackageforyourplatform.Forexample,underUbuntu: fuzzy@linux $ ruby --version ruby 1.8.6 (2007-09-24 patchlevel 111) [x86_64-linux] fuzzy@linux $ sudo apt-get install libsqlite3-ruby libsqlite-ruby libsqlite-ruby1.8 ... many apt messages fly past ... Connecting ToloadtheSQLiteextension,youmustimportthesqlitemodule,usingeitherloadorrequire,as follows: require 'sqlite' YouconnecttoadatabasebyinstantiatingaSQLite::Databaseobject,passinginthenameofthe databasefile.Bydefault,columnsinresultsetsareaccessiblebytheirordinal.However,theycanbe accessedbycolumnnamebysettingDatabase::results_as_hashtotrue: require 'sqlite' db = SQLite::Database.new("foods.db") db.results_as_hash = true QueryProcessing TheRubyextensionfollowstheSQLiteAPIquiteclosely.Itoffersbothpreparedqueriesandwrapped queries. PreparedqueriesareperformedviaDatabase::prepare(),whichpassesbackaStatementobject, whichholdsasqlite3_stmtstructure.YouexecutethequeryusingStatement’sexecutemethod,which producesaResultSetobject.YoucanpasstheStatementablock,inwhichcaseitwillyieldtheResultSet objecttotheblock.Ifyoudon’tuseablock,thentheStatementwillprovidetheResultSetobjectasa returnvalue.ResultSetisusedtoiterateoverthereturnedrows.Internally,itusessqlite3_step().You cangetattherowsinResultSeteitherthroughablockusingtheeach()iteratororbyusinga conventionalloopwiththenext()method,whichreturnsthenextrecordintheformofanarrayornilif ithasreachedtheendoftheset.Listing8-13showspreparedqueriesinactioninRuby. 233 CHAPTER8■LANGUAGEEXTENSIONS Listing8-13.PreparedQueriesinRuby #!/usr/bin/env ruby require 'sqlite3' db = SQLite3::Database.new('foods.db') stmt = db.prepare('select name from episodes') stmt.execute do | result | result.each do | row | puts row[0] end end result = stmt.execute() result.each do | row | puts row[0] end stmt.close() ItisimportanttocallStatement.close()whenyouaredonetofinalizethequery.Becausea Statementobjectholdsasqlite3_stmtstructureinternally,eachsubsequentcalltoexecutethusreuses thesamequery,avoidingtheneedtorecompilethequery. ParameterBinding TheRubyextensionsupportsbothpositionalandnamedparameterbinding.Youbindparametersusing Statement::bind_param()and/orStatement::bind_params().bind_param()hasthefollowingform: bind_param(param, value) IfparamisaFixnum,thenitrepresentstheposition(index)oftheparameter.Otherwise,itisusedas thenameoftheparameter.bind_params()takesavariablenumberofarguments.Ifthefirstargumentis ahash,thenitusesittomapparameternamestovalues.Otherwise,ituseseachargumentasa positionalparameter.Listing8-14illustratesbothformsofparameterbinding. Listing8-14.ParameterBindinginRuby require 'sqlite3' db = SQLite3::Database.new("foods.db") db.results_as_hash = true # Named paramters 234 CHAPTER8■LANGUAGEEXTENSIONS stmt = db.prepare('select * from foods where name like :name') stmt.bind_param(':name', '%Peach%') stmt.execute() do |result| result.each do |row| puts row['name'] end end # Positional paramters stmt = db.prepare('select * from foods where name like ? or type_id = ?') stmt.bind_params('%Bobka%', 1) stmt.execute() do |result| result.each do |row| puts row['name'] end end # Free read lock stmt.close() Ifyoudon’tneedtouseparameters,ashorterwaytoprocessqueriesisusingDatabase::query(), whichcutsouttheStatementobjectandjustreturnsaResultSet,asshowninListing8-14. Listing8-14.UsingtheDatabase::query()MethodinRuby require 'sqlite3' db = SQLite3::Database.new("foods.db") db.results_as_hash = true result = db.query('select * from foods limit 10') result.each do |row| puts row['name'] end result.reset() while row = result.next puts row['name'] end result.close() LikeStatementobjects,Resultobjectsarealsothinwrappersoverstatementhandlesandtherefore representcompiledqueries.Theycanbererunwithacalltoreset,whichcallssqlite3_reset() internallyandreexecutesthequery.UnlikeStatementobjectshowever,theycannotbeusedforbound parameters. Other,evenshorter,querymethodsincludeDatabase::get_first_row(),whichreturnsthefirstrow ofaquery,andDatabase::get_first_value(),whichreturnsthefirstcolumnofthefirstrowofaquery. 235 CHAPTER8■LANGUAGEEXTENSIONS User-DefinedFunctions User-definedfunctionsareimplementedusingDatabase::create_function(),whichhasthefollowing form: create_function( name, args, text_rep=Constants::TextRep::ANY ) {|func, *args| ...} Here,nameisthenameoftheSQLfunction,argsisthenumberofarguments(-1isvariable),and text_repcorrespondstotheUTFencoding.ValuesareUTF8,UTF16LE,UTF16BE,UTF16,andANY.Finally,the functionimplementationisdefinedintheblock.Listing8-15illustratesaRubyimplementationof hello_newman(). Listing8-15.hello_newman()inRuby require 'sqlite3' db = SQLite3::Database.new(':memory:') db.create_function('hello_newman', -1 ) do |func, *args| if args.length == 0 func.result = 'Hello Jerry' else func.result = 'Hello %s' % [args.join(', ')] end end puts puts puts puts db.get_first_value("SELECT db.get_first_value("SELECT db.get_first_value("SELECT db.get_first_value("SELECT hello_newman()") hello_newman('Elaine')") hello_newman('Elaine', 'Jerry')") hello_newman('Elaine', 'Jerry', 'George')") Thisprogramproducesthefollowingoutput: Hello Hello Hello Hello Jerry Elaine Elaine, Jerry Elaine, Jerry, George Java LikePythonmentionedearlier,awealthofJavaextensionsareavailableforSQLite.Thesefallintotwo broadcamps:theJDBCdrivers(sometimeswithaddedgoodies)andcompletereimplementationsof SQLiteinJava.We’llcoverthejavasqlitewrapperwrittenbyChristianWerner,whowrotetheSQLite ODBCdriveraswell.ItincludesbothaJDBCdriverandanativeJNIextension,whichcloselyshadows theSQLiteCAPI.Youcandownloadtheextensionfromwww.ch-werner.de/javasqlite/overviewsummary.html#jdbc_driver. 236 CHAPTER8■LANGUAGEEXTENSIONS ThemainclassintheJNIextensionisSQLiteDatabase.Mostofitsmethodsareimplementedusing callbacksthatreferencethefollowinginterfaces: • SQLite.Callback • SQLite.Function • SQLite.Authorizer • SQLite.Trace • SQLite.ProgressHandler TheSQLite.Callbackinterfaceisusedtoprocessresultsetsthroughrowhandlers,aswellascolumnand typeinformation.SQLite.AuthorizerisathinwrapperovertheSQLiteCAPIfunction sqlite3_set_authorizer(),withwhichyoucaninterceptdatabaseeventsbeforetheyhappen. SQLite.TraceisusedtoviewSQLstatementsastheyarecompiled,anditwrapssqlite3_trace(). SQLite.ProgressHandlerwrapssqlite3_progress_handler(),whichisusedtoissueprogresseventsafter aspecifiednumberofVDBEinstructionshavebeenprocessed. Installation ThecurrentversionrequiresJDK1.4ornewer.TheextensionusesGNUAutoconf,sobuildingand installingrequiresonlythreesteps: fuzzy@linux fuzzy@linux fuzzy@linux fuzzy@linux $ $ $ $ tar xvzf javasqlite-20100727.tar.gz ./configure make make install TheconfigurescriptwilllookforSQLiteandtheJDKinseveraldefaultlocations.However,to explicitlyspecifywheretolookforSQLiteandtheJDK,severalcommand-lineoptionsareavailable. --with-sqlite=DIRtospecifythesqlitev2location --with-sqlite3=DIRtospecifythesqlitev3location --with-jdk=DIRtospecifytheJDKlocation. Tospecifytheplacewheretheresultinglibraryshouldbeinstalled(libsqlite_jni.sofile),usethe-prefix=DIRoption.Thedefaultlocationis/usr/lib/jvm/java-6-sun/jre/lib/i386(thoughthismay varydependingonyourdistributionofLinuxoruseofanotherUnixflavororMacOSX,suchas /usr/local/lib,forexample.)Tospecifywherethesqlite.jaristobeinstalled,usethe--withjardir=DIRoption.Thedefaultis/usr/lib/jvm/java-6-sun-1.6.0.20/jre/lib/ext/sqlite.jar(again, thismayvarydependingontheageandtypeofyourdistribution).Thisfilecontainsthehigh-levelpart andtheJDBCdriver.Atruntime,itisnecessarytotelltheJVMbothplaceswiththe-classpathandDjava.library.path=..command-lineoptions. ForWindows,themakefilesjavasqlite.makandjavasqlite3.makareprovidedinthedistribution. TheycontainsomebuildinstructionsandusetheJ2SE1.4.2fromSunandMicrosoftVisualC++6.0.A DLLwiththenativeJNIpart(includingSQLite3.7.0)andtheJARfilewiththeJavapartcanbe downloadedfromthewebsite. 237 CHAPTER8■LANGUAGEEXTENSIONS Connecting YouconnecttoadatabaseusingSQLiteDatabase::open(),whichtakesthenameofthedatabaseandthe filemode,asshowninListing8-16.ThefilemodeisanartifactfromSQLite2APIandisnolongerused. Youcanprovideanyvaluetosatisfythefunction.ThecodeinListing8-16istakenfromtheexamplefile SQLiteJNIExample.java.Thefullcodefromthisexampleillustratesallthemainfacetsofdatabase operations:connecting,querying,usingfunctions,andsoforth. Listing8-16.TheJavaSQLiteTestProgram import SQLite.*; public class SQLiteJNIExample { public static void main(String args[]) { SQLite.Database db = new SQLite.Database(); try { db.open("foods.db", 700); // Trace SQL statements db.trace(new SQLTrace()); // Query example query(db); // Function example user_defined_function(db); // Aggregate example user_defined_aggregate(db); } } db.close(); } catch (java.lang.Exception e) { System.err.println("error: " + e); } ... QueryProcessing YourqueriesareissuedusingSQLiteDatabase::compile().Thisfunctioncanprocessastringcontaining multipleSQLstatements.ItreturnsaVM(virtualmachine)objectthatholdsallthestatements. 238 CHAPTER8■LANGUAGEEXTENSIONS TheVMobjectparseseachindividualSQLstatementoneachcalltocompile(),returningtrueifa completeSQLstatementwascompiledandfalseotherwise.YoucanthereforeiteratethroughallSQL statementsinaloop,breakingwhentheVMhasprocessedthelaststatement. WhentheVMhascompiledastatement,youcanexecuteitusingVM::step().Thisfunctiontakesa singleobject,whichimplementsaSQLite.Callbackinterface.TheexampleusesaclasscalledRowforthis purpose,whichisshowninListing8-17. Listing8-17.TheRowClass class Row implements SQLite.Callback { private String row[]; public void columns(String col[]) {} public void types(String types[]) {} public boolean newrow(String data[]) { // Copy to internal array row = data; return false; } } public String print() { return "Row: [" + StringUtil.join(row, ", ") + "]"; } TheSQLite.Callbackinterfacehasthreemethods:columns(),types(),andnewrow().Theyprocess thecolumnnames,columntypes,androwdata,respectively.EachcalltoVM::step()updatesallofthe column,type,androwinformation. TheuseofVMisillustratedinthequery()functionoftheexample,whichislistedinListing8-18. Listing8-18.Thequery()Function public static void query(SQLite.Database db) throws SQLite.Exception { System.out.println("\nQuery Processing:\n"); Row row = new Row(); db.set_authorizer(new AuthorizeFilter()); Vm vm = db.compile( "select "delete "insert "select do { * from foods limit 5;" + from foods where id = 5;" + into foods (type_id, name) values (5, 'Java');" + * from foods limit 5" ); 239 CHAPTER8■LANGUAGEEXTENSIONS while (vm.step(row)) { System.err.println(row.print()); } } while (vm.compile()); } TheSQLite.Database::exec()performsself-containedqueriesandhasthefollowingform: void exec(String sql, Callback cb, String[] params) Theparamsarraycorrespondsto%qor%QparametersintheSQLstatement.Anexampleisshownin Listing8-19. Listing8-19.Theexec_query()Function public static void exec_query(SQLite.Database db) throws SQLite.Exception { System.out.println("\nExec Query:\n"); String sql = "insert into foods (type_id, name) values (5, '%q')"; ResultSet result = new ResultSet(); String params[] = {"Java"}; db.exec(sql, result, params); } System.out.println("Result: last_insert_id(): " + db.last_insert_rowid()); System.out.println("Result: changes(): " + db.changes()); Notethatthisisnotthesamethingasparameterbinding.Rather,thisissprintfstylesubstitution usingsqlite3_vmprintf()intheSQLiteCAPI. User-DefinedFunctionsandAggregates TheSQLite.Functioninterfaceisusedtoimplementbothuser-definedfunctionsanduser-defined aggregates.Thehello_newman()functioninJavaisillustratedinListing8-20. Listing8-20.hello_newman()inJava class HelloNewman implements SQLite.Function { public void function(FunctionContext fc, String args[]) { if (args.length > 0) { fc.set_result("Hello " + StringUtil.join(args, ", ")); } 240 CHAPTER8■LANGUAGEEXTENSIONS } else { fc.set_result("Hello Jerry"); } public void step(FunctionContext fc, String args[]){} public void last_step(FunctionContext fc) { fc.set_result(0); } } Noticethatthestep()andlast_step()functions,whilespecifictoaggregates,mustalsobe implementedeventhoughtheydonothinginuser-definedfunctions.Thisisbecausethe SQLite.Functioninterfacedefinesmethodsforbothfunctionsandaggregates.Thisclassisregistered usingSQLite.Database.create_function().Thefunction’sreturntypemustalsoberegisteredusing SQLite.Database.function_type().Listing8-21illustratesusingtheJavaimplementationof hello_newman(). Listing8-21.Thehello_newman()TestCode // Register function db.create_function("hello_newman", -1, new HelloNewman()); // Set return type db.function_type("hello_newman", Constants.SQLITE_TEXT); // Test PrintResult r = db.exec("select db.exec("select db.exec("select new PrintResult(); hello_newman()", r); hello_newman('Elaine', 'Jerry')", r); hello_newman('Elaine', 'Jerry', 'George')", r); JDBC TheJavaextensionalsoincludessupportforJDBC.Tousethedriver,specifySQLite.JDBCDriverasthe JDBCdriver’sclassname.Also,makesureyouhavesqlite.jarinyourclasspathandthenativelibrary inyourJavalibrarypath.TheJDBCURLstoconnecttoaSQLitedatabasehavetheformat jdbc:sqlite:/path,wherepathhastobespecifiedasthepathnametotheSQLitedatabase,forexample. jdbc:sqlite://dirA/dirB/dbfile jdbc:sqlite:/DRIVE:/dirA/dirB/dbfile jdbc:sqlite:///COMPUTERNAME/shareA/dirB/dbfile Currently,thesupporteddatatypesonSQLitetablesarejava.lang.String,short,int,float,and double.Somesupportexistsforjava.sql.Date,java.sql.Time,andjava.sql.Timestamp.Aconnection propertydatereprisusedtodefinebehaviorforthesedatatypes.Avalueofdaterepr=JuliansetsSQLite tointerpretallinsert/updatesofthesedatatypesasafloating-pointconversiontotheequivalentJulian 241 CHAPTER8■LANGUAGEEXTENSIONS Day.AnyothervalueswitchesbehaviortousethestringformatsYYYY-mm-ddfordate,HH:MM:SSfortime, andYYYY-mm-dd HH:MM:SS.ffortimestamp. OtherdatatypemappingdependsmostlyontheavailabilityoftheSQLitepragmasshow_datatypes andtable_info.Enoughbasicdatabasemetadatamethodsareimplementedsuchthatitispossibleto accessSQLitedatabaseswithJDK1.4ornewerandtheiSQL-Viewertool. Listing8-22isasimpleexample(locatedinSQLiteJDBCExample.java)ofusingtheJDBCdriverto querythefoodstable. Listing8-22.TheSQLiteJDBCTestProgram import java.sql.*; import SQLite.JDBCDriver; public class SQLiteJDBCExample { public static void main ( String [ ] args ) { try { Class.forName("SQLite.JDBCDriver"); Connection c = DriverManager.getConnection( "jdbc:sqlite://tmp/foods.db", "" // username (NA), "" // password (NA)); Statement s = c.createStatement(); ResultSet rs = s.executeQuery ("select * from foods limit 10"); int cols = (rs.getMetaData()).getColumnCount(); while (rs.next()) { String fields[] = new String[cols]; for(int i=0; i select rowid,b,typeof(i),i>'text' from domain order by b; rowid ----5 1 3 2 4 b ----NULL 3.14 314 3.14 1B typeof(i -------null real integer real blob i>'text' -----------NULL 0 0 0 1 Thesecondrulesimplystatesthatwhencomparinganumericandnon-numericcolumn,where possibleSQLitewilltrytoconvertthenon-numericcolumntonumericformat: sqlite> sqlite> sqlite> sqlite> create insert insert select a ---------2 2 316 table rule2(a int, b text); into rule2 values(2,'1'); into rule2 values(2,'text'); a, typeof(a),b,typeof(b), a>b from rule2; typeof(a) ---------integer integer b ---------1 text typeof(b) ---------text text a>b ---------1 0 CHAPTER11■SQLITEINTERNALSANDNEWFEATURES Columnaisaninteger,andbistext.Whenevaluatingtheexpressiona>b,SQLitetriestocoercebto integerwhereitcan.Inthefirstrow,bis'1',whichcanbecoercedtointeger.SQLitemakesthe conversionandcomparesintegers.Inthesecondrow,bis'text'andcan’tbeconverted.SQLitethen comparesstorageclassesintegerandtext. Thethirdrulejustreiteratesthatstorageclassesestablishedbycontextarecomparedatfacevalue. Ifwhatlookslikeatexttypeiscomparedwithwhatlookslikeanintegertype,thentextisgreater. Additionally,youcanmanuallyconvertthestoragetypeofacolumnoranexpressionusingthe cast()function.Considerthefollowingexample: sqlite> select typeof(3.14), typeof(cast(3.14 as text)); typeof(3.14) -----------real typeof(cast(3.14 as text)) -------------------------text MAKESHIFT STRICT TYPING Ifyouneedsomethingstrongerthantypeaffinityfordomainintegrity,thenCHECKconstraintscanhelp.You canimplementpseudo–stricttypingdirectlyusingasinglebuilt-infunctionandaCHECKconstraint.As mentionedearlier,SQLitehasafunctionthatreturnstheinferredstorageclassofavalue—typeof().You canusetypeof()inanyrelationalexpressiontotestforavaluetype.Here’sanexample: sqlite> 0 sqlite> 0 sqlite> 1 sqlite> 1 sqlite> 1 select typeof(3.14) = 'text'; select typeof(3.14) = 'integer'; select typeof(3.14) = 'real'; select typeof(3) = 'integer'; select typeof('3') = 'text'; Therefore,youcanusethisfunctiontoimplementaCHECKconstraintthatlimitstheacceptabletypes allowedinacolumn: sqlite> create table domain (x integer check(typeof(x)='integer')); sqlite> insert into domain values('1'); SQL error: constraint failed sqlite> insert into domain values(1.1); SQL error: constraint failed sqlite> insert into domain values(1); sqlite> select x, typeof(x) from domain; 317 CHAPTER11■SQLITEINTERNALSANDNEWFEATURES x typeof(x) -- ---------1 integer sqlite> update domain set x=1.1; SQL error: constraint failed TheonlycatchhereisthatyouarelimitedtocheckingforSQLite’snativestorageclasses(orwhatcanbe implementedusingotherbuilt-inSQLfunctions).However,ifyouareaprogrammerandeitherusea languageextensionthatsupportsSQLite’suser-definedfunctions(forexample,Perl,Python,orRuby)or usetheSQLiteCAPIdirectly,youcanimplementevenmoreelaboratefunctionsfortypechecking,which canbecalledfromwithinCHECKconstraintsithinCHECKconstraints. Write Ahead Logging WiththereleaseofSQLite3.7.0,anewoptionalmodelformanagingatomictransactionswas introduced:theWriteAheadLog.TheWriteAheadLog(WAL)isnotnewtothewiderdatabase technologyworld,butit’sinclusioninSQLiteisamazingfortworeasons.First,thisfurtherenhancesthe sophisticationandrobustnessofSQLiteandthedatabasesyouuse.Second,it’sastoundingthatsucha greatfeaturehasbeenincludedinSQLiteandyetthecodeandresultingbinariesarestillsocompact andconcise. HowWALWorks Inthetraditionalmodeofoperation,SQLiteusestherollbackjournaltocapturetheprechangedata fromyourSQLstatementsandthenmakeschangestothedatabasefile(we’llavoiddiscussingthe variouscachingandfilesystemlayershere,becausetheyapplyregardlessofmodel).WhentheWALis used,thearrangementisreversed.Insteadofwritingtheoriginal,prechangeddatatotherollback journal,usingWALleavestheoriginaldatauntouchedinthedatabasefile.TheWALfileisusedtorecord thechangestothedatathatoccurforagiventransaction.Acommitactionchangestobeingaspecial recordwrittentotheWALtoindicatetheprecedingchangesareinfactcompleteandtobehonored fromanACIDperspective. Thischangeinrolesbetweendatabasefileandlogfileimmediatelyalterstheperformance dynamicsoftransactions.Insteadofcontendingoverthesamepagesinthedatabasefile,multiple transactionscansimultaneouslyrecordtheirdatachangesintheWALandcancontinuereadingthe unaltereddatafromthedatabasefile. Checkpoints ThefirstquestionthatmostpeoplethinkofwhenconfrontedwithWALtechnologiesisusually“But whendoesthedataultimatelygetwrittentothedatabase?”We’regladyouasked.Obviously,aneverendingstreamofchangesbeingwrittentoaconstantlygrowingWALfilewouldn’tscaleorwithstandthe vagariesoffilesystemfailures.TheWALusesacheckpointfunctiontowritechangesbacktothe database.Thisprocesshappensautomatically,sothedeveloperneednotconcernthemselveswith managingthecheckpointingandwrite-backtothedatabase.Bydefault,theWALinvokesacheckpoint whentheWALfilehits1,000pagesofchanges.Thiscanbemodifiedtosuitdifferentoperatingscenarios. 318 CHAPTER11■SQLITEINTERNALSANDNEWFEATURES Concurrency BecausechangesnowwritetotheWALfile,ratherthanthedatabasefile,youmightbewonderinghow thisaffectsSQLiteconcurrency.Thegoodnewsistheanswer“overwhelminglyforthebetter!” NewreadersaccessingdatafromtheWAL-enableddatabaseinitiatealookupintheWALfileto determinethelastcommitrecord.Thispointbecomestheirendmarkerforread-onlyconsistency,such thattheywillnotconsidernewwritesbeyondthispointinthefile.Thisishowthereadbecomesa consistentread—itsimplytakesnonoticeofanythingafterthecommitconsidereditsendmarker.Each readerassessisindependent,soit’spossibletohavemultiplethreadseachwithadifferentnotionof theirownindividualendmarkwithintheWALfile. Toaccessapageofdata,thereaderusesawal-indexstructuretoscantheWALfiletofindout whetherthepageexistswithchangesandusesthelatestversioniffound.Ifthepageisn’tpresentinthe WALfile,itmeansithasn’tbeenalteredsincethelastcheckpoint,andthereaderaccessesthepagefrom thedatabasefile. Thewal-indexstructureisimplementedinsharedmemory,meaningthatallthreadsandprocesses musthaveaccesstothesamememoryspace.Thatis,yourprogramsmustallexecuteonthesame machineinordertoaccessaWAL-enableddatabaseor,moreaccurately,tousethewal-index.Thisisthe featurethatrulesoutoperationacrossnetworkfilesystemslikeNFS. Asforwriters,thankstothesequentialnatureoftheWALfile,theysimplyappendchangestothe end.Note,however,thatthismeanstheymusttakeitinturnappendingtheirchanges,sowriterscan stillblockwriters. ActivationandConfigurationWAL SQLitewillstilldefaulttotherollbackjournalmethoduntilyoudecidetoswitchyourdatabasetousethe WAL.UnlikeotherPRAGMAsettings,turningontheWALisapersistentdatabase-levelchange.Thismeans youcanturnonWALinoneprogramorfromtheSQLitecommandshell,andallotherprogramswill thenbeusingthedatabaseinWALmode.Thisisveryhandybecauseitmeansyoudon’thavetoalter yourapplicationstoturnonWAL. ThesettingPRAGMA journal_mode=WAListhecommandnecessarytoactivateWAL.Acalltothis pragmawillreturnasastringthefinaljournalmodeforthedatabase. SQLite version 3.7.3 Enter ".help" for instructions Enter SQL statements terminated with a ";" sqlite> PRAGMA journal_mode=WAL; wal IfthechangetoWALissuccessful,thestringwalisreturned,asshown.Ifforsomereasonthisfails, suchastheunderlyinghostnotsupportingthenecessarysharedmemoryrequirements,thejournal modewillbeunchanged.Forinstance,onadefaultdatabase,thismeansthecommandwillreturnthe stringdelete,meaningtherollbackjournalisstillactive. 319 CHAPTER11■SQLITEINTERNALSANDNEWFEATURES Aswellasthejournal_mode PRAGMA,severalAPIoptionsandrelatedPRAGMAsaresupportedtocontrol WALandcheckpointbehavior. • sqlite3_wal_checkpoint():Forcesacheckpoint(alsoavailableaswal_checkpoint PRAGMA) • sqlite3_wal_autocheckpoint():Altersautocheckpointpagethreshold (wal_autocheckpoint PRAGMA) • sqlite3_wal_hook():Registersacallbacktobeinvokedwhenaprogramcommits totheWAL. Withtheseoptions,it’spossibletofine-tuneWALandcheckpointbehaviortosuiteventhemost unusualofapplications. WALAdvantagesandDisadvantages Naturally,achangesuchasWALbringswithititsownadvantagesanddisadvantages.Wethinkthatthe advantagesaresignificant,butit’sbesttobeawareofimpactsoyoucanformyourownjudgment. MovingtoWALhasthefollowingadvantages: • Readersdonotblockwriters,andwritersdonotblockreaders.Thisisthe“gold standard”inconcurrencymanagement. • WALisflat-outfasterinmostoperatingscenarios,whencomparedtorollback journaling. • DiskI/Obecomesmorepredictableandinducesfewerfsync()systemcalls. BecauseallWALwritesaretoalinearlywrittenlogfile,muchoftheI/Obecomes sequentialandcanbeplannedaccordingly. Tobalancetheequation,herearesomeofthenotabledisadvantagesofWAL: • Allprocessingisboundtoasinglehost.Thatis,youcannotuseWALovera networkedfilesystemlikeNFS. • UsingWALintroducestwoadditionalsemipersistentfiles,-waland -shm,fortheWALandrelatedsharedmemoryrequirements.Thiscanbe unappealingforthoseusingSQLitedatabasesasanapplicationfileformat.This alsoaffectsread-onlyenvironments,becausethe–shmfilemustbewritable, and/orthedirectoryinwhichthedatabaseexists. • WALperformancewilldegradeforverylarge(approachinggigabyte)transactions. AlthoughWALisahigh-performanceoption,verylargeorverylong-running transactionsintroduceadditionaloverhead. AnumberofotheredgecasesareworthinvestigatingifyouarethinkingofusingSQLitewithWALenableddatabasesinunusualenvironments.Youcanreviewmoredetailsabouttheseat www.sqlite.org/wal.html. 320 CHAPTER11■SQLITEINTERNALSANDNEWFEATURES OperationalIssueswithWAL-EnabledSQLiteDatabases ThereareafewoperationalconsiderationswhenworkingwithWAL-enabledSQLitedatabases.These areprimarilyperformanceandrecoveryrelated. Performance WenotedearlierthatenablingWALusuallytranslatestobetterperformance.Underourdisadvantages, weoutlinedthatforverylargechangesindata,orverylong-runningtransactions,aslightdropin performancemightresult.Here’sthebackgroundonhowthiscanhappenandwhattodo. WithWALenabled,youimplicitlygainaperformanceadvantageoverrollbackjournalingbecause onlyonewriteisrequiredtocommitatransaction,insteadoftwo(onetothedatabaseandrollback journal).However,untilacheckpointoccursthatfreesspaceintheWALfile,thefileitselfmustkeep growingasmoreandmorechangesarerecorded.Normallythisisn’tanissue:someonewillbethelucky committerwhopushesWALthroughthe1,000-pagethresholdforacheckpoint,andtheWALwillclear, andthecyclewillcontinue.Butthecheckpointcompletesitsworkifitfindsanend-pointmarkerforany currentlyactivereader.Thatmeansaverylong-runningtransactionorreadactivitycankeepthe checkpointfrommakingprogress,evenonsubsequentattempts.ThisinturnmeanstheWALfilekeeps growinginsize,withcommensuratelylongerseektimesfornewreaderstofindpages. Anotherperformanceconsiderationishowmuchworkistriggeredwhenatransactionhitsthe checkpointthreshold.Youmayfindthatthevariablenatureoflotsofveryfasttransactionsandthenone slightlylongeronethatmustperformthecheckpointworkforitspredecessorsunattractiveinsome scenarios. Forbothoftheseperformancehypotheticals,youareessentiallyweighingupreadandwrite performance.Ourrecommendedapproachistofirstrememberthatyoucan’thavethebestofboth,so somecompromisewillbeneeded,andthenifnecessaryusethesqlite3_wal_checkpoint()and sqlite3_wal_autocheckpoint()toolstobalancetheloadandfindahappyequilibrium. Recovery VersionsofSQLitepriorto3.7.0havenoknowledgeofWAL,northemethodsusedforrecoveringWALbaseddatabases.TopreventolderversionstramplingalloveraWAL-enabledSQLitedatabaseduring crashrecovery,thedatabasefileformatnumberwasbumpedupfrom1to2.Whenanolderversionof SQLiteattemptstorecoveradatabasewiththischange,itrealizesitisnota“valid”SQLitedatabaseand willreportanerrorsimilartothefollowing. file is encrypted or is not a database Don’tpanic!Yourdatabaseisfine,buttheversionofSQLitewillneedtobeupgradedinorderto workwithit.Alternatively,youcanchangebacktotherollbackjournal. PRAGMA journal_mode=DELETE; Thisresetsthedatabasefileformatnumberto1. 321 CHAPTER11■SQLITEINTERNALSANDNEWFEATURES Summary ThatconcludesourjourneythroughSQLite,notonlyinthischapterbutthebookaswell.Wehopeyou haveenjoyedit.AsyousawinChapter1,SQLiteismorethanmerelyafreedatabase.Itisawell-written softwarelibrarywithawiderangeofapplications.Itisadatabase,autility,andahelpfulprogramming tool. Whatyouhaveseeninthischapterbarelyscratchesthesurfaceoftheinternals,butitshouldgive youabetterideaabouthowthingsworknonetheless.Anditalsogivesyouanappreciationforhow elegantlySQLiteapproachesaverycomplexproblem.YouknowfirsthandhowbigSQLis,andyou’ve seenthecomplexityofthemodelsbehindit.YetSQLiteisasmalllibraryandmanagestoputmanyof theseconceptstoworkinasmallamountofcodeandexcels! 322 Index ■Special Characters $argcparameter,225 $func_refparameter,225 $nameparameter,225 $namevariable,250 $type_idvariable,250 $xvariable,245 %operator,61 &operator,61 *operator,61 _rowid_value,94 |operator,61 ||operator,61 +operator,61 operator,61 /operator,61 -operator,61 ■A abortpolicy,113 abortresolution,113–115 abs()function,66 accessfunctions,forB-treemoduleAPI, 308–309 activation,ofWAL,319 addcolumnclause,55 ADDCOLUMNcommand,12 ADDCONSTRAINTcommand,12 AddFiledialogbox,263 AdditionalDependenciespropertypage, 28 administration,118–124 attachingdatabases,118–119 cleaningdatabases,119 ofdatabases,35–45 backingupdatabase,42–43 creatingdatabase,35–37 databasefileinformation,44–45 exportingdata,39 formattingdata,40–41 gettingschemainformation,37–39 importingdata,40 unattendedmaintenance,41–42 explainqueryplancommand,123 andpragmas,120–122 auto_vacuum,122 cachesize,120 databaseschema,120–121 integrity_check,122 synchronous,121–122 temp_store,122 temp_store_directory,122 323 ■ INDEX sqlite_mastertable,123 administrators,SQLitefor,3 Advancedtab,19 afterkeyword,108 aftertrigger,110 aftervalue,134 aggregates,67 inExtensionCAPI,204–209 exampleof,206–209 registering,205–206 withlanguageextensions forPerl,225–226 forPython,231–232 user-defined,137 aliases,fortables,77–79 ALTERCOLUMNcommand,12 ALTERTABLEcommand,12,54 altertablestatement,286,288 alteringtables,54–55 ambiguity,ofcolumnnames,77 aNamevariable,272 ANDoperator,61 AndroidDDMS,280 AndroidDeveloperTools,280–281 Androiddevelopment,279–301 backupservicefordatabases,300 andlargedatabases,300–301 prerequisitesfor,279–284 additionalcomponents,281–284 downloadingAndroidDeveloper Tools,280–281 downloadingAndroidSDKStarter Package,280 JDK(JavaDevelopmentKit),280 SeinfeldAndroidapp,294–300 addingdatabasetoproject,296 creatingproject,295–296 linkingdataanduserinterface,298– 299 324 queryingfoodstable,296–297 userinterfacefor,297–298 viewingapp,299–300 SQLiteDatabaseclass,286–290 conveniencemethodsfor,288–289 executingquerieswith,287–288 implementing,290–292 openingandclosingdatabaseswith, 286–287 transactionswith,289 usefulmethodsfor,290 SQLiteOpenHelperclass,285–286,290– 292 SQLiteQueryBuilderclass,293–294 AndroidPlatformscomponent,282 AndroidVirtualDevice(AVD),283 android.database.sqlitenamespace,285 API,forB-treemodule accessfunctions,308–309 configurationfunctions,310 cursorfunctions,309 recordfunctions,310 tablefunctions,309 AppceleratorTitaniumframework,258, 284 ApplicationSettings,26,28 applicationDidFinishLaunchingevent,276 applicationDidFinishLaunchingfunction, 269 applicationWillTerminateevent,272 aptutility,31 apt-getutility,31 architecture,5–8 backend,7–8 compiler,6 interface,6 utilities,8 virtualmachine,6–7 Arithmeticoperators,62 ■ INDEX askeyword,79 ascsortorder,65 atomicprinciple,111 attachcommand,118 ATTACHevent,182 attachstatement,184 attachingdatabases,118–119 auto_vacuumpragma,119,122,128 autocommitmode,andwritetransactions, 143–145 autoincrementcolumn,95 autoincrementconstraint,95–96 autoincrementkeyword,94–95 available_drivers()function,222 AVD(AndroidVirtualDevice),283 avg()function,67,137,195 avgaggregate,67 ■B bcolumn,317 backend,architectureofSQLite,7–8 backingup,42–43 BackupAgentHelperAPI,300 BackupManagerAPI,300 Bakeryrow,64 bar.dbdatabase,10–11 basetable,54 beforekeyword,108 beforetrigger,110 begincommand,111,116–118,139,141 beginexclusivecommand,118,148 beginimmediatecommand,118,148–149 beginline,141 beginstatement,117 begin.commitcommand,141 begin...commit/rollbacktransaction scope,112 beginTransaction()method,249,289 beginTransactionWithListener()method, 289 binaries forLinux,30–31 forMacOSX,30–31 forPOSIXsystems,30–31 binarycollation,101,138,216 Binarylargeobject(BLOB),4,102 binaryoperators,forwhereclause,60–62 bind_param()method,234 bind_params()method,234 BLOB(Binarylargeobject),4,102 blobclass,102–103,196 blobcolumns,315 B-treemodule,303–310 APIfor accessfunctions,308–309 configurationfunctions,310 cursorfunctions,309 recordfunctions,310 tablefunctions,309 datastructuresofSQLite,127 anddatabasefileformat B+trees,304–305 fieldtypesin,305–306 hierarchicaldataorganizationin, 307 overflowpagesin,307–308 pagereusein,304 recordstructurein,305 recordsin,304 btree.cfile,310 btree.hfile,310 BuildandRunmenuoption,272 buildUnionQuery()method,294 busy()function,147 busyconditions,errorhandlinginCAPI of,176–177 325 ■ INDEX busyhandler,usingwithtransactions, 146–147 ■C CAPI,153–193 errorhandlingin,174–176 ofbusyconditions,176–177 ofschemachanges,177–178 fetchingrecordswith,164–169 columninformationfor,165–166 columnvaluesin,166–167 exampleof,168–169 operationalcontrolfunctions,178–189 commit_hook()function,178–179 rollback_hook()function,179 set_authorizer()function,180–189 update_hook()function,179–180 parameterizedquerieswith,169–174 namedparameters,173 numberedparameters,172 Tclparameters,173–174 preparedquerieswith,161–164 compilationof,161–162 executionof,162 finalizationof,163–164 threadingsupportin,190–193 andmemorymanagement,193 sharedcachemode,190–193 wrapperfunctionsin,153–160 forconnectinganddisconnecting, 153–155 exec()function,155–159 get_table()function,159–160 Cachepartitionsizeparameter,284 cache_sizepragma,120,145 Cartesianjoin,75 cascadeaction,101 caseexpression,83–84 326 cast()function,212,317 casttable,115 cast.namecolumn,115 checkconstraints,99–100,137,315,317– 318 checkpoints,andWAL,318 Churcher,Claire,47 classvalues,103 Classesfolder,265 -classpathoption,237 clauses distinctclause,72 groupbyclause,67–71 limitclause,64 orderbyclause,64–66 whereclause,59–64 binaryoperators,60–62 globoperator,64 likeoperator,63 logicaloperators,63 operators,60 values,60 cleaningdatabases,119 cleanuphandlers,forfunctionsin ExtensionCAPI,202–203 clonecommand,23 close()method,228,244,285,287 Closeinstruction,151 closingdatabases,withSQLiteDatabase class,286–287 CLP(command-lineprogram),17,32–35 incommand-linemode,34–35 installingonWindows,18–21 inshellmode,33–34 cnxargument,197 coalescefunction,85–86 codeandSQLite,149–152 importanceoffinalizing,150–151 sharedcachemode,151–152 ■ INDEX usingmultipleconnections,149–150 collatekeyword,101 collatenocaseconstraint,54 collate1.sqlfile,209 collate2.sqlfile,210 Collationinterface,199 collation_nameparameter,119 collations forcolumns,andindexes,107 anddomainintegrity,101 inExtensionCAPI,209–217 defined,210–212 ondemand,216–217 exampleof,212–216 overviewof,210–212 typesof,212 user-defined,138 columnconstraints,54 columnnames,andambiguityof,77 columntypes,andtypeaffinity,313 column_defattribute,55 column_definitionsattribute,54 column_listvariable,87 columns collationsfor,andindexes,107 informationabout,inCAPI,165–166 valuesof,inCAPI,166–167 columns()method,239 columnsvariable,106 command-lineprogram.SeeCLP commands deletecommand,92 explainqueryplancommand,123 insertcommand,87–91 multiplerows,90–91 onerow,87–89 setofrows,89–90 selectcommand,57–59 syntaxforSQLinSQLite,51–52 updatecommand,91–92 comma-separatedvalues(CSV),40 comments,syntaxforSQLinSQLite,53 commit()method,249 commitcommand,111,115,118,139,141, 143 commitline,141 commit_hook()function,inCAPI,178– 179 compactness,featuresofSQLite,9 compilation,ofpreparedqueries,161–162 compile()method,239 compiler,6 compileStatement()method,288 compoundqueries,81–83 con.commit()lines,230 concurrency,andWAL,319 Configurationdrop-downbox,26,28 configurationfunctions,forB-treemodule API,310 configurecommand,30 conflictresolution,andtransactions,112– 115 connect()function,227 connectingtoSQLite,usinglanguage extension forJava,238 forPerl,222 forPHP,248 forPython,227 forRuby,233 forTcl,244 Connection::create_aggregate()method, 231 connections,datastructuresofSQLite, 126–127 constraints ofcheck,99–100 offoreignkey,100–101 ofnotnull,98–99 327 ■ INDEX ofprimarykey,94–97 ofunique,93 contactsdatabase,93 contactstable,92,94,97 contacts.namecolumn,101 ControlPanel,19 convenience,featuresofSQLite,10–11 correlatedsubquery,80 :cosmoparameter,173 count()function,67,69,137,195 countaggregate,67–68,72 count(*)zResultfield,208 packagerequiredirective,244 packages forLinux,30–31 forMacOSX,30–31 forPOSIXsystems,30–31 pagecache,andwritetransactions,145– 146 page_sizepragma,128 pager,127 pages,anddatabasefileformat overflowpagesin,307–308 reuseof,304 parameters inCAPI,169–174 namedparameters,173 numberedparameters,172 Tclparameters,173–174 forlanguageextensions forPerl,224 forPython,229–230 forRuby,234–235 andSQLiteAPI,131–132 Pathentry,19 PATHenvironmentvariable,23 pBlockedparameter,193 PDO(PHPDataObjects),247–248 PDO_ATTR_TIMEOUTparameter,249 PDOStatementclass,248 PDOStatement::bindColumn()method, 250 PDOStatement::bindParam()method,249 pendingstate,forwritetransactions,142 ■ INDEX performance andlimitationsofSQLite,11–13 andWAL,321 Perl,languageextensionfor,221–226 aggregateswith,225–226 connectingto,222 installationof,221–222 parametersfor,224 queryprocessingwith,222–224 user-definedfunctionswith,224–225 perlsum()aggregate,225 perlsum.pmpackage,225 phonecolumn,54,93,98–99 phonevalue,93,99,101 PhoneGapframework,258,284 PHP,languageextensionfor,247–252 connectingto,248 installationof,248 queryprocessingwith,248–251 user-definedfunctionswith,251–252 PHPDataObjects(PDO),247–248 phpsumaggregate,251 Platformscomponent,Android,282 pNotifyArgpointer,192 portability,featuresofSQLite,8 POSIXsystems,30–32 binariesandpackages,30–31 compilingSQLitefromsource,31–32 powerconsumption,12 ppDbargument,155 ppStmtparameter,161 PRAGMAcommands,39 PRAGMAjournal_mode=WALsetting,319 pragmas,120–122 auto_vacuum,122 cachesize,120 databaseschema,120–121 integrity_check,122 synchronous,121–122 temp_store,122 temp_store_directory,122 PrecompiledBinariesForWindows section,21 --prefix=DIRoption,237 prepare()method,131–132,222,224,249 preparedqueries withCAPI,161–164 compilationof,161–162 executionof,162 finalizationof,163–164 executing,129–131 prerequisites forAndroiddevelopment,279–284 additionalcomponents,281–284 downloadingAndroidDeveloper Tools,280–281 downloadingAndroidSDKStarter Package,280 JDK(JavaDevelopmentKit),280 foriOSdevelopment,253–259 DeveloperProgrammembership, 254 downloadingiOSSDK,254–258 primarykeyconstraints,54,94–97 print_sql_result()function,187,201 .prompt[value]command,40 PropertyPagesdialogbox,26 publicboolean isDbLockedByOtherThreads() method,290 publicintgetVersion()method,290 publiclonggetMaximumSize()method, 290 publicstaticintreleaseMemory()method, 290 pUserDataargument,197–198 pysum()aggregate,137,231 Python,languageextensionfor,226–232 aggregateswith,231–232 337 ■ INDEX APSWasalternative,232 connectingto,227 installationof,226–227 parametersfor,229–230 queryprocessingwith,227–229 user-definedfunctionswith,231 pzTailparameter,164 ■Q queries,withSQLiteDatabaseclass,287– 288 query()method,239,248–249,287–288 queryingdatabases,55–86 compoundqueries,81–83 executingpreparedqueries,129–131 executingwrappedqueries,132–133 relationaloperations,55–56 subqueries,79–80 queryWithFactory()method,288 ■R raise()function,110 RANK()function,13 rawQuery()method,287–288,294 rawQueryWithFactory()method,288 RDBMS(relationaldatabasemanagement system),1 .readcommand,40 readtransactions,141 read_committedpragma,191 read_uncommittedpragma,151,191 readFoodsFromDatabasefunction,270 READMEfile,196 read-uncommittedisolationlevel,shared cachemode,191–192 read-uncommittedmode,151 realclass,102–103 338 recordfunctions,forB-treemoduleAPI, 310 records,anddatabasefileformat,304–305 recovery,issueswithWAL,321–322 recursivetriggers,12 referentialintegrity,92 regexppredicate,64 registeringinExtensionCAPI aggregates,205–206 functions,196–197 reindexcommand,119 relationaldatabasemanagementsystem (RDBMS),1 relationaloperations,queryingdatabases, 55–56 relationaloperators,62 releasecommand,112 reliability,featuresofSQLite,10 renameclause,55 renameoperation,77 RENAMETABLEcommand,12 replace()methods,289 replacecommand,114 resfolder,297 RESERVEDconnection,148 RESERVEDlock,140–141,144,148 RESERVEDstate,140–142,144–145,147– 148 reset()function,132,150–151 Resourcesfolder,263 restrictaction,101 resultpargument,159 resultppointer,159 reversecollation,101 REVOKEcommand,13 rightouterjoin,76 RIGHTOUTERJOINstatement,12 R.javafile,298 ■ INDEX rollback()method,249 rollbackcommand,111–112,139 rollbackresolution,113,115 rollback_hook()function,inCAPI,179 rootpagecolumn,123 Rowclass,239 ROW_NUMBER()function,13 rowidargument,180 rowidcolumn,96–97 rowidvalue,94–96 rows,andinsertcommand multiplerows,90–91 onerow,87–89 setofrows,89–90 rsyncutility,3 RTRIMcollation,138 Ruby,languageextensionfor,232–236 connectingto,233 installationof,232–233 parametersfor,234–235 queryprocessingwith,233–234 user-definedfunctionswith,236 ■S SAggCtxstruct,208 Samplescomponent,282 savepointcommand,112 .schema[tablename]command,38 .schemacommand,42,55 .schemafoodsshellcommand,88 schemainformation,administrationof databases,37–39 .schemashellcommand,55 schemaview,37,40 scope,fortransactions,111–112 SDKStarterPackage,prerequisitefor Androiddevelopment,280 SeinfeldAndroidapp,294–300 addingdatabasetoproject,296 creatingproject,295–296 linkingdataanduserinterface,298–299 queryingfoodstable,296–297 userinterfacefor,297–298 viewingapp,299–300 selectclause,57–59,65,67–68,70–71,79, 89 selectcommand,55–59,67,72,75,80,87 selectform,insertcommand,90 selecthello_newman()function,137 selectidclause,77 SELECTstatements,10–11,129,131,210 selectrow()function,222 select-stmtparameter,104 .separatorcommand,40 SETclause,92 setdefaultaction,101 setnullaction,101 set_authorizer()function,inCAPI,180– 189 setAttribute()method,PDOclass,249 setDistinct()method,293 setProjectionMap(Map columnMap)method,293 setTables()method,293 setTransactionSuccessful()method,289 setup.cfgfile,227 setup.exefile,28–29 sharedcachemode overview,151–152 threadingsupportinCAPI,190–193 read-uncommittedisolationlevel, 191–192 unlocknotification,192–193 SHAREDconnection,148 Sharedlibrary,31 SHAREDlocks,142,144,146–147,149–151 sharedobject(so),17 339 ■ INDEX SHAREDstate,140–142,144–145 shellmode,command-lineprogramin, 33–34 shell.cfile,26,28 shortdatatype,241 .showcommand,40 show_datatypespragma,242 simplicity,featuresofSQLite,9 sleep()function,177 so(sharedobject),17 sourceclause,78 sourcecode compilingonLinux,31–32 compilingonMacOSX,31–32 compilingonPOSIXsystems,31–32 compilingonWindows,22–25 Fossilsourcecontrol,23–25 stablesourcedistribution,22 SourceCodesection,22 spam_mother_in_law()function,147 sprintf()function,134 sqlargument,156,159 sqlcolumn,123 SQLforSQLite administration,118–124 attachingdatabases,118–119 cleaningdatabases,119 explainqueryplancommand,123 andpragmas,120–122 ofpragmas,122 sqlite_mastertable,123 aggregates,67 aliases,fortables,77–79 andambiguityofcolumnnames,77 caseexpression,83–84 compoundqueries,81–83 creatingdatabases,53–55 alteringtables,54–55 creatingtables,53–54 340 dataintegrity,92–104 domainintegrity,97–101 entityintegrity,93–97 indexes,106–108 storageclassesforSQLite,101–104 triggers,108–111 viewsinSQLite,104–106 deletecommand,92 distinctclause,72 exampledatabase,47–50 installation,48–49 runningexamples,49–50 functions,66 groupbyclause,67–71 indexes,106–108 andcollationsforcolumns,107 utilizationof,107–108 insertcommand,87–91 multiplerows,90–91 onerow,87–89 setofrows,89–90 joiningtables,72–77 crossjoins,75–76 innerjoins,74–75 naturaljoins,77 outerjoins,76 preferredsyntaxfor,77 limitclause,64 modifyingdata,87–92 nullinSQLite,84 orderbyclause,64–66 queryingdatabases,55–86 selectcommand,57–59 storageclassesfor,101–104 subqueries,79–80 syntaxfor,50–53 commands,51–52 comments,53 ■ INDEX identifiers,53 keywords,53 literals,52 transactions,111–118 andconflictresolution,112–115 anddeadlocks,116–117 andlocks,115–116 scopefor,111–112 typesof,117–118 triggers,108–111 errorhandlingwith,110 andupdatableviews,110–111 updatetriggers,109–110 updatecommand,91–92 viewsin,104–106 whereclause,59–64 binaryoperators,60–62 globoperator,64 likeoperator,63 logicaloperators,63 operators,60 values,60 SQLite foradministrators,3 fordevelopers,2–3 downloading,17–18 embeddeddatabase,1 historyof,3–4 toolsfor,45 whereused,4–5 SQLiteAPI,125–138 coreAPI,127–135 connectingtodatabase,128 anderrorhandling,133–134 executingpreparedqueries,129–131 executingwrappedqueries,132–133 formattingSQLstatements,134–135 andparameters,131–132 operationalcontrolwith,135 principaldatastructures,126–135 B-treeandpager,127 connectionsandstatements,126– 127 user-definedextensions aggregates,137 collations,138 functions,136–137 usingthreads,136 sqlitedirectory,33 sqlite_analyzerview,44 SQLITE_ATTACHevent,182 SQLITE_BUSYerror,118,133 SQLITE_BUSYvalue,146–148,151 sqlite_column_type()function,199 sqlite_complete()function,164 sqlite_create_funtion()function,64 SQLITE_CREATE_INDEXevent,181 SQLITE_CREATE_TABLEevent,181 SQLITE_CREATE_TEMP_INDEXevent, 181 SQLITE_CREATE_TEMP_TABLEevent,181 SQLITE_CREATE_TEMP_TRIGGERevent, 181 SQLITE_CREATE_TEMP_VIEWevent,181 SQLITE_CREATE_TRIGGERevent,181 SQLITE_CREATE_VIEWevent,181 SQLITE_DELETEevent,181 SQLITE_DENYconstant,180 SQLITE_DETACHevent,182 SQLITE_DONEvalue,129,151 SQLITE_DROP_INDEXevent,181 SQLITE_DROP_TABLEevent,181 SQLITE_DROP_TEMP_INDEXevent,181 SQLITE_DROP_TEMP_TABLEevent,181 SQLITE_DROP_TEMP_TRIGGERevent, 181 SQLITE_DROP_TEMP_VIEWevent,181 SQLITE_DROP_TRIGGERevent,181 341 ■ INDEX SQLITE_DROP_VIEWevent,181 SQLITE_ENABLE_COLUMN_METADATA directive,166 SQLITE_ENABLE_MEMORY_MANAGEME NTdirective,193 SQLITE_ERRORerror,133 SQLITE_FULLerror,95 SQLITE_IGNOREconstant,180,183 SQLITE_INSERTevent,181 SQLITE_LOCKEDvalue,151 sqlite_mastertable,107,123,186,188,192, 303–304 sqlite_masterview,38,44,135 SQLITE_NOMEMerror,208 SQLITE_OKconstant,180 SQLITE_OPEN_CREATEflag,154 SQLITE_OPEN_FULLMUTEXflag,155 SQLITE_OPEN_NOMUTEXflag,155 SQLITE_OPEN_PRIVATECACHEflag,155 SQLITE_OPEN_SHAREDCACHEflag,155 SQLITE_PRAGMAevent,181 SQLITE_READevent,180–181,187 SQLITE_RESULTvalue,151 sqlite_result_xxx()functions,202 SQLITE_ROWvalue,129 SQLITE_SCHEMAcondition,178,189 SQLITE_SCHEMAerrors,162,178,192 SQLITE_SCHEMAevent,189 SQLITE_SELECTevent,181,187 sqlite_sequencetable,95 SQLITE_TRANSACTIONevent,182 SQLITE_UPDATEevent,180,182 sqlite3command,244 sqlite3handle,126,128,132 sqlite3package,244 sqlite3structure,248 sqlite3_aggregate_context()function,198, 207–208 sqlite3_analyzertool,145 342 sqlite3_bind()function,176 sqlite3_bind_double()function,170 sqlite3_bind_parameter_index()function, 173 sqlite3_bind_xxx()functions,167,170,202 sqlite3_busy_handler()function,176–177 sqlite3_busy_timeout()function,147,176– 177 sqlite3_changes()function,159 sqlite3_close()function,155,192,272 sqlite3_collation_needed()function,216 sqlite3_column_blob()function,167 sqlite3_column_bytes()function,167 sqlite3_column_count()function,165 sqlite3_column_decltype()function,165– 166 sqlite3_column_name()function,165 sqlite3_column_origin_name()function, 166 sqlite3_column_text()method,272 sqlite3_column_type()function,165 sqlite3_column_xxx()functions,161,166, 199,203,272 sqlite3_commit_hook()function,135, 178–179 sqlite3_complete()function,164 sqlite3_create_collation()function,138 sqlite3_create_collation_v2()function,213 sqlite3_create_function()function,136, 196–198,205,213 sqlite3_data_count()function,165 sqlite3_db_handle()function,169 sqlite3_errcode()function,134 sqlite3_errmsg()function,134,162,169, 174 sqlite3_exec()function,132,155–156,158– 159,161,164,189–190,248 sqlite3_finalize()function,129,161,163, 171,224,272 sqlite3_free()function,157,203 ■ INDEX sqlite3_free_table()function,159 sqlite3_free(errmsg)function,157 sqlite3_get_table()function,132–133,159– 161,164,189 sqlite3_interrupt()function,189 sqlite3_last_insert_rowid()function,159 sqlite3_malloc()function,159,202 sqlite3_mprintf()function,134,171,203 sqlite3_open()function,128,154 sqlite3_open_v2()function,154–155,174, 271 sqlite3_open_v2(),sqlite3_prepare() method,263 sqlite3_open16()function,154 sqlite3_prepare()function,163–164,169– 170,172–173,178,228 sqlite3_prepare()_v2function,131 sqlite3_prepare_v2()function,129,131, 161–162,164,174,202,223 sqlite3_progress_handler()function,189, 237 sqlite3_release_memory()function,193 sqlite3_reset()function,132,161,163,171, 229,235 sqlite3_result_error()function,203 sqlite3_result_error_nomem()function, 208 sqlite3_result_text()function,202–203, 208 sqlite3_result_value()function,203 sqlite3_result_xxx()function,203,208 sqlite3_rollback_hook()function,135,179 sqlite3_set_authorizer()function,135, 176,180,188,237 sqlite3_soft_heap_limit()function,193 sqlite3_step()function,129,161–162,170– 171,177–178,192,223,228 sqlite3_stmthandle,127,129,227 sqlite3_stmtstructure,161,170,233–234, 248 sqlite3_trace()function,178,201,237 sqlite3_unlock_notify()function,192 sqlite3_update_hook()function,135,179 sqlite3_user_data()function,198 sqlite3_value_blob()function,199 sqlite3_value_bytes()function,199 sqlite3_value_text()function,208 sqlite3_value_type()function,199 sqlite3_value_xxx()functions,198–199 sqlite3_vmprintf()method,240 sqlite3_wal_autocheckpoint()function, 320–321 sqlite3_wal_checkpoint()function,320– 321 sqlite3_wal_hook()function,320 sqlite3BtreeBeginStmtroutine,309 sqlite3BtreeBeginTransroutine,308 sqlite3BtreeClearTableroutine,309 sqlite3BtreeCloseroutine,308 sqlite3BtreeCloseCursorfunction,309 sqlite3BtreeCommitroutine,308 sqlite3BtreeCommitStmtroutine,309 sqlite3BtreeCreateTableroutine,309 sqlite3BtreeCursorfunction,309 sqlite3BtreeDatafunction,310 sqlite3BtreeDataSizefunction,310 sqlite3BtreeDeletefunction,310 sqlite3BtreeDropTableroutine,309 sqlite3BtreeFirstfunction,309 sqlite3BtreeGetAutoVacuumfunction,310 sqlite3BtreeGetPageSizefunction,310 sqlite3BtreeInsertfunction,310 sqlite3BtreeKeyfunction,310 sqlite3BtreeKeySizefunction,310 sqlite3BtreeLastfunction,309 sqlite3BtreeMovetofunction,309 sqlite3BtreeNextfunction,309 sqlite3BtreeOpenroutine,308 sqlite3BtreePreviousfunction,309 sqlite3BtreeRollbackroutine,309 343 ■ INDEX sqlite3BtreeRollbackStmtroutine,309 sqlite3BtreeSetAutoVacuumfunction,310 sqlite3BtreeSetBusyHandlerfunction,310 sqlite3BtreeSetCacheSizefunction,310 sqlite3BtreeSetPageSizefunction,310 sqlite3BtreeSetSafetyLevelfunction,310 sqlite3.deffile,21,26 sqlite3.dllfile,21 sqlite3.exefile,19–20,30 sqlite3.liblibrary,21–22,28 SQLite.Callbackinterface,237,239 sqliteCreateAggregate()method,251 sqliteCreateFunction()method,251 SQLiteDatabaseclass,286–290 conveniencemethodsfor,288–289 executingquerieswith,287–288 implementing,290–292 openingandclosingdatabaseswith, 286–287 transactionswith,289 usefulmethodsfor,290 SQLiteDatabase::compile()method,238 SQLite.Database.create_function() function,241 SQLiteDatabase.CursorFactoryclass,285 SQLite.Database::exec()method,240 SQLite.Database.function_type()function, 241 SQLiteDatabase::open()method,238 sqlite.fossilfile,23 SQLite.Functioninterface,240–241 sqlite.jarfile,237,241 SQLite.JDBCDriverclass,241 SQLiteJDBCExample.javafile,242 SQLiteJNIExample.javafile,238 SQLitemantool,45 SQLiteManagertool,46 SQLiteOpenHelper()method,287 344 SQLiteOpenHelperclass,forAndroid development,285–286,290–292 SQLiteQueryBuilderclass,forAndroid development,293–294 sql.sqlfile,49 srcfolder,25 stablesourcedistribution,compiling sourcecodeonWindows,22 stackableflagsparameter,287 startup,accessingdatabaseupon,269–272 Statement::bind_params()method,234 Statement.close()method,234 statements,datastructuresofSQLite,126– 127 Staticallylinkedcommand-lineprogram, 31 step()function,131,137,146–148,151, 198,231,241 storageclasses forSQLite,101–104 andtypeaffinity,314 andtypeconversions,315–318 str_agg()function,206–207,209 str_agg_finalize()function,206–208 str_agg_step()function,206–208 strcat()function,206 subqueries,79–80 subselects,79 sum()function,67,137,195 sum_agg()finalizefunction,208 Synapticutility,31 synchronouspragma,121–122,143 syncs()function,310 syntaxforSQLinSQLite,50–53 commands,51–52 comments,53 identifiers,53 keywords,53 literals,52 SystemVariableslist,19 ■ INDEX ■T tparameter,266 tablefunctions,forB-treemoduleAPI,309 tableparameter,293 table_infopragma,121,242 table_nameattribute,54 table_namevariable,106 table_name.column_namenotation,73 tables aliasesfor,77–79 altering,54–55 creating,53–54 joining,72–77 crossjoins,75–76 innerjoins,74–75 naturaljoins,77 outerjoins,76 preferredsyntaxfor,77 .tables[pattern]command,37 tablesvariable,58 TakeOffGWnetworkinstaller,28–29 TakeOffGWpackage,28–30 tar-xzvfsqlite-amalgamation3.6.23.1.tar.gzcommand,30 Tcl languageextensionfor,243–247 connectingto,244 installationof,243–244 queryprocessingwith,244–246 user-definedfunctionswith,247 parametersinCAPI,173–174 TclExtensionArchitecture(TEA),18 tclsqlite.cfile,26 TEA(TclExtensionArchitecture),18 tempdatabase,118 tempkeyword,54 temp_storepragma,122,131 temporarykeyword,54 temporarytable,54 testtable,36–38,40–42,114 test_idxindex,38 test2table,41 test2.dbdatabase,42 test3.dbdatabase,42 test.csvfile,41 test.dbdatabase,35,42 test.dbfile,36,39,43 test.sqlfile,42–43,49 textclass,102–103,196 TextFieldelements,267 threading withSQLiteAPI,136 supportinCAPI,190–193 andmemorymanagement,193 sharedcachemode,190–193 THREADSAFEpreprocessorflag,21 three-valuelogic,85 /tmpfolder,33 tokens,52 Transactionmethod,246 transactions,111–118,138–149 andconflictresolution,112–115 anddeadlocks,116–117 andexclusivestate,145 lifecyclesfor,138–139 lockstates,139–141 andlocks,115–116 readtransactions,141 scopefor,111–112 sizingpagecache,145–146 withSQLiteDatabaseclass,289 typesof,117–118 usingbusyhandler,146–147 writetransactions,141–145 andautocommit,143–145 exclusivestate,142–143 andpagecache,145 pendingstate,142 345 ■ INDEX reservedstate,141–142 triggers,108–111 errorhandlingwith,110 andupdatableviews,110–111 updatetriggers,109–110 tristatelogic,85 typeaffinity,313–315 andcolumntypes,313 exampleof,314–315 andstorageclasses,314 typeconversions,andstorageclasses,315– 318 type_idattribute,48,65,68,71 type_idcolumn,72,76,87–88,100 type_idgroup,68 type_idvalues,68,71–72,83,89 typeof()function,102,317 typeof(b)column,315 types()method,239 typessubquery,80 updateoperation,135,179–180 UPDATEstatement,10–12,110,112 updatetriggers,109–110 update_hook()function,inCAPI,179–180 update_listcolumnassignment,91 upper()function,66 UPSERTstatement,10 USBDriverforWindowscomponent,282 userinterface,linkingdatawith,298–299 UserInterfacesgroup,266 user-definedfunctions,withlanguage extensions forJava,240–241 forPerl,224–225 forPHP,251–252 forPython,231 forRuby,236 forTcl,247 utilities,8 ■U vacuumcommand,119,122 VACUUMoperation,189 valueargument,199 valuefield,36,41 value_listvariable,87 values forExtensionCAPI,198–199 forwhereclause,60 varchar(100)column,9 VDBE(virtualdatabaseengine),6,161 Venndiagram,74 versionparameter,285 views,inSQLite,104–106 virtualdatabaseengine(VDBE),6,161 VM(virtualmachine),6–7,238 VM::step()method,239 voidmethod,288 UIViewControllerclass,266 unaryoperators,60 unionalloperation,81 unionkeyword,81 unionoperation,81 UNIONstatement,12 uniqueconstraints,54,91–93,96–97,106, 112–113,115 uniquekeyword,106 unlocknotification,sharedcachemode, 192–193 UNLOCKEDstate,140–144 UnlockFile()function,148 updatableviews,andtriggers,110–111 updatecommand,91–92,98,108,115, 141–142,145,147,149 updatefilter,183 346 ■V ■ INDEX ■W WAL(WriteAheadLog),318–322 activationof,319 advantagesanddisadvantagesof,320 andcheckpoints,318 andconcurrency,319 configurationof,320 operationalissueswith,321–322 overview,318 whencondition,83–84 whereclause,59–64 binaryoperators,60–62 globoperator,64 likeoperator,63 logicaloperators,63 operators,60 values,60 wherekeyword,57 wherepredicate,84 whileloop,149 .widthoption,49 Win32ApplicationWizard,28 Win32Projecttemplate,27 Windows,18–30 buildingdynamicallylinkedSQLite clientwithVisualC++,27–28 buildingSQLiteDLLwithMicrosoft VisualC++,25–27 buildingSQLitewithMinGW,28–30 compilingSQLitesourcecodeon Windows,22–25 installingcommand-lineprogram,18– 21 installingSQLiteDLL,21–22 Windowscommandshell,19 \windows\system32folder,19 --with-jardir=DIRoption,237 wrappedqueries,executing,132–133 wrapperfunctions,inCAPI,153–160 forconnectinganddisconnecting,153– 155 exec()function,155–159 get_table()function,159–160 WriteAheadLog.SeeWAL writetransactions,141–145 andautocommit,143–145 exclusivestate,142–143 andpagecache,145 pendingstate,142 reservedstate,141–142 Write-AheadLogmode,192 ■X xCallbackfunction,179 xcode_3.2.4_and_ios_sdk_4.1.dmgfile,254 xCompareargument,213 xFinalargument,197,206 xFuncargument,197,206 xNotifyfunction,192 xStepargument,197,206 ■Y -shmfile,320 -walfile,320 ■Z zeroconfiguration,featuresofSQLite,8 zFunctionNameargument,197 zVfsparameter,155 347
Our partners will collect data and use cookies for ad personalization and measurement.
Learn how we and our ad partner Google, collect and use data .
Agree Cookies