pgsql.c 200 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 5 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997-2016 The PHP Group |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.01 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.php.net/license/3_01.txt |
  11. | If you did not receive a copy of the PHP license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@php.net so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. | Authors: Zeev Suraski <zeev@zend.com> |
  16. | Jouni Ahto <jouni.ahto@exdec.fi> |
  17. | Yasuo Ohgaki <yohgaki@php.net> |
  18. | Youichi Iwakiri <yiwakiri@st.rim.or.jp> (pg_copy_*) |
  19. | Chris Kings-Lynne <chriskl@php.net> (v3 protocol) |
  20. +----------------------------------------------------------------------+
  21. */
  22. /* $Id$ */
  23. #include <stdlib.h>
  24. #define PHP_PGSQL_PRIVATE 1
  25. #ifdef HAVE_CONFIG_H
  26. #include "config.h"
  27. #endif
  28. #define SMART_STR_PREALLOC 512
  29. #include "php.h"
  30. #include "php_ini.h"
  31. #include "ext/standard/php_standard.h"
  32. #include "ext/standard/php_smart_str.h"
  33. #include "ext/ereg/php_regex.h"
  34. #ifdef PHP_WIN32
  35. # include "win32/time.h"
  36. #endif
  37. #undef PACKAGE_BUGREPORT
  38. #undef PACKAGE_NAME
  39. #undef PACKAGE_STRING
  40. #undef PACKAGE_TARNAME
  41. #undef PACKAGE_VERSION
  42. #include "php_pgsql.h"
  43. #include "php_globals.h"
  44. #include "zend_exceptions.h"
  45. #if HAVE_PGSQL
  46. #ifndef InvalidOid
  47. #define InvalidOid ((Oid) 0)
  48. #endif
  49. #define PGSQL_ASSOC 1<<0
  50. #define PGSQL_NUM 1<<1
  51. #define PGSQL_BOTH (PGSQL_ASSOC|PGSQL_NUM)
  52. #define PGSQL_STATUS_LONG 1
  53. #define PGSQL_STATUS_STRING 2
  54. #define PGSQL_MAX_LENGTH_OF_LONG 30
  55. #define PGSQL_MAX_LENGTH_OF_DOUBLE 60
  56. #if LONG_MAX < UINT_MAX
  57. #define PGSQL_RETURN_OID(oid) do { \
  58. if (oid > LONG_MAX) { \
  59. smart_str s = {0}; \
  60. smart_str_append_unsigned(&s, oid); \
  61. smart_str_0(&s); \
  62. RETURN_STRINGL(s.c, s.len, 0); \
  63. } \
  64. RETURN_LONG((long)oid); \
  65. } while(0)
  66. #else
  67. #define PGSQL_RETURN_OID(oid) (RETURN_LONG((long)oid))
  68. #endif
  69. #if HAVE_PQSETNONBLOCKING
  70. #define PQ_SETNONBLOCKING(pg_link, flag) PQsetnonblocking(pg_link, flag)
  71. #else
  72. #define PQ_SETNONBLOCKING(pg_link, flag) 0
  73. #endif
  74. #define CHECK_DEFAULT_LINK(x) if ((x) == -1) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "No PostgreSQL link opened yet"); }
  75. #ifndef HAVE_PQFREEMEM
  76. #define PQfreemem free
  77. #endif
  78. ZEND_DECLARE_MODULE_GLOBALS(pgsql)
  79. static PHP_GINIT_FUNCTION(pgsql);
  80. /* {{{ arginfo */
  81. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_connect, 0, 0, 1)
  82. ZEND_ARG_INFO(0, connection_string)
  83. ZEND_ARG_INFO(0, connect_type)
  84. ZEND_ARG_INFO(0, host)
  85. ZEND_ARG_INFO(0, port)
  86. ZEND_ARG_INFO(0, options)
  87. ZEND_ARG_INFO(0, tty)
  88. ZEND_ARG_INFO(0, database)
  89. ZEND_END_ARG_INFO()
  90. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_pconnect, 0, 0, 1)
  91. ZEND_ARG_INFO(0, connection_string)
  92. ZEND_ARG_INFO(0, host)
  93. ZEND_ARG_INFO(0, port)
  94. ZEND_ARG_INFO(0, options)
  95. ZEND_ARG_INFO(0, tty)
  96. ZEND_ARG_INFO(0, database)
  97. ZEND_END_ARG_INFO()
  98. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_connect_poll, 0, 0, 0)
  99. ZEND_ARG_INFO(0, connection)
  100. ZEND_END_ARG_INFO()
  101. #if HAVE_PQPARAMETERSTATUS
  102. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_parameter_status, 0, 0, 1)
  103. ZEND_ARG_INFO(0, connection)
  104. ZEND_ARG_INFO(0, param_name)
  105. ZEND_END_ARG_INFO()
  106. #endif
  107. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_close, 0, 0, 0)
  108. ZEND_ARG_INFO(0, connection)
  109. ZEND_END_ARG_INFO()
  110. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_dbname, 0, 0, 0)
  111. ZEND_ARG_INFO(0, connection)
  112. ZEND_END_ARG_INFO()
  113. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_last_error, 0, 0, 0)
  114. ZEND_ARG_INFO(0, connection)
  115. ZEND_END_ARG_INFO()
  116. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_options, 0, 0, 0)
  117. ZEND_ARG_INFO(0, connection)
  118. ZEND_END_ARG_INFO()
  119. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_port, 0, 0, 0)
  120. ZEND_ARG_INFO(0, connection)
  121. ZEND_END_ARG_INFO()
  122. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_tty, 0, 0, 0)
  123. ZEND_ARG_INFO(0, connection)
  124. ZEND_END_ARG_INFO()
  125. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_host, 0, 0, 0)
  126. ZEND_ARG_INFO(0, connection)
  127. ZEND_END_ARG_INFO()
  128. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_version, 0, 0, 0)
  129. ZEND_ARG_INFO(0, connection)
  130. ZEND_END_ARG_INFO()
  131. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_ping, 0, 0, 0)
  132. ZEND_ARG_INFO(0, connection)
  133. ZEND_END_ARG_INFO()
  134. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_query, 0, 0, 0)
  135. ZEND_ARG_INFO(0, connection)
  136. ZEND_ARG_INFO(0, query)
  137. ZEND_END_ARG_INFO()
  138. #if HAVE_PQEXECPARAMS
  139. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_query_params, 0, 0, 0)
  140. ZEND_ARG_INFO(0, connection)
  141. ZEND_ARG_INFO(0, query)
  142. ZEND_ARG_INFO(0, params)
  143. ZEND_END_ARG_INFO()
  144. #endif
  145. #if HAVE_PQPREPARE
  146. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_prepare, 0, 0, 0)
  147. ZEND_ARG_INFO(0, connection)
  148. ZEND_ARG_INFO(0, stmtname)
  149. ZEND_ARG_INFO(0, query)
  150. ZEND_END_ARG_INFO()
  151. #endif
  152. #if HAVE_PQEXECPREPARED
  153. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_execute, 0, 0, 0)
  154. ZEND_ARG_INFO(0, connection)
  155. ZEND_ARG_INFO(0, stmtname)
  156. ZEND_ARG_INFO(0, params)
  157. ZEND_END_ARG_INFO()
  158. #endif
  159. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_num_rows, 0, 0, 1)
  160. ZEND_ARG_INFO(0, result)
  161. ZEND_END_ARG_INFO()
  162. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_num_fields, 0, 0, 1)
  163. ZEND_ARG_INFO(0, result)
  164. ZEND_END_ARG_INFO()
  165. #if HAVE_PQCMDTUPLES
  166. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_affected_rows, 0, 0, 1)
  167. ZEND_ARG_INFO(0, result)
  168. ZEND_END_ARG_INFO()
  169. #endif
  170. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_last_notice, 0, 0, 1)
  171. ZEND_ARG_INFO(0, connection)
  172. ZEND_END_ARG_INFO()
  173. #ifdef HAVE_PQFTABLE
  174. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_table, 0, 0, 2)
  175. ZEND_ARG_INFO(0, result)
  176. ZEND_ARG_INFO(0, field_number)
  177. ZEND_ARG_INFO(0, oid_only)
  178. ZEND_END_ARG_INFO()
  179. #endif
  180. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_name, 0, 0, 2)
  181. ZEND_ARG_INFO(0, result)
  182. ZEND_ARG_INFO(0, field_number)
  183. ZEND_END_ARG_INFO()
  184. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_size, 0, 0, 2)
  185. ZEND_ARG_INFO(0, result)
  186. ZEND_ARG_INFO(0, field_number)
  187. ZEND_END_ARG_INFO()
  188. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_type, 0, 0, 2)
  189. ZEND_ARG_INFO(0, result)
  190. ZEND_ARG_INFO(0, field_number)
  191. ZEND_END_ARG_INFO()
  192. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_type_oid, 0, 0, 2)
  193. ZEND_ARG_INFO(0, result)
  194. ZEND_ARG_INFO(0, field_number)
  195. ZEND_END_ARG_INFO()
  196. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_num, 0, 0, 2)
  197. ZEND_ARG_INFO(0, result)
  198. ZEND_ARG_INFO(0, field_name)
  199. ZEND_END_ARG_INFO()
  200. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_fetch_result, 0, 0, 1)
  201. ZEND_ARG_INFO(0, result)
  202. ZEND_ARG_INFO(0, row_number)
  203. ZEND_ARG_INFO(0, field_name)
  204. ZEND_END_ARG_INFO()
  205. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_fetch_row, 0, 0, 1)
  206. ZEND_ARG_INFO(0, result)
  207. ZEND_ARG_INFO(0, row)
  208. ZEND_ARG_INFO(0, result_type)
  209. ZEND_END_ARG_INFO()
  210. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_fetch_assoc, 0, 0, 1)
  211. ZEND_ARG_INFO(0, result)
  212. ZEND_ARG_INFO(0, row)
  213. ZEND_END_ARG_INFO()
  214. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_fetch_array, 0, 0, 1)
  215. ZEND_ARG_INFO(0, result)
  216. ZEND_ARG_INFO(0, row)
  217. ZEND_ARG_INFO(0, result_type)
  218. ZEND_END_ARG_INFO()
  219. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_fetch_object, 0, 0, 1)
  220. ZEND_ARG_INFO(0, result)
  221. ZEND_ARG_INFO(0, row)
  222. ZEND_ARG_INFO(0, class_name)
  223. ZEND_ARG_INFO(0, l)
  224. ZEND_ARG_INFO(0, ctor_params)
  225. ZEND_END_ARG_INFO()
  226. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_fetch_all, 0, 0, 1)
  227. ZEND_ARG_INFO(0, result)
  228. ZEND_END_ARG_INFO()
  229. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_fetch_all_columns, 0, 0, 1)
  230. ZEND_ARG_INFO(0, result)
  231. ZEND_ARG_INFO(0, column_number)
  232. ZEND_END_ARG_INFO()
  233. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_result_seek, 0, 0, 2)
  234. ZEND_ARG_INFO(0, result)
  235. ZEND_ARG_INFO(0, offset)
  236. ZEND_END_ARG_INFO()
  237. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_prtlen, 0, 0, 1)
  238. ZEND_ARG_INFO(0, result)
  239. ZEND_ARG_INFO(0, row)
  240. ZEND_ARG_INFO(0, field_name_or_number)
  241. ZEND_END_ARG_INFO()
  242. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_is_null, 0, 0, 1)
  243. ZEND_ARG_INFO(0, result)
  244. ZEND_ARG_INFO(0, row)
  245. ZEND_ARG_INFO(0, field_name_or_number)
  246. ZEND_END_ARG_INFO()
  247. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_free_result, 0, 0, 1)
  248. ZEND_ARG_INFO(0, result)
  249. ZEND_END_ARG_INFO()
  250. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_last_oid, 0, 0, 1)
  251. ZEND_ARG_INFO(0, result)
  252. ZEND_END_ARG_INFO()
  253. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_trace, 0, 0, 1)
  254. ZEND_ARG_INFO(0, filename)
  255. ZEND_ARG_INFO(0, mode)
  256. ZEND_ARG_INFO(0, connection)
  257. ZEND_END_ARG_INFO()
  258. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_untrace, 0, 0, 0)
  259. ZEND_ARG_INFO(0, connection)
  260. ZEND_END_ARG_INFO()
  261. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_create, 0, 0, 0)
  262. ZEND_ARG_INFO(0, connection)
  263. ZEND_ARG_INFO(0, large_object_id)
  264. ZEND_END_ARG_INFO()
  265. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_unlink, 0, 0, 0)
  266. ZEND_ARG_INFO(0, connection)
  267. ZEND_ARG_INFO(0, large_object_oid)
  268. ZEND_END_ARG_INFO()
  269. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_open, 0, 0, 0)
  270. ZEND_ARG_INFO(0, connection)
  271. ZEND_ARG_INFO(0, large_object_oid)
  272. ZEND_ARG_INFO(0, mode)
  273. ZEND_END_ARG_INFO()
  274. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_close, 0, 0, 1)
  275. ZEND_ARG_INFO(0, large_object)
  276. ZEND_END_ARG_INFO()
  277. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_read, 0, 0, 1)
  278. ZEND_ARG_INFO(0, large_object)
  279. ZEND_ARG_INFO(0, len)
  280. ZEND_END_ARG_INFO()
  281. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_write, 0, 0, 2)
  282. ZEND_ARG_INFO(0, large_object)
  283. ZEND_ARG_INFO(0, buf)
  284. ZEND_ARG_INFO(0, len)
  285. ZEND_END_ARG_INFO()
  286. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_read_all, 0, 0, 1)
  287. ZEND_ARG_INFO(0, large_object)
  288. ZEND_END_ARG_INFO()
  289. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_import, 0, 0, 0)
  290. ZEND_ARG_INFO(0, connection)
  291. ZEND_ARG_INFO(0, filename)
  292. ZEND_ARG_INFO(0, large_object_oid)
  293. ZEND_END_ARG_INFO()
  294. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_export, 0, 0, 0)
  295. ZEND_ARG_INFO(0, connection)
  296. ZEND_ARG_INFO(0, objoid)
  297. ZEND_ARG_INFO(0, filename)
  298. ZEND_END_ARG_INFO()
  299. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_seek, 0, 0, 2)
  300. ZEND_ARG_INFO(0, large_object)
  301. ZEND_ARG_INFO(0, offset)
  302. ZEND_ARG_INFO(0, whence)
  303. ZEND_END_ARG_INFO()
  304. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_tell, 0, 0, 1)
  305. ZEND_ARG_INFO(0, large_object)
  306. ZEND_END_ARG_INFO()
  307. #if HAVE_PG_LO_TRUNCATE
  308. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_truncate, 0, 0, 1)
  309. ZEND_ARG_INFO(0, large_object)
  310. ZEND_ARG_INFO(0, size)
  311. ZEND_END_ARG_INFO()
  312. #endif
  313. #if HAVE_PQSETERRORVERBOSITY
  314. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_set_error_verbosity, 0, 0, 0)
  315. ZEND_ARG_INFO(0, connection)
  316. ZEND_ARG_INFO(0, verbosity)
  317. ZEND_END_ARG_INFO()
  318. #endif
  319. #if HAVE_PQCLIENTENCODING
  320. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_set_client_encoding, 0, 0, 0)
  321. ZEND_ARG_INFO(0, connection)
  322. ZEND_ARG_INFO(0, encoding)
  323. ZEND_END_ARG_INFO()
  324. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_client_encoding, 0, 0, 0)
  325. ZEND_ARG_INFO(0, connection)
  326. ZEND_END_ARG_INFO()
  327. #endif
  328. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_end_copy, 0, 0, 0)
  329. ZEND_ARG_INFO(0, connection)
  330. ZEND_END_ARG_INFO()
  331. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_put_line, 0, 0, 0)
  332. ZEND_ARG_INFO(0, connection)
  333. ZEND_ARG_INFO(0, query)
  334. ZEND_END_ARG_INFO()
  335. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_copy_to, 0, 0, 2)
  336. ZEND_ARG_INFO(0, connection)
  337. ZEND_ARG_INFO(0, table_name)
  338. ZEND_ARG_INFO(0, delimiter)
  339. ZEND_ARG_INFO(0, null_as)
  340. ZEND_END_ARG_INFO()
  341. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_copy_from, 0, 0, 3)
  342. ZEND_ARG_INFO(0, connection)
  343. ZEND_ARG_INFO(0, table_name)
  344. ZEND_ARG_INFO(0, rows)
  345. ZEND_ARG_INFO(0, delimiter)
  346. ZEND_ARG_INFO(0, null_as)
  347. ZEND_END_ARG_INFO()
  348. #if HAVE_PQESCAPE
  349. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_escape_string, 0, 0, 0)
  350. ZEND_ARG_INFO(0, connection)
  351. ZEND_ARG_INFO(0, data)
  352. ZEND_END_ARG_INFO()
  353. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_escape_bytea, 0, 0, 0)
  354. ZEND_ARG_INFO(0, connection)
  355. ZEND_ARG_INFO(0, data)
  356. ZEND_END_ARG_INFO()
  357. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_unescape_bytea, 0, 0, 1)
  358. ZEND_ARG_INFO(0, data)
  359. ZEND_END_ARG_INFO()
  360. #endif
  361. #if HAVE_PQESCAPE
  362. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_escape_literal, 0, 0, 0)
  363. ZEND_ARG_INFO(0, connection)
  364. ZEND_ARG_INFO(0, data)
  365. ZEND_END_ARG_INFO()
  366. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_escape_identifier, 0, 0, 0)
  367. ZEND_ARG_INFO(0, connection)
  368. ZEND_ARG_INFO(0, data)
  369. ZEND_END_ARG_INFO()
  370. #endif
  371. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_result_error, 0, 0, 1)
  372. ZEND_ARG_INFO(0, result)
  373. ZEND_END_ARG_INFO()
  374. #if HAVE_PQRESULTERRORFIELD
  375. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_result_error_field, 0, 0, 2)
  376. ZEND_ARG_INFO(0, result)
  377. ZEND_ARG_INFO(0, fieldcode)
  378. ZEND_END_ARG_INFO()
  379. #endif
  380. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_connection_status, 0, 0, 1)
  381. ZEND_ARG_INFO(0, connection)
  382. ZEND_END_ARG_INFO()
  383. #if HAVE_PGTRANSACTIONSTATUS
  384. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_transaction_status, 0, 0, 1)
  385. ZEND_ARG_INFO(0, connection)
  386. ZEND_END_ARG_INFO()
  387. #endif
  388. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_connection_reset, 0, 0, 1)
  389. ZEND_ARG_INFO(0, connection)
  390. ZEND_END_ARG_INFO()
  391. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_cancel_query, 0, 0, 1)
  392. ZEND_ARG_INFO(0, connection)
  393. ZEND_END_ARG_INFO()
  394. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_connection_busy, 0, 0, 1)
  395. ZEND_ARG_INFO(0, connection)
  396. ZEND_END_ARG_INFO()
  397. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_send_query, 0, 0, 2)
  398. ZEND_ARG_INFO(0, connection)
  399. ZEND_ARG_INFO(0, query)
  400. ZEND_END_ARG_INFO()
  401. #if HAVE_PQSENDQUERYPARAMS
  402. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_send_query_params, 0, 0, 3)
  403. ZEND_ARG_INFO(0, connection)
  404. ZEND_ARG_INFO(0, query)
  405. ZEND_ARG_INFO(0, params)
  406. ZEND_END_ARG_INFO()
  407. #endif
  408. #if HAVE_PQSENDPREPARE
  409. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_send_prepare, 0, 0, 3)
  410. ZEND_ARG_INFO(0, connection)
  411. ZEND_ARG_INFO(0, stmtname)
  412. ZEND_ARG_INFO(0, query)
  413. ZEND_END_ARG_INFO()
  414. #endif
  415. #if HAVE_PQSENDQUERYPREPARED
  416. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_send_execute, 0, 0, 3)
  417. ZEND_ARG_INFO(0, connection)
  418. ZEND_ARG_INFO(0, stmtname)
  419. ZEND_ARG_INFO(0, params)
  420. ZEND_END_ARG_INFO()
  421. #endif
  422. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_get_result, 0, 0, 1)
  423. ZEND_ARG_INFO(0, connection)
  424. ZEND_END_ARG_INFO()
  425. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_result_status, 0, 0, 1)
  426. ZEND_ARG_INFO(0, result)
  427. ZEND_ARG_INFO(0, result_type)
  428. ZEND_END_ARG_INFO()
  429. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_get_notify, 0, 0, 0)
  430. ZEND_ARG_INFO(0, connection)
  431. ZEND_ARG_INFO(0, e)
  432. ZEND_END_ARG_INFO()
  433. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_get_pid, 0, 0, 0)
  434. ZEND_ARG_INFO(0, connection)
  435. ZEND_END_ARG_INFO()
  436. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_socket, 0, 0, 1)
  437. ZEND_ARG_INFO(0, connection)
  438. ZEND_END_ARG_INFO()
  439. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_consume_input, 0, 0, 1)
  440. ZEND_ARG_INFO(0, connection)
  441. ZEND_END_ARG_INFO()
  442. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_flush, 0, 0, 1)
  443. ZEND_ARG_INFO(0, connection)
  444. ZEND_END_ARG_INFO()
  445. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_meta_data, 0, 0, 2)
  446. ZEND_ARG_INFO(0, db)
  447. ZEND_ARG_INFO(0, table)
  448. ZEND_END_ARG_INFO()
  449. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_convert, 0, 0, 3)
  450. ZEND_ARG_INFO(0, db)
  451. ZEND_ARG_INFO(0, table)
  452. ZEND_ARG_INFO(0, values)
  453. ZEND_ARG_INFO(0, options)
  454. ZEND_END_ARG_INFO()
  455. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_insert, 0, 0, 3)
  456. ZEND_ARG_INFO(0, db)
  457. ZEND_ARG_INFO(0, table)
  458. ZEND_ARG_INFO(0, values)
  459. ZEND_ARG_INFO(0, options)
  460. ZEND_END_ARG_INFO()
  461. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_update, 0, 0, 4)
  462. ZEND_ARG_INFO(0, db)
  463. ZEND_ARG_INFO(0, table)
  464. ZEND_ARG_INFO(0, fields)
  465. ZEND_ARG_INFO(0, ids)
  466. ZEND_ARG_INFO(0, options)
  467. ZEND_END_ARG_INFO()
  468. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_delete, 0, 0, 3)
  469. ZEND_ARG_INFO(0, db)
  470. ZEND_ARG_INFO(0, table)
  471. ZEND_ARG_INFO(0, ids)
  472. ZEND_ARG_INFO(0, options)
  473. ZEND_END_ARG_INFO()
  474. ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_select, 0, 0, 3)
  475. ZEND_ARG_INFO(0, db)
  476. ZEND_ARG_INFO(0, table)
  477. ZEND_ARG_INFO(0, ids)
  478. ZEND_ARG_INFO(0, options)
  479. ZEND_END_ARG_INFO()
  480. /* }}} */
  481. /* {{{ pgsql_functions[]
  482. */
  483. const zend_function_entry pgsql_functions[] = {
  484. /* connection functions */
  485. PHP_FE(pg_connect, arginfo_pg_connect)
  486. PHP_FE(pg_pconnect, arginfo_pg_pconnect)
  487. PHP_FE(pg_connect_poll, arginfo_pg_connect_poll)
  488. PHP_FE(pg_close, arginfo_pg_close)
  489. PHP_FE(pg_connection_status, arginfo_pg_connection_status)
  490. PHP_FE(pg_connection_busy, arginfo_pg_connection_busy)
  491. PHP_FE(pg_connection_reset, arginfo_pg_connection_reset)
  492. PHP_FE(pg_host, arginfo_pg_host)
  493. PHP_FE(pg_dbname, arginfo_pg_dbname)
  494. PHP_FE(pg_port, arginfo_pg_port)
  495. PHP_FE(pg_tty, arginfo_pg_tty)
  496. PHP_FE(pg_options, arginfo_pg_options)
  497. PHP_FE(pg_version, arginfo_pg_version)
  498. PHP_FE(pg_ping, arginfo_pg_ping)
  499. #if HAVE_PQPARAMETERSTATUS
  500. PHP_FE(pg_parameter_status, arginfo_pg_parameter_status)
  501. #endif
  502. #if HAVE_PGTRANSACTIONSTATUS
  503. PHP_FE(pg_transaction_status, arginfo_pg_transaction_status)
  504. #endif
  505. /* query functions */
  506. PHP_FE(pg_query, arginfo_pg_query)
  507. #if HAVE_PQEXECPARAMS
  508. PHP_FE(pg_query_params, arginfo_pg_query_params)
  509. #endif
  510. #if HAVE_PQPREPARE
  511. PHP_FE(pg_prepare, arginfo_pg_prepare)
  512. #endif
  513. #if HAVE_PQEXECPREPARED
  514. PHP_FE(pg_execute, arginfo_pg_execute)
  515. #endif
  516. PHP_FE(pg_send_query, arginfo_pg_send_query)
  517. #if HAVE_PQSENDQUERYPARAMS
  518. PHP_FE(pg_send_query_params, arginfo_pg_send_query_params)
  519. #endif
  520. #if HAVE_PQSENDPREPARE
  521. PHP_FE(pg_send_prepare, arginfo_pg_send_prepare)
  522. #endif
  523. #if HAVE_PQSENDQUERYPREPARED
  524. PHP_FE(pg_send_execute, arginfo_pg_send_execute)
  525. #endif
  526. PHP_FE(pg_cancel_query, arginfo_pg_cancel_query)
  527. /* result functions */
  528. PHP_FE(pg_fetch_result, arginfo_pg_fetch_result)
  529. PHP_FE(pg_fetch_row, arginfo_pg_fetch_row)
  530. PHP_FE(pg_fetch_assoc, arginfo_pg_fetch_assoc)
  531. PHP_FE(pg_fetch_array, arginfo_pg_fetch_array)
  532. PHP_FE(pg_fetch_object, arginfo_pg_fetch_object)
  533. PHP_FE(pg_fetch_all, arginfo_pg_fetch_all)
  534. PHP_FE(pg_fetch_all_columns, arginfo_pg_fetch_all_columns)
  535. #if HAVE_PQCMDTUPLES
  536. PHP_FE(pg_affected_rows,arginfo_pg_affected_rows)
  537. #endif
  538. PHP_FE(pg_get_result, arginfo_pg_get_result)
  539. PHP_FE(pg_result_seek, arginfo_pg_result_seek)
  540. PHP_FE(pg_result_status,arginfo_pg_result_status)
  541. PHP_FE(pg_free_result, arginfo_pg_free_result)
  542. PHP_FE(pg_last_oid, arginfo_pg_last_oid)
  543. PHP_FE(pg_num_rows, arginfo_pg_num_rows)
  544. PHP_FE(pg_num_fields, arginfo_pg_num_fields)
  545. PHP_FE(pg_field_name, arginfo_pg_field_name)
  546. PHP_FE(pg_field_num, arginfo_pg_field_num)
  547. PHP_FE(pg_field_size, arginfo_pg_field_size)
  548. PHP_FE(pg_field_type, arginfo_pg_field_type)
  549. PHP_FE(pg_field_type_oid, arginfo_pg_field_type_oid)
  550. PHP_FE(pg_field_prtlen, arginfo_pg_field_prtlen)
  551. PHP_FE(pg_field_is_null,arginfo_pg_field_is_null)
  552. #ifdef HAVE_PQFTABLE
  553. PHP_FE(pg_field_table, arginfo_pg_field_table)
  554. #endif
  555. /* async message function */
  556. PHP_FE(pg_get_notify, arginfo_pg_get_notify)
  557. PHP_FE(pg_socket, arginfo_pg_socket)
  558. PHP_FE(pg_consume_input,arginfo_pg_consume_input)
  559. PHP_FE(pg_flush, arginfo_pg_flush)
  560. PHP_FE(pg_get_pid, arginfo_pg_get_pid)
  561. /* error message functions */
  562. PHP_FE(pg_result_error, arginfo_pg_result_error)
  563. #if HAVE_PQRESULTERRORFIELD
  564. PHP_FE(pg_result_error_field, arginfo_pg_result_error_field)
  565. #endif
  566. PHP_FE(pg_last_error, arginfo_pg_last_error)
  567. PHP_FE(pg_last_notice, arginfo_pg_last_notice)
  568. /* copy functions */
  569. PHP_FE(pg_put_line, arginfo_pg_put_line)
  570. PHP_FE(pg_end_copy, arginfo_pg_end_copy)
  571. PHP_FE(pg_copy_to, arginfo_pg_copy_to)
  572. PHP_FE(pg_copy_from, arginfo_pg_copy_from)
  573. /* debug functions */
  574. PHP_FE(pg_trace, arginfo_pg_trace)
  575. PHP_FE(pg_untrace, arginfo_pg_untrace)
  576. /* large object functions */
  577. PHP_FE(pg_lo_create, arginfo_pg_lo_create)
  578. PHP_FE(pg_lo_unlink, arginfo_pg_lo_unlink)
  579. PHP_FE(pg_lo_open, arginfo_pg_lo_open)
  580. PHP_FE(pg_lo_close, arginfo_pg_lo_close)
  581. PHP_FE(pg_lo_read, arginfo_pg_lo_read)
  582. PHP_FE(pg_lo_write, arginfo_pg_lo_write)
  583. PHP_FE(pg_lo_read_all, arginfo_pg_lo_read_all)
  584. PHP_FE(pg_lo_import, arginfo_pg_lo_import)
  585. PHP_FE(pg_lo_export, arginfo_pg_lo_export)
  586. PHP_FE(pg_lo_seek, arginfo_pg_lo_seek)
  587. PHP_FE(pg_lo_tell, arginfo_pg_lo_tell)
  588. #if HAVE_PG_LO_TRUNCATE
  589. PHP_FE(pg_lo_truncate, arginfo_pg_lo_truncate)
  590. #endif
  591. /* utility functions */
  592. #if HAVE_PQESCAPE
  593. PHP_FE(pg_escape_string, arginfo_pg_escape_string)
  594. PHP_FE(pg_escape_bytea, arginfo_pg_escape_bytea)
  595. PHP_FE(pg_unescape_bytea, arginfo_pg_unescape_bytea)
  596. PHP_FE(pg_escape_literal, arginfo_pg_escape_literal)
  597. PHP_FE(pg_escape_identifier, arginfo_pg_escape_identifier)
  598. #endif
  599. #if HAVE_PQSETERRORVERBOSITY
  600. PHP_FE(pg_set_error_verbosity, arginfo_pg_set_error_verbosity)
  601. #endif
  602. #if HAVE_PQCLIENTENCODING
  603. PHP_FE(pg_client_encoding, arginfo_pg_client_encoding)
  604. PHP_FE(pg_set_client_encoding, arginfo_pg_set_client_encoding)
  605. #endif
  606. /* misc function */
  607. PHP_FE(pg_meta_data, arginfo_pg_meta_data)
  608. PHP_FE(pg_convert, arginfo_pg_convert)
  609. PHP_FE(pg_insert, arginfo_pg_insert)
  610. PHP_FE(pg_update, arginfo_pg_update)
  611. PHP_FE(pg_delete, arginfo_pg_delete)
  612. PHP_FE(pg_select, arginfo_pg_select)
  613. /* aliases for downwards compatibility */
  614. PHP_FALIAS(pg_exec, pg_query, arginfo_pg_query)
  615. PHP_FALIAS(pg_getlastoid, pg_last_oid, arginfo_pg_last_oid)
  616. #if HAVE_PQCMDTUPLES
  617. PHP_FALIAS(pg_cmdtuples, pg_affected_rows, arginfo_pg_affected_rows)
  618. #endif
  619. PHP_FALIAS(pg_errormessage, pg_last_error, arginfo_pg_last_error)
  620. PHP_FALIAS(pg_numrows, pg_num_rows, arginfo_pg_num_rows)
  621. PHP_FALIAS(pg_numfields, pg_num_fields, arginfo_pg_num_fields)
  622. PHP_FALIAS(pg_fieldname, pg_field_name, arginfo_pg_field_name)
  623. PHP_FALIAS(pg_fieldsize, pg_field_size, arginfo_pg_field_size)
  624. PHP_FALIAS(pg_fieldtype, pg_field_type, arginfo_pg_field_type)
  625. PHP_FALIAS(pg_fieldnum, pg_field_num, arginfo_pg_field_num)
  626. PHP_FALIAS(pg_fieldprtlen, pg_field_prtlen, arginfo_pg_field_prtlen)
  627. PHP_FALIAS(pg_fieldisnull, pg_field_is_null, arginfo_pg_field_is_null)
  628. PHP_FALIAS(pg_freeresult, pg_free_result, arginfo_pg_free_result)
  629. PHP_FALIAS(pg_result, pg_fetch_result, arginfo_pg_get_result)
  630. PHP_FALIAS(pg_loreadall, pg_lo_read_all, arginfo_pg_lo_read_all)
  631. PHP_FALIAS(pg_locreate, pg_lo_create, arginfo_pg_lo_create)
  632. PHP_FALIAS(pg_lounlink, pg_lo_unlink, arginfo_pg_lo_unlink)
  633. PHP_FALIAS(pg_loopen, pg_lo_open, arginfo_pg_lo_open)
  634. PHP_FALIAS(pg_loclose, pg_lo_close, arginfo_pg_lo_close)
  635. PHP_FALIAS(pg_loread, pg_lo_read, arginfo_pg_lo_read)
  636. PHP_FALIAS(pg_lowrite, pg_lo_write, arginfo_pg_lo_write)
  637. PHP_FALIAS(pg_loimport, pg_lo_import, arginfo_pg_lo_import)
  638. PHP_FALIAS(pg_loexport, pg_lo_export, arginfo_pg_lo_export)
  639. #if HAVE_PQCLIENTENCODING
  640. PHP_FALIAS(pg_clientencoding, pg_client_encoding, arginfo_pg_client_encoding)
  641. PHP_FALIAS(pg_setclientencoding, pg_set_client_encoding, arginfo_pg_set_client_encoding)
  642. #endif
  643. PHP_FE_END
  644. };
  645. /* }}} */
  646. /* {{{ pgsql_module_entry
  647. */
  648. zend_module_entry pgsql_module_entry = {
  649. STANDARD_MODULE_HEADER,
  650. "pgsql",
  651. pgsql_functions,
  652. PHP_MINIT(pgsql),
  653. PHP_MSHUTDOWN(pgsql),
  654. PHP_RINIT(pgsql),
  655. PHP_RSHUTDOWN(pgsql),
  656. PHP_MINFO(pgsql),
  657. NO_VERSION_YET,
  658. PHP_MODULE_GLOBALS(pgsql),
  659. PHP_GINIT(pgsql),
  660. NULL,
  661. NULL,
  662. STANDARD_MODULE_PROPERTIES_EX
  663. };
  664. /* }}} */
  665. #ifdef COMPILE_DL_PGSQL
  666. ZEND_GET_MODULE(pgsql)
  667. #endif
  668. static int le_link, le_plink, le_result, le_lofp, le_string;
  669. /* Compatibility definitions */
  670. #ifndef HAVE_PGSQL_WITH_MULTIBYTE_SUPPORT
  671. #define pg_encoding_to_char(x) "SQL_ASCII"
  672. #endif
  673. #if !HAVE_PQESCAPE_CONN
  674. #define PQescapeStringConn(conn, to, from, len, error) PQescapeString(to, from, len)
  675. #endif
  676. #if HAVE_PQESCAPELITERAL
  677. #define PGSQLescapeLiteral(conn, str, len) PQescapeLiteral(conn, str, len)
  678. #define PGSQLescapeIdentifier(conn, str, len) PQescapeIdentifier(conn, str, len)
  679. #define PGSQLfree(a) PQfreemem(a)
  680. #else
  681. #define PGSQLescapeLiteral(conn, str, len) php_pgsql_PQescapeInternal(conn, str, len, 1, 0)
  682. #define PGSQLescapeLiteral2(conn, str, len) php_pgsql_PQescapeInternal(conn, str, len, 1, 1)
  683. #define PGSQLescapeIdentifier(conn, str, len) php_pgsql_PQescapeInternal(conn, str, len, 0, 0)
  684. #define PGSQLfree(a) efree(a)
  685. /* emulate libpq's PQescapeInternal() 9.0 or later */
  686. static char* php_pgsql_PQescapeInternal(PGconn *conn, const char *str, size_t len, int escape_literal, int safe) {
  687. char *result, *rp, *s;
  688. size_t tmp_len;
  689. if (!conn) {
  690. return NULL;
  691. }
  692. /* allocate enough memory */
  693. rp = result = (char *)safe_emalloc(len, 2, 5); /* leading " E" needs extra 2 bytes + quote_chars on both end for 2 bytes + NULL */
  694. if (escape_literal) {
  695. size_t new_len;
  696. if (safe) {
  697. char *tmp = (char *)safe_emalloc(len, 2, 1);
  698. *rp++ = '\'';
  699. /* PQescapeString does not escape \, but it handles multibyte chars safely.
  700. This escape is incompatible with PQescapeLiteral. */
  701. new_len = PQescapeStringConn(conn, tmp, str, len, NULL);
  702. strncpy(rp, tmp, new_len);
  703. efree(tmp);
  704. rp += new_len;
  705. } else {
  706. char *encoding;
  707. /* This is compatible with PQescapeLiteral, but it cannot handle multbyte chars
  708. such as SJIS, BIG5. Raise warning and return NULL by checking
  709. client_encoding. */
  710. encoding = (char *) pg_encoding_to_char(PQclientEncoding(conn));
  711. if (!strncmp(encoding, "SJIS", sizeof("SJIS")-1) ||
  712. !strncmp(encoding, "SHIFT_JIS_2004", sizeof("SHIFT_JIS_2004")-1) ||
  713. !strncmp(encoding, "BIG5", sizeof("BIG5")-1) ||
  714. !strncmp(encoding, "GB18030", sizeof("GB18030")-1) ||
  715. !strncmp(encoding, "GBK", sizeof("GBK")-1) ||
  716. !strncmp(encoding, "JOHAB", sizeof("JOHAB")-1) ||
  717. !strncmp(encoding, "UHC", sizeof("UHC")-1) ) {
  718. TSRMLS_FETCH();
  719. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unsafe encoding is used. Do not use '%s' encoding or use PostgreSQL 9.0 or later libpq.", encoding);
  720. }
  721. /* check backslashes */
  722. tmp_len = strspn(str, "\\");
  723. if (tmp_len != len) {
  724. /* add " E" for escaping slashes */
  725. *rp++ = ' ';
  726. *rp++ = 'E';
  727. }
  728. *rp++ = '\'';
  729. for (s = (char *)str; s - str < len; ++s) {
  730. if (*s == '\'' || *s == '\\') {
  731. *rp++ = *s;
  732. *rp++ = *s;
  733. } else {
  734. *rp++ = *s;
  735. }
  736. }
  737. }
  738. *rp++ = '\'';
  739. } else {
  740. /* Identifier escape. */
  741. *rp++ = '"';
  742. for (s = (char *)str; s - str < len; ++s) {
  743. if (*s == '"') {
  744. *rp++ = '"';
  745. *rp++ = '"';
  746. } else {
  747. *rp++ = *s;
  748. }
  749. }
  750. *rp++ = '"';
  751. }
  752. *rp = '\0';
  753. return result;
  754. }
  755. #endif
  756. /* {{{ _php_pgsql_trim_message */
  757. static char * _php_pgsql_trim_message(const char *message, int *len)
  758. {
  759. register int i = strlen(message)-1;
  760. if (i>1 && (message[i-1] == '\r' || message[i-1] == '\n') && message[i] == '.') {
  761. --i;
  762. }
  763. while (i>0 && (message[i] == '\r' || message[i] == '\n')) {
  764. --i;
  765. }
  766. ++i;
  767. if (len) {
  768. *len = i;
  769. }
  770. return estrndup(message, i);
  771. }
  772. /* }}} */
  773. /* {{{ _php_pgsql_trim_result */
  774. static inline char * _php_pgsql_trim_result(PGconn * pgsql, char **buf)
  775. {
  776. return *buf = _php_pgsql_trim_message(PQerrorMessage(pgsql), NULL);
  777. }
  778. /* }}} */
  779. #define PQErrorMessageTrim(pgsql, buf) _php_pgsql_trim_result(pgsql, buf)
  780. #define PHP_PQ_ERROR(text, pgsql) { \
  781. char *msgbuf = _php_pgsql_trim_message(PQerrorMessage(pgsql), NULL); \
  782. php_error_docref(NULL TSRMLS_CC, E_WARNING, text, msgbuf); \
  783. efree(msgbuf); \
  784. } \
  785. /* {{{ php_pgsql_set_default_link
  786. */
  787. static void php_pgsql_set_default_link(int id TSRMLS_DC)
  788. {
  789. zend_list_addref(id);
  790. if (PGG(default_link) != -1) {
  791. zend_list_delete(PGG(default_link));
  792. }
  793. PGG(default_link) = id;
  794. }
  795. /* }}} */
  796. /* {{{ _close_pgsql_link
  797. */
  798. static void _close_pgsql_link(zend_rsrc_list_entry *rsrc TSRMLS_DC)
  799. {
  800. PGconn *link = (PGconn *)rsrc->ptr;
  801. PGresult *res;
  802. while ((res = PQgetResult(link))) {
  803. PQclear(res);
  804. }
  805. PQfinish(link);
  806. PGG(num_links)--;
  807. }
  808. /* }}} */
  809. /* {{{ _close_pgsql_plink
  810. */
  811. static void _close_pgsql_plink(zend_rsrc_list_entry *rsrc TSRMLS_DC)
  812. {
  813. PGconn *link = (PGconn *)rsrc->ptr;
  814. PGresult *res;
  815. while ((res = PQgetResult(link))) {
  816. PQclear(res);
  817. }
  818. PQfinish(link);
  819. PGG(num_persistent)--;
  820. PGG(num_links)--;
  821. }
  822. /* }}} */
  823. /* {{{ _php_pgsql_notice_handler
  824. */
  825. static void _php_pgsql_notice_handler(void *resource_id, const char *message)
  826. {
  827. php_pgsql_notice *notice;
  828. TSRMLS_FETCH();
  829. if (! PGG(ignore_notices)) {
  830. notice = (php_pgsql_notice *)emalloc(sizeof(php_pgsql_notice));
  831. notice->message = _php_pgsql_trim_message(message, (int *)&notice->len);
  832. if (PGG(log_notices)) {
  833. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "%s", notice->message);
  834. }
  835. zend_hash_index_update(&PGG(notices), (ulong)resource_id, (void **)&notice, sizeof(php_pgsql_notice *), NULL);
  836. }
  837. }
  838. /* }}} */
  839. #define PHP_PGSQL_NOTICE_PTR_DTOR (void (*)(void *))_php_pgsql_notice_ptr_dtor
  840. /* {{{ _php_pgsql_notice_dtor
  841. */
  842. static void _php_pgsql_notice_ptr_dtor(void **ptr)
  843. {
  844. php_pgsql_notice *notice = (php_pgsql_notice *)*ptr;
  845. if (notice) {
  846. efree(notice->message);
  847. efree(notice);
  848. notice = NULL;
  849. }
  850. }
  851. /* }}} */
  852. /* {{{ _rollback_transactions
  853. */
  854. static int _rollback_transactions(zend_rsrc_list_entry *rsrc TSRMLS_DC)
  855. {
  856. PGconn *link;
  857. PGresult *res;
  858. int orig;
  859. if (Z_TYPE_P(rsrc) != le_plink)
  860. return 0;
  861. link = (PGconn *) rsrc->ptr;
  862. if (PQ_SETNONBLOCKING(link, 0)) {
  863. php_error_docref("ref.pgsql" TSRMLS_CC, E_NOTICE, "Cannot set connection to blocking mode");
  864. return -1;
  865. }
  866. while ((res = PQgetResult(link))) {
  867. PQclear(res);
  868. }
  869. #if HAVE_PGTRANSACTIONSTATUS && HAVE_PQPROTOCOLVERSION
  870. if ((PQprotocolVersion(link) >= 3 && PQtransactionStatus(link) != PQTRANS_IDLE) || PQprotocolVersion(link) < 3)
  871. #endif
  872. {
  873. orig = PGG(ignore_notices);
  874. PGG(ignore_notices) = 1;
  875. #if HAVE_PGTRANSACTIONSTATUS && HAVE_PQPROTOCOLVERSION
  876. res = PQexec(link,"ROLLBACK;");
  877. #else
  878. res = PQexec(link,"BEGIN;");
  879. PQclear(res);
  880. res = PQexec(link,"ROLLBACK;");
  881. #endif
  882. PQclear(res);
  883. PGG(ignore_notices) = orig;
  884. }
  885. return 0;
  886. }
  887. /* }}} */
  888. /* {{{ _free_ptr
  889. */
  890. static void _free_ptr(zend_rsrc_list_entry *rsrc TSRMLS_DC)
  891. {
  892. pgLofp *lofp = (pgLofp *)rsrc->ptr;
  893. efree(lofp);
  894. }
  895. /* }}} */
  896. /* {{{ _free_result
  897. */
  898. static void _free_result(zend_rsrc_list_entry *rsrc TSRMLS_DC)
  899. {
  900. pgsql_result_handle *pg_result = (pgsql_result_handle *)rsrc->ptr;
  901. PQclear(pg_result->result);
  902. efree(pg_result);
  903. }
  904. /* }}} */
  905. static int _php_pgsql_detect_identifier_escape(const char *identifier, size_t len)
  906. {
  907. size_t i;
  908. /* Handle edge case. Cannot be a escaped string */
  909. if (len <= 2) {
  910. return FAILURE;
  911. }
  912. /* Detect double qoutes */
  913. if (identifier[0] == '"' && identifier[len-1] == '"') {
  914. /* Detect wrong format of " inside of escaped string */
  915. for (i = 1; i < len-1; i++) {
  916. if (identifier[i] == '"' && (identifier[++i] != '"' || i == len-1)) {
  917. return FAILURE;
  918. }
  919. }
  920. } else {
  921. return FAILURE;
  922. }
  923. /* Escaped properly */
  924. return SUCCESS;
  925. }
  926. /* {{{ PHP_INI
  927. */
  928. PHP_INI_BEGIN()
  929. STD_PHP_INI_BOOLEAN( "pgsql.allow_persistent", "1", PHP_INI_SYSTEM, OnUpdateBool, allow_persistent, zend_pgsql_globals, pgsql_globals)
  930. STD_PHP_INI_ENTRY_EX("pgsql.max_persistent", "-1", PHP_INI_SYSTEM, OnUpdateLong, max_persistent, zend_pgsql_globals, pgsql_globals, display_link_numbers)
  931. STD_PHP_INI_ENTRY_EX("pgsql.max_links", "-1", PHP_INI_SYSTEM, OnUpdateLong, max_links, zend_pgsql_globals, pgsql_globals, display_link_numbers)
  932. STD_PHP_INI_BOOLEAN( "pgsql.auto_reset_persistent", "0", PHP_INI_SYSTEM, OnUpdateBool, auto_reset_persistent, zend_pgsql_globals, pgsql_globals)
  933. STD_PHP_INI_BOOLEAN( "pgsql.ignore_notice", "0", PHP_INI_ALL, OnUpdateBool, ignore_notices, zend_pgsql_globals, pgsql_globals)
  934. STD_PHP_INI_BOOLEAN( "pgsql.log_notice", "0", PHP_INI_ALL, OnUpdateBool, log_notices, zend_pgsql_globals, pgsql_globals)
  935. PHP_INI_END()
  936. /* }}} */
  937. /* {{{ PHP_GINIT_FUNCTION
  938. */
  939. static PHP_GINIT_FUNCTION(pgsql)
  940. {
  941. memset(pgsql_globals, 0, sizeof(zend_pgsql_globals));
  942. /* Initilize notice message hash at MINIT only */
  943. zend_hash_init_ex(&pgsql_globals->notices, 0, NULL, PHP_PGSQL_NOTICE_PTR_DTOR, 1, 0);
  944. }
  945. /* }}} */
  946. /* {{{ PHP_MINIT_FUNCTION
  947. */
  948. PHP_MINIT_FUNCTION(pgsql)
  949. {
  950. REGISTER_INI_ENTRIES();
  951. le_link = zend_register_list_destructors_ex(_close_pgsql_link, NULL, "pgsql link", module_number);
  952. le_plink = zend_register_list_destructors_ex(NULL, _close_pgsql_plink, "pgsql link persistent", module_number);
  953. le_result = zend_register_list_destructors_ex(_free_result, NULL, "pgsql result", module_number);
  954. le_lofp = zend_register_list_destructors_ex(_free_ptr, NULL, "pgsql large object", module_number);
  955. le_string = zend_register_list_destructors_ex(_free_ptr, NULL, "pgsql string", module_number);
  956. #if HAVE_PG_CONFIG_H
  957. /* PG_VERSION - libpq version */
  958. REGISTER_STRING_CONSTANT("PGSQL_LIBPQ_VERSION", PG_VERSION, CONST_CS | CONST_PERSISTENT);
  959. REGISTER_STRING_CONSTANT("PGSQL_LIBPQ_VERSION_STR", PG_VERSION_STR, CONST_CS | CONST_PERSISTENT);
  960. #endif
  961. /* For connection option */
  962. REGISTER_LONG_CONSTANT("PGSQL_CONNECT_FORCE_NEW", PGSQL_CONNECT_FORCE_NEW, CONST_CS | CONST_PERSISTENT);
  963. REGISTER_LONG_CONSTANT("PGSQL_CONNECT_ASYNC", PGSQL_CONNECT_ASYNC, CONST_CS | CONST_PERSISTENT);
  964. /* For pg_fetch_array() */
  965. REGISTER_LONG_CONSTANT("PGSQL_ASSOC", PGSQL_ASSOC, CONST_CS | CONST_PERSISTENT);
  966. REGISTER_LONG_CONSTANT("PGSQL_NUM", PGSQL_NUM, CONST_CS | CONST_PERSISTENT);
  967. REGISTER_LONG_CONSTANT("PGSQL_BOTH", PGSQL_BOTH, CONST_CS | CONST_PERSISTENT);
  968. /* For pg_connection_status() */
  969. REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_BAD", CONNECTION_BAD, CONST_CS | CONST_PERSISTENT);
  970. REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_OK", CONNECTION_OK, CONST_CS | CONST_PERSISTENT);
  971. REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_STARTED", CONNECTION_STARTED, CONST_CS | CONST_PERSISTENT);
  972. REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_MADE", CONNECTION_MADE, CONST_CS | CONST_PERSISTENT);
  973. REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_AWAITING_RESPONSE", CONNECTION_AWAITING_RESPONSE, CONST_CS | CONST_PERSISTENT);
  974. REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_AUTH_OK", CONNECTION_AUTH_OK, CONST_CS | CONST_PERSISTENT);
  975. #ifdef CONNECTION_SSL_STARTUP
  976. REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_SSL_STARTUP", CONNECTION_SSL_STARTUP, CONST_CS | CONST_PERSISTENT);
  977. #endif
  978. REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_SETENV", CONNECTION_SETENV, CONST_CS | CONST_PERSISTENT);
  979. /* For pg_connect_poll() */
  980. REGISTER_LONG_CONSTANT("PGSQL_POLLING_FAILED", PGRES_POLLING_FAILED, CONST_CS | CONST_PERSISTENT);
  981. REGISTER_LONG_CONSTANT("PGSQL_POLLING_READING", PGRES_POLLING_READING, CONST_CS | CONST_PERSISTENT);
  982. REGISTER_LONG_CONSTANT("PGSQL_POLLING_WRITING", PGRES_POLLING_WRITING, CONST_CS | CONST_PERSISTENT);
  983. REGISTER_LONG_CONSTANT("PGSQL_POLLING_OK", PGRES_POLLING_OK, CONST_CS | CONST_PERSISTENT);
  984. REGISTER_LONG_CONSTANT("PGSQL_POLLING_ACTIVE", PGRES_POLLING_ACTIVE, CONST_CS | CONST_PERSISTENT);
  985. #if HAVE_PGTRANSACTIONSTATUS
  986. /* For pg_transaction_status() */
  987. REGISTER_LONG_CONSTANT("PGSQL_TRANSACTION_IDLE", PQTRANS_IDLE, CONST_CS | CONST_PERSISTENT);
  988. REGISTER_LONG_CONSTANT("PGSQL_TRANSACTION_ACTIVE", PQTRANS_ACTIVE, CONST_CS | CONST_PERSISTENT);
  989. REGISTER_LONG_CONSTANT("PGSQL_TRANSACTION_INTRANS", PQTRANS_INTRANS, CONST_CS | CONST_PERSISTENT);
  990. REGISTER_LONG_CONSTANT("PGSQL_TRANSACTION_INERROR", PQTRANS_INERROR, CONST_CS | CONST_PERSISTENT);
  991. REGISTER_LONG_CONSTANT("PGSQL_TRANSACTION_UNKNOWN", PQTRANS_UNKNOWN, CONST_CS | CONST_PERSISTENT);
  992. #endif
  993. #if HAVE_PQSETERRORVERBOSITY
  994. /* For pg_set_error_verbosity() */
  995. REGISTER_LONG_CONSTANT("PGSQL_ERRORS_TERSE", PQERRORS_TERSE, CONST_CS | CONST_PERSISTENT);
  996. REGISTER_LONG_CONSTANT("PGSQL_ERRORS_DEFAULT", PQERRORS_DEFAULT, CONST_CS | CONST_PERSISTENT);
  997. REGISTER_LONG_CONSTANT("PGSQL_ERRORS_VERBOSE", PQERRORS_VERBOSE, CONST_CS | CONST_PERSISTENT);
  998. #endif
  999. /* For lo_seek() */
  1000. REGISTER_LONG_CONSTANT("PGSQL_SEEK_SET", SEEK_SET, CONST_CS | CONST_PERSISTENT);
  1001. REGISTER_LONG_CONSTANT("PGSQL_SEEK_CUR", SEEK_CUR, CONST_CS | CONST_PERSISTENT);
  1002. REGISTER_LONG_CONSTANT("PGSQL_SEEK_END", SEEK_END, CONST_CS | CONST_PERSISTENT);
  1003. /* For pg_result_status() return value type */
  1004. REGISTER_LONG_CONSTANT("PGSQL_STATUS_LONG", PGSQL_STATUS_LONG, CONST_CS | CONST_PERSISTENT);
  1005. REGISTER_LONG_CONSTANT("PGSQL_STATUS_STRING", PGSQL_STATUS_STRING, CONST_CS | CONST_PERSISTENT);
  1006. /* For pg_result_status() return value */
  1007. REGISTER_LONG_CONSTANT("PGSQL_EMPTY_QUERY", PGRES_EMPTY_QUERY, CONST_CS | CONST_PERSISTENT);
  1008. REGISTER_LONG_CONSTANT("PGSQL_COMMAND_OK", PGRES_COMMAND_OK, CONST_CS | CONST_PERSISTENT);
  1009. REGISTER_LONG_CONSTANT("PGSQL_TUPLES_OK", PGRES_TUPLES_OK, CONST_CS | CONST_PERSISTENT);
  1010. REGISTER_LONG_CONSTANT("PGSQL_COPY_OUT", PGRES_COPY_OUT, CONST_CS | CONST_PERSISTENT);
  1011. REGISTER_LONG_CONSTANT("PGSQL_COPY_IN", PGRES_COPY_IN, CONST_CS | CONST_PERSISTENT);
  1012. REGISTER_LONG_CONSTANT("PGSQL_BAD_RESPONSE", PGRES_BAD_RESPONSE, CONST_CS | CONST_PERSISTENT);
  1013. REGISTER_LONG_CONSTANT("PGSQL_NONFATAL_ERROR", PGRES_NONFATAL_ERROR, CONST_CS | CONST_PERSISTENT);
  1014. REGISTER_LONG_CONSTANT("PGSQL_FATAL_ERROR", PGRES_FATAL_ERROR, CONST_CS | CONST_PERSISTENT);
  1015. #if HAVE_PQRESULTERRORFIELD
  1016. /* For pg_result_error_field() field codes */
  1017. REGISTER_LONG_CONSTANT("PGSQL_DIAG_SEVERITY", PG_DIAG_SEVERITY, CONST_CS | CONST_PERSISTENT);
  1018. REGISTER_LONG_CONSTANT("PGSQL_DIAG_SQLSTATE", PG_DIAG_SQLSTATE, CONST_CS | CONST_PERSISTENT);
  1019. REGISTER_LONG_CONSTANT("PGSQL_DIAG_MESSAGE_PRIMARY", PG_DIAG_MESSAGE_PRIMARY, CONST_CS | CONST_PERSISTENT);
  1020. REGISTER_LONG_CONSTANT("PGSQL_DIAG_MESSAGE_DETAIL", PG_DIAG_MESSAGE_DETAIL, CONST_CS | CONST_PERSISTENT);
  1021. REGISTER_LONG_CONSTANT("PGSQL_DIAG_MESSAGE_HINT", PG_DIAG_MESSAGE_HINT, CONST_CS | CONST_PERSISTENT);
  1022. REGISTER_LONG_CONSTANT("PGSQL_DIAG_STATEMENT_POSITION", PG_DIAG_STATEMENT_POSITION, CONST_CS | CONST_PERSISTENT);
  1023. #ifdef PG_DIAG_INTERNAL_POSITION
  1024. REGISTER_LONG_CONSTANT("PGSQL_DIAG_INTERNAL_POSITION", PG_DIAG_INTERNAL_POSITION, CONST_CS | CONST_PERSISTENT);
  1025. #endif
  1026. #ifdef PG_DIAG_INTERNAL_QUERY
  1027. REGISTER_LONG_CONSTANT("PGSQL_DIAG_INTERNAL_QUERY", PG_DIAG_INTERNAL_QUERY, CONST_CS | CONST_PERSISTENT);
  1028. #endif
  1029. REGISTER_LONG_CONSTANT("PGSQL_DIAG_CONTEXT", PG_DIAG_CONTEXT, CONST_CS | CONST_PERSISTENT);
  1030. REGISTER_LONG_CONSTANT("PGSQL_DIAG_SOURCE_FILE", PG_DIAG_SOURCE_FILE, CONST_CS | CONST_PERSISTENT);
  1031. REGISTER_LONG_CONSTANT("PGSQL_DIAG_SOURCE_LINE", PG_DIAG_SOURCE_LINE, CONST_CS | CONST_PERSISTENT);
  1032. REGISTER_LONG_CONSTANT("PGSQL_DIAG_SOURCE_FUNCTION", PG_DIAG_SOURCE_FUNCTION, CONST_CS | CONST_PERSISTENT);
  1033. #endif
  1034. /* pg_convert options */
  1035. REGISTER_LONG_CONSTANT("PGSQL_CONV_IGNORE_DEFAULT", PGSQL_CONV_IGNORE_DEFAULT, CONST_CS | CONST_PERSISTENT);
  1036. REGISTER_LONG_CONSTANT("PGSQL_CONV_FORCE_NULL", PGSQL_CONV_FORCE_NULL, CONST_CS | CONST_PERSISTENT);
  1037. REGISTER_LONG_CONSTANT("PGSQL_CONV_IGNORE_NOT_NULL", PGSQL_CONV_IGNORE_NOT_NULL, CONST_CS | CONST_PERSISTENT);
  1038. /* pg_insert/update/delete/select options */
  1039. REGISTER_LONG_CONSTANT("PGSQL_DML_ESCAPE", PGSQL_DML_ESCAPE, CONST_CS | CONST_PERSISTENT);
  1040. REGISTER_LONG_CONSTANT("PGSQL_DML_NO_CONV", PGSQL_DML_NO_CONV, CONST_CS | CONST_PERSISTENT);
  1041. REGISTER_LONG_CONSTANT("PGSQL_DML_EXEC", PGSQL_DML_EXEC, CONST_CS | CONST_PERSISTENT);
  1042. REGISTER_LONG_CONSTANT("PGSQL_DML_ASYNC", PGSQL_DML_ASYNC, CONST_CS | CONST_PERSISTENT);
  1043. REGISTER_LONG_CONSTANT("PGSQL_DML_STRING", PGSQL_DML_STRING, CONST_CS | CONST_PERSISTENT);
  1044. return SUCCESS;
  1045. }
  1046. /* }}} */
  1047. /* {{{ PHP_MSHUTDOWN_FUNCTION
  1048. */
  1049. PHP_MSHUTDOWN_FUNCTION(pgsql)
  1050. {
  1051. UNREGISTER_INI_ENTRIES();
  1052. zend_hash_destroy(&PGG(notices));
  1053. return SUCCESS;
  1054. }
  1055. /* }}} */
  1056. /* {{{ PHP_RINIT_FUNCTION
  1057. */
  1058. PHP_RINIT_FUNCTION(pgsql)
  1059. {
  1060. PGG(default_link)=-1;
  1061. PGG(num_links) = PGG(num_persistent);
  1062. return SUCCESS;
  1063. }
  1064. /* }}} */
  1065. /* {{{ PHP_RSHUTDOWN_FUNCTION
  1066. */
  1067. PHP_RSHUTDOWN_FUNCTION(pgsql)
  1068. {
  1069. /* clean up notice messages */
  1070. zend_hash_clean(&PGG(notices));
  1071. /* clean up persistent connection */
  1072. zend_hash_apply(&EG(persistent_list), (apply_func_t) _rollback_transactions TSRMLS_CC);
  1073. return SUCCESS;
  1074. }
  1075. /* }}} */
  1076. /* {{{ PHP_MINFO_FUNCTION
  1077. */
  1078. PHP_MINFO_FUNCTION(pgsql)
  1079. {
  1080. char buf[256];
  1081. php_info_print_table_start();
  1082. php_info_print_table_header(2, "PostgreSQL Support", "enabled");
  1083. #if HAVE_PG_CONFIG_H
  1084. php_info_print_table_row(2, "PostgreSQL(libpq) Version", PG_VERSION);
  1085. php_info_print_table_row(2, "PostgreSQL(libpq) ", PG_VERSION_STR);
  1086. #ifdef HAVE_PGSQL_WITH_MULTIBYTE_SUPPORT
  1087. php_info_print_table_row(2, "Multibyte character support", "enabled");
  1088. #else
  1089. php_info_print_table_row(2, "Multibyte character support", "disabled");
  1090. #endif
  1091. #if defined(USE_SSL) || defined(USE_OPENSSL)
  1092. php_info_print_table_row(2, "SSL support", "enabled");
  1093. #else
  1094. php_info_print_table_row(2, "SSL support", "disabled");
  1095. #endif
  1096. #endif /* HAVE_PG_CONFIG_H */
  1097. snprintf(buf, sizeof(buf), "%ld", PGG(num_persistent));
  1098. php_info_print_table_row(2, "Active Persistent Links", buf);
  1099. snprintf(buf, sizeof(buf), "%ld", PGG(num_links));
  1100. php_info_print_table_row(2, "Active Links", buf);
  1101. php_info_print_table_end();
  1102. DISPLAY_INI_ENTRIES();
  1103. }
  1104. /* }}} */
  1105. /* {{{ php_pgsql_do_connect
  1106. */
  1107. static void php_pgsql_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent)
  1108. {
  1109. char *host=NULL,*port=NULL,*options=NULL,*tty=NULL,*dbname=NULL,*connstring=NULL;
  1110. PGconn *pgsql;
  1111. smart_str str = {0};
  1112. zval **args[5];
  1113. int i, connect_type = 0;
  1114. PGresult *pg_result;
  1115. if (ZEND_NUM_ARGS() < 1 || ZEND_NUM_ARGS() > 5
  1116. || zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args) == FAILURE) {
  1117. WRONG_PARAM_COUNT;
  1118. }
  1119. smart_str_appends(&str, "pgsql");
  1120. for (i = 0; i < ZEND_NUM_ARGS(); i++) {
  1121. /* make sure that the PGSQL_CONNECT_FORCE_NEW bit is not part of the hash so that subsequent connections
  1122. * can re-use this connection. Bug #39979
  1123. */
  1124. if (i == 1 && ZEND_NUM_ARGS() == 2 && Z_TYPE_PP(args[i]) == IS_LONG) {
  1125. if (Z_LVAL_PP(args[1]) == PGSQL_CONNECT_FORCE_NEW) {
  1126. continue;
  1127. } else if (Z_LVAL_PP(args[1]) & PGSQL_CONNECT_FORCE_NEW) {
  1128. smart_str_append_long(&str, Z_LVAL_PP(args[1]) ^ PGSQL_CONNECT_FORCE_NEW);
  1129. }
  1130. }
  1131. convert_to_string_ex(args[i]);
  1132. smart_str_appendc(&str, '_');
  1133. smart_str_appendl(&str, Z_STRVAL_PP(args[i]), Z_STRLEN_PP(args[i]));
  1134. }
  1135. smart_str_0(&str);
  1136. if (ZEND_NUM_ARGS() == 1) { /* new style, using connection string */
  1137. connstring = Z_STRVAL_PP(args[0]);
  1138. } else if (ZEND_NUM_ARGS() == 2 ) { /* Safe to add conntype_option, since 2 args was illegal */
  1139. connstring = Z_STRVAL_PP(args[0]);
  1140. convert_to_long_ex(args[1]);
  1141. connect_type = Z_LVAL_PP(args[1]);
  1142. } else {
  1143. host = Z_STRVAL_PP(args[0]);
  1144. port = Z_STRVAL_PP(args[1]);
  1145. dbname = Z_STRVAL_PP(args[ZEND_NUM_ARGS()-1]);
  1146. switch (ZEND_NUM_ARGS()) {
  1147. case 5:
  1148. tty = Z_STRVAL_PP(args[3]);
  1149. /* fall through */
  1150. case 4:
  1151. options = Z_STRVAL_PP(args[2]);
  1152. break;
  1153. }
  1154. }
  1155. if (persistent && PGG(allow_persistent)) {
  1156. zend_rsrc_list_entry *le;
  1157. /* try to find if we already have this link in our persistent list */
  1158. if (zend_hash_find(&EG(persistent_list), str.c, str.len+1, (void **) &le)==FAILURE) { /* we don't */
  1159. zend_rsrc_list_entry new_le;
  1160. if (PGG(max_links)!=-1 && PGG(num_links)>=PGG(max_links)) {
  1161. php_error_docref(NULL TSRMLS_CC, E_WARNING,
  1162. "Cannot create new link. Too many open links (%ld)", PGG(num_links));
  1163. goto err;
  1164. }
  1165. if (PGG(max_persistent)!=-1 && PGG(num_persistent)>=PGG(max_persistent)) {
  1166. php_error_docref(NULL TSRMLS_CC, E_WARNING,
  1167. "Cannot create new link. Too many open persistent links (%ld)", PGG(num_persistent));
  1168. goto err;
  1169. }
  1170. /* create the link */
  1171. if (connstring) {
  1172. pgsql=PQconnectdb(connstring);
  1173. } else {
  1174. pgsql=PQsetdb(host,port,options,tty,dbname);
  1175. }
  1176. if (pgsql==NULL || PQstatus(pgsql)==CONNECTION_BAD) {
  1177. PHP_PQ_ERROR("Unable to connect to PostgreSQL server: %s", pgsql)
  1178. if (pgsql) {
  1179. PQfinish(pgsql);
  1180. }
  1181. goto err;
  1182. }
  1183. /* hash it up */
  1184. Z_TYPE(new_le) = le_plink;
  1185. new_le.ptr = pgsql;
  1186. if (zend_hash_update(&EG(persistent_list), str.c, str.len+1, (void *) &new_le, sizeof(zend_rsrc_list_entry), NULL)==FAILURE) {
  1187. goto err;
  1188. }
  1189. PGG(num_links)++;
  1190. PGG(num_persistent)++;
  1191. } else { /* we do */
  1192. if (Z_TYPE_P(le) != le_plink) {
  1193. RETURN_FALSE;
  1194. }
  1195. /* ensure that the link did not die */
  1196. if (PGG(auto_reset_persistent) & 1) {
  1197. /* need to send & get something from backend to
  1198. make sure we catch CONNECTION_BAD every time */
  1199. PGresult *pg_result;
  1200. pg_result = PQexec(le->ptr, "select 1");
  1201. PQclear(pg_result);
  1202. }
  1203. if (PQstatus(le->ptr)==CONNECTION_BAD) { /* the link died */
  1204. if (le->ptr == NULL) {
  1205. if (connstring) {
  1206. le->ptr=PQconnectdb(connstring);
  1207. } else {
  1208. le->ptr=PQsetdb(host,port,options,tty,dbname);
  1209. }
  1210. }
  1211. else {
  1212. PQreset(le->ptr);
  1213. }
  1214. if (le->ptr==NULL || PQstatus(le->ptr)==CONNECTION_BAD) {
  1215. php_error_docref(NULL TSRMLS_CC, E_WARNING,"PostgreSQL link lost, unable to reconnect");
  1216. zend_hash_del(&EG(persistent_list),str.c,str.len+1);
  1217. goto err;
  1218. }
  1219. }
  1220. pgsql = (PGconn *) le->ptr;
  1221. #if HAVE_PQPROTOCOLVERSION && HAVE_PQPARAMETERSTATUS
  1222. if (PQprotocolVersion(pgsql) >= 3 && atof(PQparameterStatus(pgsql, "server_version")) >= 7.2) {
  1223. #else
  1224. if (atof(PG_VERSION) >= 7.2) {
  1225. #endif
  1226. pg_result = PQexec(pgsql, "RESET ALL;");
  1227. PQclear(pg_result);
  1228. }
  1229. }
  1230. ZEND_REGISTER_RESOURCE(return_value, pgsql, le_plink);
  1231. } else { /* Non persistent connection */
  1232. zend_rsrc_list_entry *index_ptr,new_index_ptr;
  1233. /* first we check the hash for the hashed_details key. if it exists,
  1234. * it should point us to the right offset where the actual pgsql link sits.
  1235. * if it doesn't, open a new pgsql link, add it to the resource list,
  1236. * and add a pointer to it with hashed_details as the key.
  1237. */
  1238. if (!(connect_type & PGSQL_CONNECT_FORCE_NEW)
  1239. && zend_hash_find(&EG(regular_list),str.c,str.len+1,(void **) &index_ptr)==SUCCESS) {
  1240. int type;
  1241. ulong link;
  1242. void *ptr;
  1243. if (Z_TYPE_P(index_ptr) != le_index_ptr) {
  1244. RETURN_FALSE;
  1245. }
  1246. link = (ulong) index_ptr->ptr;
  1247. ptr = zend_list_find(link,&type); /* check if the link is still there */
  1248. if (ptr && (type==le_link || type==le_plink)) {
  1249. Z_LVAL_P(return_value) = link;
  1250. zend_list_addref(link);
  1251. php_pgsql_set_default_link(link TSRMLS_CC);
  1252. Z_TYPE_P(return_value) = IS_RESOURCE;
  1253. goto cleanup;
  1254. } else {
  1255. zend_hash_del(&EG(regular_list),str.c,str.len+1);
  1256. }
  1257. }
  1258. if (PGG(max_links)!=-1 && PGG(num_links)>=PGG(max_links)) {
  1259. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot create new link. Too many open links (%ld)", PGG(num_links));
  1260. goto err;
  1261. }
  1262. /* Non-blocking connect */
  1263. if (connect_type & PGSQL_CONNECT_ASYNC) {
  1264. if (connstring) {
  1265. pgsql = PQconnectStart(connstring);
  1266. if (pgsql==NULL || PQstatus(pgsql)==CONNECTION_BAD) {
  1267. PHP_PQ_ERROR("Unable to connect to PostgreSQL server: %s", pgsql);
  1268. if (pgsql) {
  1269. PQfinish(pgsql);
  1270. }
  1271. goto err;
  1272. }
  1273. } else {
  1274. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Connection string required for async connections");
  1275. goto err;
  1276. }
  1277. } else {
  1278. if (connstring) {
  1279. pgsql = PQconnectdb(connstring);
  1280. } else {
  1281. pgsql = PQsetdb(host,port,options,tty,dbname);
  1282. }
  1283. if (pgsql==NULL || PQstatus(pgsql)==CONNECTION_BAD) {
  1284. PHP_PQ_ERROR("Unable to connect to PostgreSQL server: %s", pgsql);
  1285. if (pgsql) {
  1286. PQfinish(pgsql);
  1287. }
  1288. goto err;
  1289. }
  1290. }
  1291. /* add it to the list */
  1292. ZEND_REGISTER_RESOURCE(return_value, pgsql, le_link);
  1293. /* add it to the hash */
  1294. new_index_ptr.ptr = (void *) Z_LVAL_P(return_value);
  1295. Z_TYPE(new_index_ptr) = le_index_ptr;
  1296. if (zend_hash_update(&EG(regular_list),str.c,str.len+1,(void *) &new_index_ptr, sizeof(zend_rsrc_list_entry), NULL)==FAILURE) {
  1297. goto err;
  1298. }
  1299. PGG(num_links)++;
  1300. }
  1301. /* set notice processor */
  1302. if (! PGG(ignore_notices) && Z_TYPE_P(return_value) == IS_RESOURCE) {
  1303. PQsetNoticeProcessor(pgsql, _php_pgsql_notice_handler, (void*)Z_RESVAL_P(return_value));
  1304. }
  1305. php_pgsql_set_default_link(Z_LVAL_P(return_value) TSRMLS_CC);
  1306. cleanup:
  1307. smart_str_free(&str);
  1308. return;
  1309. err:
  1310. smart_str_free(&str);
  1311. RETURN_FALSE;
  1312. }
  1313. /* }}} */
  1314. #if 0
  1315. /* {{{ php_pgsql_get_default_link
  1316. */
  1317. static int php_pgsql_get_default_link(INTERNAL_FUNCTION_PARAMETERS)
  1318. {
  1319. if (PGG(default_link)==-1) { /* no link opened yet, implicitly open one */
  1320. ht = 0;
  1321. php_pgsql_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU,0);
  1322. }
  1323. return PGG(default_link);
  1324. }
  1325. /* }}} */
  1326. #endif
  1327. /* {{{ proto resource pg_connect(string connection_string[, int connect_type] | [string host, string port [, string options [, string tty,]]] string database)
  1328. Open a PostgreSQL connection */
  1329. PHP_FUNCTION(pg_connect)
  1330. {
  1331. php_pgsql_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU,0);
  1332. }
  1333. /* }}} */
  1334. /* {{{ proto resource pg_connect_poll(resource connection)
  1335. Poll the status of an in-progress async PostgreSQL connection attempt*/
  1336. PHP_FUNCTION(pg_connect_poll)
  1337. {
  1338. zval *pgsql_link;
  1339. int id = -1;
  1340. PGconn *pgsql;
  1341. int ret;
  1342. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pgsql_link) == FAILURE) {
  1343. return;
  1344. }
  1345. if (pgsql_link == NULL && id == -1) {
  1346. RETURN_FALSE;
  1347. }
  1348. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  1349. ret = PQconnectPoll(pgsql);
  1350. RETURN_LONG(ret);
  1351. }
  1352. /* }}} */
  1353. /* {{{ proto resource pg_pconnect(string connection_string | [string host, string port [, string options [, string tty,]]] string database)
  1354. Open a persistent PostgreSQL connection */
  1355. PHP_FUNCTION(pg_pconnect)
  1356. {
  1357. php_pgsql_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU,1);
  1358. }
  1359. /* }}} */
  1360. /* {{{ proto bool pg_close([resource connection])
  1361. Close a PostgreSQL connection */
  1362. PHP_FUNCTION(pg_close)
  1363. {
  1364. zval *pgsql_link = NULL;
  1365. int id = -1, argc = ZEND_NUM_ARGS();
  1366. PGconn *pgsql;
  1367. if (zend_parse_parameters(argc TSRMLS_CC, "|r", &pgsql_link) == FAILURE) {
  1368. return;
  1369. }
  1370. if (argc == 0) {
  1371. id = PGG(default_link);
  1372. CHECK_DEFAULT_LINK(id);
  1373. }
  1374. if (pgsql_link == NULL && id == -1) {
  1375. RETURN_FALSE;
  1376. }
  1377. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  1378. if (id==-1) { /* explicit resource number */
  1379. zend_list_delete(Z_RESVAL_P(pgsql_link));
  1380. }
  1381. if (id!=-1
  1382. || (pgsql_link && Z_RESVAL_P(pgsql_link)==PGG(default_link))) {
  1383. zend_list_delete(PGG(default_link));
  1384. PGG(default_link) = -1;
  1385. }
  1386. RETURN_TRUE;
  1387. }
  1388. /* }}} */
  1389. #define PHP_PG_DBNAME 1
  1390. #define PHP_PG_ERROR_MESSAGE 2
  1391. #define PHP_PG_OPTIONS 3
  1392. #define PHP_PG_PORT 4
  1393. #define PHP_PG_TTY 5
  1394. #define PHP_PG_HOST 6
  1395. #define PHP_PG_VERSION 7
  1396. /* {{{ php_pgsql_get_link_info
  1397. */
  1398. static void php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type)
  1399. {
  1400. zval *pgsql_link = NULL;
  1401. int id = -1, argc = ZEND_NUM_ARGS();
  1402. PGconn *pgsql;
  1403. char *msgbuf;
  1404. if (zend_parse_parameters(argc TSRMLS_CC, "|r", &pgsql_link) == FAILURE) {
  1405. return;
  1406. }
  1407. if (argc == 0) {
  1408. id = PGG(default_link);
  1409. CHECK_DEFAULT_LINK(id);
  1410. }
  1411. if (pgsql_link == NULL && id == -1) {
  1412. RETURN_FALSE;
  1413. }
  1414. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  1415. switch(entry_type) {
  1416. case PHP_PG_DBNAME:
  1417. Z_STRVAL_P(return_value) = PQdb(pgsql);
  1418. break;
  1419. case PHP_PG_ERROR_MESSAGE:
  1420. RETURN_STRING(PQErrorMessageTrim(pgsql, &msgbuf), 0);
  1421. return;
  1422. case PHP_PG_OPTIONS:
  1423. Z_STRVAL_P(return_value) = PQoptions(pgsql);
  1424. break;
  1425. case PHP_PG_PORT:
  1426. Z_STRVAL_P(return_value) = PQport(pgsql);
  1427. break;
  1428. case PHP_PG_TTY:
  1429. Z_STRVAL_P(return_value) = PQtty(pgsql);
  1430. break;
  1431. case PHP_PG_HOST:
  1432. Z_STRVAL_P(return_value) = PQhost(pgsql);
  1433. break;
  1434. case PHP_PG_VERSION:
  1435. array_init(return_value);
  1436. add_assoc_string(return_value, "client", PG_VERSION, 1);
  1437. #if HAVE_PQPROTOCOLVERSION
  1438. add_assoc_long(return_value, "protocol", PQprotocolVersion(pgsql));
  1439. #if HAVE_PQPARAMETERSTATUS
  1440. if (PQprotocolVersion(pgsql) >= 3) {
  1441. /* 8.0 or grater supports protorol version 3 */
  1442. char *tmp;
  1443. add_assoc_string(return_value, "server", (char*)PQparameterStatus(pgsql, "server_version"), 1);
  1444. tmp = (char*)PQparameterStatus(pgsql, "server_encoding");
  1445. add_assoc_string(return_value, "server_encoding", tmp, 1);
  1446. tmp = (char*)PQparameterStatus(pgsql, "client_encoding");
  1447. add_assoc_string(return_value, "client_encoding", tmp, 1);
  1448. tmp = (char*)PQparameterStatus(pgsql, "is_superuser");
  1449. add_assoc_string(return_value, "is_superuser", tmp, 1);
  1450. tmp = (char*)PQparameterStatus(pgsql, "session_authorization");
  1451. add_assoc_string(return_value, "session_authorization", tmp, 1);
  1452. tmp = (char*)PQparameterStatus(pgsql, "DateStyle");
  1453. add_assoc_string(return_value, "DateStyle", tmp, 1);
  1454. tmp = (char*)PQparameterStatus(pgsql, "IntervalStyle");
  1455. add_assoc_string(return_value, "IntervalStyle", tmp ? tmp : "", 1);
  1456. tmp = (char*)PQparameterStatus(pgsql, "TimeZone");
  1457. add_assoc_string(return_value, "TimeZone", tmp ? tmp : "", 1);
  1458. tmp = (char*)PQparameterStatus(pgsql, "integer_datetimes");
  1459. add_assoc_string(return_value, "integer_datetimes", tmp ? tmp : "", 1);
  1460. tmp = (char*)PQparameterStatus(pgsql, "standard_conforming_strings");
  1461. add_assoc_string(return_value, "standard_conforming_strings", tmp ? tmp : "", 1);
  1462. tmp = (char*)PQparameterStatus(pgsql, "application_name");
  1463. add_assoc_string(return_value, "application_name", tmp ? tmp : "", 1);
  1464. }
  1465. #endif
  1466. #endif
  1467. return;
  1468. default:
  1469. RETURN_FALSE;
  1470. }
  1471. if (Z_STRVAL_P(return_value)) {
  1472. Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
  1473. Z_STRVAL_P(return_value) = (char *) estrdup(Z_STRVAL_P(return_value));
  1474. } else {
  1475. Z_STRLEN_P(return_value) = 0;
  1476. Z_STRVAL_P(return_value) = (char *) estrdup("");
  1477. }
  1478. Z_TYPE_P(return_value) = IS_STRING;
  1479. }
  1480. /* }}} */
  1481. /* {{{ proto string pg_dbname([resource connection])
  1482. Get the database name */
  1483. PHP_FUNCTION(pg_dbname)
  1484. {
  1485. php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_DBNAME);
  1486. }
  1487. /* }}} */
  1488. /* {{{ proto string pg_last_error([resource connection])
  1489. Get the error message string */
  1490. PHP_FUNCTION(pg_last_error)
  1491. {
  1492. php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_ERROR_MESSAGE);
  1493. }
  1494. /* }}} */
  1495. /* {{{ proto string pg_options([resource connection])
  1496. Get the options associated with the connection */
  1497. PHP_FUNCTION(pg_options)
  1498. {
  1499. php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_OPTIONS);
  1500. }
  1501. /* }}} */
  1502. /* {{{ proto int pg_port([resource connection])
  1503. Return the port number associated with the connection */
  1504. PHP_FUNCTION(pg_port)
  1505. {
  1506. php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_PORT);
  1507. }
  1508. /* }}} */
  1509. /* {{{ proto string pg_tty([resource connection])
  1510. Return the tty name associated with the connection */
  1511. PHP_FUNCTION(pg_tty)
  1512. {
  1513. php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_TTY);
  1514. }
  1515. /* }}} */
  1516. /* {{{ proto string pg_host([resource connection])
  1517. Returns the host name associated with the connection */
  1518. PHP_FUNCTION(pg_host)
  1519. {
  1520. php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_HOST);
  1521. }
  1522. /* }}} */
  1523. /* {{{ proto array pg_version([resource connection])
  1524. Returns an array with client, protocol and server version (when available) */
  1525. PHP_FUNCTION(pg_version)
  1526. {
  1527. php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_VERSION);
  1528. }
  1529. /* }}} */
  1530. #if HAVE_PQPARAMETERSTATUS
  1531. /* {{{ proto string|false pg_parameter_status([resource connection,] string param_name)
  1532. Returns the value of a server parameter */
  1533. PHP_FUNCTION(pg_parameter_status)
  1534. {
  1535. zval *pgsql_link;
  1536. int id;
  1537. PGconn *pgsql;
  1538. char *param;
  1539. int len;
  1540. if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "rs", &pgsql_link, &param, &len) == SUCCESS) {
  1541. id = -1;
  1542. } else if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &param, &len) == SUCCESS) {
  1543. pgsql_link = NULL;
  1544. id = PGG(default_link);
  1545. } else {
  1546. RETURN_FALSE;
  1547. }
  1548. if (pgsql_link == NULL && id == -1) {
  1549. RETURN_FALSE;
  1550. }
  1551. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  1552. param = (char*)PQparameterStatus(pgsql, param);
  1553. if (param) {
  1554. RETURN_STRING(param, 1);
  1555. } else {
  1556. RETURN_FALSE;
  1557. }
  1558. }
  1559. /* }}} */
  1560. #endif
  1561. /* {{{ proto bool pg_ping([resource connection])
  1562. Ping database. If connection is bad, try to reconnect. */
  1563. PHP_FUNCTION(pg_ping)
  1564. {
  1565. zval *pgsql_link;
  1566. int id;
  1567. PGconn *pgsql;
  1568. PGresult *res;
  1569. if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r", &pgsql_link) == SUCCESS) {
  1570. id = -1;
  1571. } else {
  1572. pgsql_link = NULL;
  1573. id = PGG(default_link);
  1574. }
  1575. if (pgsql_link == NULL && id == -1) {
  1576. RETURN_FALSE;
  1577. }
  1578. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  1579. /* ping connection */
  1580. res = PQexec(pgsql, "SELECT 1;");
  1581. PQclear(res);
  1582. /* check status. */
  1583. if (PQstatus(pgsql) == CONNECTION_OK)
  1584. RETURN_TRUE;
  1585. /* reset connection if it's broken */
  1586. PQreset(pgsql);
  1587. if (PQstatus(pgsql) == CONNECTION_OK) {
  1588. RETURN_TRUE;
  1589. }
  1590. RETURN_FALSE;
  1591. }
  1592. /* }}} */
  1593. /* {{{ proto resource pg_query([resource connection,] string query)
  1594. Execute a query */
  1595. PHP_FUNCTION(pg_query)
  1596. {
  1597. zval *pgsql_link = NULL;
  1598. char *query;
  1599. int id = -1, query_len, argc = ZEND_NUM_ARGS();
  1600. int leftover = 0;
  1601. PGconn *pgsql;
  1602. PGresult *pgsql_result;
  1603. ExecStatusType status;
  1604. pgsql_result_handle *pg_result;
  1605. if (argc == 1) {
  1606. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &query, &query_len) == FAILURE) {
  1607. return;
  1608. }
  1609. id = PGG(default_link);
  1610. CHECK_DEFAULT_LINK(id);
  1611. } else {
  1612. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &pgsql_link, &query, &query_len) == FAILURE) {
  1613. return;
  1614. }
  1615. }
  1616. if (pgsql_link == NULL && id == -1) {
  1617. RETURN_FALSE;
  1618. }
  1619. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  1620. if (PQ_SETNONBLOCKING(pgsql, 0)) {
  1621. php_error_docref(NULL TSRMLS_CC, E_NOTICE,"Cannot set connection to blocking mode");
  1622. RETURN_FALSE;
  1623. }
  1624. while ((pgsql_result = PQgetResult(pgsql))) {
  1625. PQclear(pgsql_result);
  1626. leftover = 1;
  1627. }
  1628. if (leftover) {
  1629. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Found results on this connection. Use pg_get_result() to get these results first");
  1630. }
  1631. pgsql_result = PQexec(pgsql, query);
  1632. if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
  1633. PQclear(pgsql_result);
  1634. PQreset(pgsql);
  1635. pgsql_result = PQexec(pgsql, query);
  1636. }
  1637. if (pgsql_result) {
  1638. status = PQresultStatus(pgsql_result);
  1639. } else {
  1640. status = (ExecStatusType) PQstatus(pgsql);
  1641. }
  1642. switch (status) {
  1643. case PGRES_EMPTY_QUERY:
  1644. case PGRES_BAD_RESPONSE:
  1645. case PGRES_NONFATAL_ERROR:
  1646. case PGRES_FATAL_ERROR:
  1647. PHP_PQ_ERROR("Query failed: %s", pgsql);
  1648. PQclear(pgsql_result);
  1649. RETURN_FALSE;
  1650. break;
  1651. case PGRES_COMMAND_OK: /* successful command that did not return rows */
  1652. default:
  1653. if (pgsql_result) {
  1654. pg_result = (pgsql_result_handle *) emalloc(sizeof(pgsql_result_handle));
  1655. pg_result->conn = pgsql;
  1656. pg_result->result = pgsql_result;
  1657. pg_result->row = 0;
  1658. ZEND_REGISTER_RESOURCE(return_value, pg_result, le_result);
  1659. } else {
  1660. PQclear(pgsql_result);
  1661. RETURN_FALSE;
  1662. }
  1663. break;
  1664. }
  1665. }
  1666. /* }}} */
  1667. #if HAVE_PQEXECPARAMS || HAVE_PQEXECPREPARED || HAVE_PQSENDQUERYPARAMS || HAVE_PQSENDQUERYPREPARED
  1668. /* {{{ _php_pgsql_free_params */
  1669. static void _php_pgsql_free_params(char **params, int num_params)
  1670. {
  1671. if (num_params > 0) {
  1672. int i;
  1673. for (i = 0; i < num_params; i++) {
  1674. if (params[i]) {
  1675. efree(params[i]);
  1676. }
  1677. }
  1678. efree(params);
  1679. }
  1680. }
  1681. /* }}} */
  1682. #endif
  1683. #if HAVE_PQEXECPARAMS
  1684. /* {{{ proto resource pg_query_params([resource connection,] string query, array params)
  1685. Execute a query */
  1686. PHP_FUNCTION(pg_query_params)
  1687. {
  1688. zval *pgsql_link = NULL;
  1689. zval *pv_param_arr, **tmp;
  1690. char *query;
  1691. int query_len, id = -1, argc = ZEND_NUM_ARGS();
  1692. int leftover = 0;
  1693. int num_params = 0;
  1694. char **params = NULL;
  1695. PGconn *pgsql;
  1696. PGresult *pgsql_result;
  1697. ExecStatusType status;
  1698. pgsql_result_handle *pg_result;
  1699. if (argc == 2) {
  1700. if (zend_parse_parameters(argc TSRMLS_CC, "sa", &query, &query_len, &pv_param_arr) == FAILURE) {
  1701. return;
  1702. }
  1703. id = PGG(default_link);
  1704. CHECK_DEFAULT_LINK(id);
  1705. } else {
  1706. if (zend_parse_parameters(argc TSRMLS_CC, "rsa", &pgsql_link, &query, &query_len, &pv_param_arr) == FAILURE) {
  1707. return;
  1708. }
  1709. }
  1710. if (pgsql_link == NULL && id == -1) {
  1711. RETURN_FALSE;
  1712. }
  1713. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  1714. if (PQ_SETNONBLOCKING(pgsql, 0)) {
  1715. php_error_docref(NULL TSRMLS_CC, E_NOTICE,"Cannot set connection to blocking mode");
  1716. RETURN_FALSE;
  1717. }
  1718. while ((pgsql_result = PQgetResult(pgsql))) {
  1719. PQclear(pgsql_result);
  1720. leftover = 1;
  1721. }
  1722. if (leftover) {
  1723. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Found results on this connection. Use pg_get_result() to get these results first");
  1724. }
  1725. zend_hash_internal_pointer_reset(Z_ARRVAL_P(pv_param_arr));
  1726. num_params = zend_hash_num_elements(Z_ARRVAL_P(pv_param_arr));
  1727. if (num_params > 0) {
  1728. int i = 0;
  1729. params = (char **)safe_emalloc(sizeof(char *), num_params, 0);
  1730. for(i = 0; i < num_params; i++) {
  1731. if (zend_hash_get_current_data(Z_ARRVAL_P(pv_param_arr), (void **) &tmp) == FAILURE) {
  1732. php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error getting parameter");
  1733. _php_pgsql_free_params(params, num_params);
  1734. RETURN_FALSE;
  1735. }
  1736. if (Z_TYPE_PP(tmp) == IS_NULL) {
  1737. params[i] = NULL;
  1738. } else {
  1739. zval tmp_val = **tmp;
  1740. zval_copy_ctor(&tmp_val);
  1741. convert_to_cstring(&tmp_val);
  1742. if (Z_TYPE(tmp_val) != IS_STRING) {
  1743. php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error converting parameter");
  1744. zval_dtor(&tmp_val);
  1745. _php_pgsql_free_params(params, num_params);
  1746. RETURN_FALSE;
  1747. }
  1748. params[i] = estrndup(Z_STRVAL(tmp_val), Z_STRLEN(tmp_val));
  1749. zval_dtor(&tmp_val);
  1750. }
  1751. zend_hash_move_forward(Z_ARRVAL_P(pv_param_arr));
  1752. }
  1753. }
  1754. pgsql_result = PQexecParams(pgsql, query, num_params,
  1755. NULL, (const char * const *)params, NULL, NULL, 0);
  1756. if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
  1757. PQclear(pgsql_result);
  1758. PQreset(pgsql);
  1759. pgsql_result = PQexecParams(pgsql, query, num_params,
  1760. NULL, (const char * const *)params, NULL, NULL, 0);
  1761. }
  1762. if (pgsql_result) {
  1763. status = PQresultStatus(pgsql_result);
  1764. } else {
  1765. status = (ExecStatusType) PQstatus(pgsql);
  1766. }
  1767. _php_pgsql_free_params(params, num_params);
  1768. switch (status) {
  1769. case PGRES_EMPTY_QUERY:
  1770. case PGRES_BAD_RESPONSE:
  1771. case PGRES_NONFATAL_ERROR:
  1772. case PGRES_FATAL_ERROR:
  1773. PHP_PQ_ERROR("Query failed: %s", pgsql);
  1774. PQclear(pgsql_result);
  1775. RETURN_FALSE;
  1776. break;
  1777. case PGRES_COMMAND_OK: /* successful command that did not return rows */
  1778. default:
  1779. if (pgsql_result) {
  1780. pg_result = (pgsql_result_handle *) emalloc(sizeof(pgsql_result_handle));
  1781. pg_result->conn = pgsql;
  1782. pg_result->result = pgsql_result;
  1783. pg_result->row = 0;
  1784. ZEND_REGISTER_RESOURCE(return_value, pg_result, le_result);
  1785. } else {
  1786. PQclear(pgsql_result);
  1787. RETURN_FALSE;
  1788. }
  1789. break;
  1790. }
  1791. }
  1792. /* }}} */
  1793. #endif
  1794. #if HAVE_PQPREPARE
  1795. /* {{{ proto resource pg_prepare([resource connection,] string stmtname, string query)
  1796. Prepare a query for future execution */
  1797. PHP_FUNCTION(pg_prepare)
  1798. {
  1799. zval *pgsql_link = NULL;
  1800. char *query, *stmtname;
  1801. int query_len, stmtname_len, id = -1, argc = ZEND_NUM_ARGS();
  1802. int leftover = 0;
  1803. PGconn *pgsql;
  1804. PGresult *pgsql_result;
  1805. ExecStatusType status;
  1806. pgsql_result_handle *pg_result;
  1807. if (argc == 2) {
  1808. if (zend_parse_parameters(argc TSRMLS_CC, "ss", &stmtname, &stmtname_len, &query, &query_len) == FAILURE) {
  1809. return;
  1810. }
  1811. id = PGG(default_link);
  1812. CHECK_DEFAULT_LINK(id);
  1813. } else {
  1814. if (zend_parse_parameters(argc TSRMLS_CC, "rss", &pgsql_link, &stmtname, &stmtname_len, &query, &query_len) == FAILURE) {
  1815. return;
  1816. }
  1817. }
  1818. if (pgsql_link == NULL && id == -1) {
  1819. RETURN_FALSE;
  1820. }
  1821. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  1822. if (PQ_SETNONBLOCKING(pgsql, 0)) {
  1823. php_error_docref(NULL TSRMLS_CC, E_NOTICE,"Cannot set connection to blocking mode");
  1824. RETURN_FALSE;
  1825. }
  1826. while ((pgsql_result = PQgetResult(pgsql))) {
  1827. PQclear(pgsql_result);
  1828. leftover = 1;
  1829. }
  1830. if (leftover) {
  1831. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Found results on this connection. Use pg_get_result() to get these results first");
  1832. }
  1833. pgsql_result = PQprepare(pgsql, stmtname, query, 0, NULL);
  1834. if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
  1835. PQclear(pgsql_result);
  1836. PQreset(pgsql);
  1837. pgsql_result = PQprepare(pgsql, stmtname, query, 0, NULL);
  1838. }
  1839. if (pgsql_result) {
  1840. status = PQresultStatus(pgsql_result);
  1841. } else {
  1842. status = (ExecStatusType) PQstatus(pgsql);
  1843. }
  1844. switch (status) {
  1845. case PGRES_EMPTY_QUERY:
  1846. case PGRES_BAD_RESPONSE:
  1847. case PGRES_NONFATAL_ERROR:
  1848. case PGRES_FATAL_ERROR:
  1849. PHP_PQ_ERROR("Query failed: %s", pgsql);
  1850. PQclear(pgsql_result);
  1851. RETURN_FALSE;
  1852. break;
  1853. case PGRES_COMMAND_OK: /* successful command that did not return rows */
  1854. default:
  1855. if (pgsql_result) {
  1856. pg_result = (pgsql_result_handle *) emalloc(sizeof(pgsql_result_handle));
  1857. pg_result->conn = pgsql;
  1858. pg_result->result = pgsql_result;
  1859. pg_result->row = 0;
  1860. ZEND_REGISTER_RESOURCE(return_value, pg_result, le_result);
  1861. } else {
  1862. PQclear(pgsql_result);
  1863. RETURN_FALSE;
  1864. }
  1865. break;
  1866. }
  1867. }
  1868. /* }}} */
  1869. #endif
  1870. #if HAVE_PQEXECPREPARED
  1871. /* {{{ proto resource pg_execute([resource connection,] string stmtname, array params)
  1872. Execute a prepared query */
  1873. PHP_FUNCTION(pg_execute)
  1874. {
  1875. zval *pgsql_link = NULL;
  1876. zval *pv_param_arr, **tmp;
  1877. char *stmtname;
  1878. int stmtname_len, id = -1, argc = ZEND_NUM_ARGS();
  1879. int leftover = 0;
  1880. int num_params = 0;
  1881. char **params = NULL;
  1882. PGconn *pgsql;
  1883. PGresult *pgsql_result;
  1884. ExecStatusType status;
  1885. pgsql_result_handle *pg_result;
  1886. if (argc == 2) {
  1887. if (zend_parse_parameters(argc TSRMLS_CC, "sa/", &stmtname, &stmtname_len, &pv_param_arr)==FAILURE) {
  1888. return;
  1889. }
  1890. id = PGG(default_link);
  1891. CHECK_DEFAULT_LINK(id);
  1892. } else {
  1893. if (zend_parse_parameters(argc TSRMLS_CC, "rsa/", &pgsql_link, &stmtname, &stmtname_len, &pv_param_arr) == FAILURE) {
  1894. return;
  1895. }
  1896. }
  1897. if (pgsql_link == NULL && id == -1) {
  1898. RETURN_FALSE;
  1899. }
  1900. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  1901. if (PQ_SETNONBLOCKING(pgsql, 0)) {
  1902. php_error_docref(NULL TSRMLS_CC, E_NOTICE,"Cannot set connection to blocking mode");
  1903. RETURN_FALSE;
  1904. }
  1905. while ((pgsql_result = PQgetResult(pgsql))) {
  1906. PQclear(pgsql_result);
  1907. leftover = 1;
  1908. }
  1909. if (leftover) {
  1910. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Found results on this connection. Use pg_get_result() to get these results first");
  1911. }
  1912. zend_hash_internal_pointer_reset(Z_ARRVAL_P(pv_param_arr));
  1913. num_params = zend_hash_num_elements(Z_ARRVAL_P(pv_param_arr));
  1914. if (num_params > 0) {
  1915. int i = 0;
  1916. params = (char **)safe_emalloc(sizeof(char *), num_params, 0);
  1917. for(i = 0; i < num_params; i++) {
  1918. if (zend_hash_get_current_data(Z_ARRVAL_P(pv_param_arr), (void **) &tmp) == FAILURE) {
  1919. php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error getting parameter");
  1920. _php_pgsql_free_params(params, num_params);
  1921. RETURN_FALSE;
  1922. }
  1923. if (Z_TYPE_PP(tmp) == IS_NULL) {
  1924. params[i] = NULL;
  1925. } else {
  1926. zval tmp_val = **tmp;
  1927. zval_copy_ctor(&tmp_val);
  1928. convert_to_string(&tmp_val);
  1929. if (Z_TYPE(tmp_val) != IS_STRING) {
  1930. php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error converting parameter");
  1931. zval_dtor(&tmp_val);
  1932. _php_pgsql_free_params(params, num_params);
  1933. RETURN_FALSE;
  1934. }
  1935. params[i] = estrndup(Z_STRVAL(tmp_val), Z_STRLEN(tmp_val));
  1936. zval_dtor(&tmp_val);
  1937. }
  1938. zend_hash_move_forward(Z_ARRVAL_P(pv_param_arr));
  1939. }
  1940. }
  1941. pgsql_result = PQexecPrepared(pgsql, stmtname, num_params,
  1942. (const char * const *)params, NULL, NULL, 0);
  1943. if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
  1944. PQclear(pgsql_result);
  1945. PQreset(pgsql);
  1946. pgsql_result = PQexecPrepared(pgsql, stmtname, num_params,
  1947. (const char * const *)params, NULL, NULL, 0);
  1948. }
  1949. if (pgsql_result) {
  1950. status = PQresultStatus(pgsql_result);
  1951. } else {
  1952. status = (ExecStatusType) PQstatus(pgsql);
  1953. }
  1954. _php_pgsql_free_params(params, num_params);
  1955. switch (status) {
  1956. case PGRES_EMPTY_QUERY:
  1957. case PGRES_BAD_RESPONSE:
  1958. case PGRES_NONFATAL_ERROR:
  1959. case PGRES_FATAL_ERROR:
  1960. PHP_PQ_ERROR("Query failed: %s", pgsql);
  1961. PQclear(pgsql_result);
  1962. RETURN_FALSE;
  1963. break;
  1964. case PGRES_COMMAND_OK: /* successful command that did not return rows */
  1965. default:
  1966. if (pgsql_result) {
  1967. pg_result = (pgsql_result_handle *) emalloc(sizeof(pgsql_result_handle));
  1968. pg_result->conn = pgsql;
  1969. pg_result->result = pgsql_result;
  1970. pg_result->row = 0;
  1971. ZEND_REGISTER_RESOURCE(return_value, pg_result, le_result);
  1972. } else {
  1973. PQclear(pgsql_result);
  1974. RETURN_FALSE;
  1975. }
  1976. break;
  1977. }
  1978. }
  1979. /* }}} */
  1980. #endif
  1981. #define PHP_PG_NUM_ROWS 1
  1982. #define PHP_PG_NUM_FIELDS 2
  1983. #define PHP_PG_CMD_TUPLES 3
  1984. /* {{{ php_pgsql_get_result_info
  1985. */
  1986. static void php_pgsql_get_result_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type)
  1987. {
  1988. zval *result;
  1989. PGresult *pgsql_result;
  1990. pgsql_result_handle *pg_result;
  1991. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &result) == FAILURE) {
  1992. return;
  1993. }
  1994. ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result);
  1995. pgsql_result = pg_result->result;
  1996. switch (entry_type) {
  1997. case PHP_PG_NUM_ROWS:
  1998. Z_LVAL_P(return_value) = PQntuples(pgsql_result);
  1999. break;
  2000. case PHP_PG_NUM_FIELDS:
  2001. Z_LVAL_P(return_value) = PQnfields(pgsql_result);
  2002. break;
  2003. case PHP_PG_CMD_TUPLES:
  2004. #if HAVE_PQCMDTUPLES
  2005. Z_LVAL_P(return_value) = atoi(PQcmdTuples(pgsql_result));
  2006. #else
  2007. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Not supported under this build");
  2008. Z_LVAL_P(return_value) = 0;
  2009. #endif
  2010. break;
  2011. default:
  2012. RETURN_FALSE;
  2013. }
  2014. Z_TYPE_P(return_value) = IS_LONG;
  2015. }
  2016. /* }}} */
  2017. /* {{{ proto int pg_num_rows(resource result)
  2018. Return the number of rows in the result */
  2019. PHP_FUNCTION(pg_num_rows)
  2020. {
  2021. php_pgsql_get_result_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_NUM_ROWS);
  2022. }
  2023. /* }}} */
  2024. /* {{{ proto int pg_num_fields(resource result)
  2025. Return the number of fields in the result */
  2026. PHP_FUNCTION(pg_num_fields)
  2027. {
  2028. php_pgsql_get_result_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_NUM_FIELDS);
  2029. }
  2030. /* }}} */
  2031. #if HAVE_PQCMDTUPLES
  2032. /* {{{ proto int pg_affected_rows(resource result)
  2033. Returns the number of affected tuples */
  2034. PHP_FUNCTION(pg_affected_rows)
  2035. {
  2036. php_pgsql_get_result_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_CMD_TUPLES);
  2037. }
  2038. /* }}} */
  2039. #endif
  2040. /* {{{ proto string pg_last_notice(resource connection)
  2041. Returns the last notice set by the backend */
  2042. PHP_FUNCTION(pg_last_notice)
  2043. {
  2044. zval *pgsql_link;
  2045. PGconn *pg_link;
  2046. int id = -1;
  2047. php_pgsql_notice **notice;
  2048. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pgsql_link) == FAILURE) {
  2049. return;
  2050. }
  2051. /* Just to check if user passed valid resoruce */
  2052. ZEND_FETCH_RESOURCE2(pg_link, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  2053. if (zend_hash_index_find(&PGG(notices), Z_RESVAL_P(pgsql_link), (void **)&notice) == FAILURE) {
  2054. RETURN_FALSE;
  2055. }
  2056. RETURN_STRINGL((*notice)->message, (*notice)->len, 1);
  2057. }
  2058. /* }}} */
  2059. /* {{{ get_field_name
  2060. */
  2061. static char *get_field_name(PGconn *pgsql, Oid oid, HashTable *list TSRMLS_DC)
  2062. {
  2063. PGresult *result;
  2064. smart_str str = {0};
  2065. zend_rsrc_list_entry *field_type;
  2066. char *ret=NULL;
  2067. /* try to lookup the type in the resource list */
  2068. smart_str_appends(&str, "pgsql_oid_");
  2069. smart_str_append_unsigned(&str, oid);
  2070. smart_str_0(&str);
  2071. if (zend_hash_find(list,str.c,str.len+1,(void **) &field_type)==SUCCESS) {
  2072. ret = estrdup((char *)field_type->ptr);
  2073. } else { /* hash all oid's */
  2074. int i,num_rows;
  2075. int oid_offset,name_offset;
  2076. char *tmp_oid, *end_ptr, *tmp_name;
  2077. zend_rsrc_list_entry new_oid_entry;
  2078. if ((result = PQexec(pgsql,"select oid,typname from pg_type")) == NULL || PQresultStatus(result) != PGRES_TUPLES_OK) {
  2079. if (result) {
  2080. PQclear(result);
  2081. }
  2082. smart_str_free(&str);
  2083. return STR_EMPTY_ALLOC();
  2084. }
  2085. num_rows = PQntuples(result);
  2086. oid_offset = PQfnumber(result,"oid");
  2087. name_offset = PQfnumber(result,"typname");
  2088. for (i=0; i<num_rows; i++) {
  2089. if ((tmp_oid = PQgetvalue(result,i,oid_offset))==NULL) {
  2090. continue;
  2091. }
  2092. str.len = 0;
  2093. smart_str_appends(&str, "pgsql_oid_");
  2094. smart_str_appends(&str, tmp_oid);
  2095. smart_str_0(&str);
  2096. if ((tmp_name = PQgetvalue(result,i,name_offset))==NULL) {
  2097. continue;
  2098. }
  2099. Z_TYPE(new_oid_entry) = le_string;
  2100. new_oid_entry.ptr = estrdup(tmp_name);
  2101. zend_hash_update(list,str.c,str.len+1,(void *) &new_oid_entry, sizeof(zend_rsrc_list_entry), NULL);
  2102. if (!ret && strtoul(tmp_oid, &end_ptr, 10)==oid) {
  2103. ret = estrdup(tmp_name);
  2104. }
  2105. }
  2106. PQclear(result);
  2107. }
  2108. smart_str_free(&str);
  2109. return ret;
  2110. }
  2111. /* }}} */
  2112. #ifdef HAVE_PQFTABLE
  2113. /* {{{ proto mixed pg_field_table(resource result, int field_number[, bool oid_only])
  2114. Returns the name of the table field belongs to, or table's oid if oid_only is true */
  2115. PHP_FUNCTION(pg_field_table)
  2116. {
  2117. zval *result;
  2118. pgsql_result_handle *pg_result;
  2119. long fnum = -1;
  2120. zend_bool return_oid = 0;
  2121. Oid oid;
  2122. smart_str hash_key = {0};
  2123. char *table_name;
  2124. zend_rsrc_list_entry *field_table;
  2125. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl|b", &result, &fnum, &return_oid) == FAILURE) {
  2126. return;
  2127. }
  2128. ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result);
  2129. if (fnum < 0 || fnum >= PQnfields(pg_result->result)) {
  2130. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad field offset specified");
  2131. RETURN_FALSE;
  2132. }
  2133. oid = PQftable(pg_result->result, fnum);
  2134. if (InvalidOid == oid) {
  2135. RETURN_FALSE;
  2136. }
  2137. if (return_oid) {
  2138. #if UINT_MAX > LONG_MAX /* Oid is unsigned int, we don't need this code, where LONG is wider */
  2139. if (oid > LONG_MAX) {
  2140. smart_str oidstr = {0};
  2141. smart_str_append_unsigned(&oidstr, oid);
  2142. smart_str_0(&oidstr);
  2143. RETURN_STRINGL(oidstr.c, oidstr.len, 0);
  2144. } else
  2145. #endif
  2146. RETURN_LONG((long)oid);
  2147. }
  2148. /* try to lookup the table name in the resource list */
  2149. smart_str_appends(&hash_key, "pgsql_table_oid_");
  2150. smart_str_append_unsigned(&hash_key, oid);
  2151. smart_str_0(&hash_key);
  2152. if (zend_hash_find(&EG(regular_list), hash_key.c, hash_key.len+1, (void **) &field_table) == SUCCESS) {
  2153. smart_str_free(&hash_key);
  2154. RETURN_STRING((char *)field_table->ptr, 1);
  2155. } else { /* Not found, lookup by querying PostgreSQL system tables */
  2156. PGresult *tmp_res;
  2157. smart_str querystr = {0};
  2158. zend_rsrc_list_entry new_field_table;
  2159. smart_str_appends(&querystr, "select relname from pg_class where oid=");
  2160. smart_str_append_unsigned(&querystr, oid);
  2161. smart_str_0(&querystr);
  2162. if ((tmp_res = PQexec(pg_result->conn, querystr.c)) == NULL || PQresultStatus(tmp_res) != PGRES_TUPLES_OK) {
  2163. if (tmp_res) {
  2164. PQclear(tmp_res);
  2165. }
  2166. smart_str_free(&querystr);
  2167. smart_str_free(&hash_key);
  2168. RETURN_FALSE;
  2169. }
  2170. smart_str_free(&querystr);
  2171. if ((table_name = PQgetvalue(tmp_res, 0, 0)) == NULL) {
  2172. PQclear(tmp_res);
  2173. smart_str_free(&hash_key);
  2174. RETURN_FALSE;
  2175. }
  2176. Z_TYPE(new_field_table) = le_string;
  2177. new_field_table.ptr = estrdup(table_name);
  2178. zend_hash_update(&EG(regular_list), hash_key.c, hash_key.len+1, (void *) &new_field_table, sizeof(zend_rsrc_list_entry), NULL);
  2179. smart_str_free(&hash_key);
  2180. PQclear(tmp_res);
  2181. RETURN_STRING(table_name, 1);
  2182. }
  2183. }
  2184. /* }}} */
  2185. #endif
  2186. #define PHP_PG_FIELD_NAME 1
  2187. #define PHP_PG_FIELD_SIZE 2
  2188. #define PHP_PG_FIELD_TYPE 3
  2189. #define PHP_PG_FIELD_TYPE_OID 4
  2190. /* {{{ php_pgsql_get_field_info
  2191. */
  2192. static void php_pgsql_get_field_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type)
  2193. {
  2194. zval *result;
  2195. long field;
  2196. PGresult *pgsql_result;
  2197. pgsql_result_handle *pg_result;
  2198. Oid oid;
  2199. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &result, &field) == FAILURE) {
  2200. return;
  2201. }
  2202. ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result);
  2203. pgsql_result = pg_result->result;
  2204. if (field < 0 || field >= PQnfields(pgsql_result)) {
  2205. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad field offset specified");
  2206. RETURN_FALSE;
  2207. }
  2208. switch (entry_type) {
  2209. case PHP_PG_FIELD_NAME:
  2210. Z_STRVAL_P(return_value) = PQfname(pgsql_result, field);
  2211. Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
  2212. Z_STRVAL_P(return_value) = estrndup(Z_STRVAL_P(return_value),Z_STRLEN_P(return_value));
  2213. Z_TYPE_P(return_value) = IS_STRING;
  2214. break;
  2215. case PHP_PG_FIELD_SIZE:
  2216. Z_LVAL_P(return_value) = PQfsize(pgsql_result, field);
  2217. Z_TYPE_P(return_value) = IS_LONG;
  2218. break;
  2219. case PHP_PG_FIELD_TYPE:
  2220. Z_STRVAL_P(return_value) = get_field_name(pg_result->conn, PQftype(pgsql_result, field), &EG(regular_list) TSRMLS_CC);
  2221. Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
  2222. Z_TYPE_P(return_value) = IS_STRING;
  2223. break;
  2224. case PHP_PG_FIELD_TYPE_OID:
  2225. oid = PQftype(pgsql_result, field);
  2226. #if UINT_MAX > LONG_MAX
  2227. if (oid > LONG_MAX) {
  2228. smart_str s = {0};
  2229. smart_str_append_unsigned(&s, oid);
  2230. smart_str_0(&s);
  2231. Z_STRVAL_P(return_value) = s.c;
  2232. Z_STRLEN_P(return_value) = s.len;
  2233. Z_TYPE_P(return_value) = IS_STRING;
  2234. } else
  2235. #endif
  2236. {
  2237. Z_LVAL_P(return_value) = (long)oid;
  2238. Z_TYPE_P(return_value) = IS_LONG;
  2239. }
  2240. break;
  2241. default:
  2242. RETURN_FALSE;
  2243. }
  2244. }
  2245. /* }}} */
  2246. /* {{{ proto string pg_field_name(resource result, int field_number)
  2247. Returns the name of the field */
  2248. PHP_FUNCTION(pg_field_name)
  2249. {
  2250. php_pgsql_get_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_FIELD_NAME);
  2251. }
  2252. /* }}} */
  2253. /* {{{ proto int pg_field_size(resource result, int field_number)
  2254. Returns the internal size of the field */
  2255. PHP_FUNCTION(pg_field_size)
  2256. {
  2257. php_pgsql_get_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_FIELD_SIZE);
  2258. }
  2259. /* }}} */
  2260. /* {{{ proto string pg_field_type(resource result, int field_number)
  2261. Returns the type name for the given field */
  2262. PHP_FUNCTION(pg_field_type)
  2263. {
  2264. php_pgsql_get_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_FIELD_TYPE);
  2265. }
  2266. /* }}} */
  2267. /* {{{ proto string pg_field_type_oid(resource result, int field_number)
  2268. Returns the type oid for the given field */
  2269. PHP_FUNCTION(pg_field_type_oid)
  2270. {
  2271. php_pgsql_get_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_FIELD_TYPE_OID);
  2272. }
  2273. /* }}} */
  2274. /* {{{ proto int pg_field_num(resource result, string field_name)
  2275. Returns the field number of the named field */
  2276. PHP_FUNCTION(pg_field_num)
  2277. {
  2278. zval *result;
  2279. char *field;
  2280. int field_len;
  2281. PGresult *pgsql_result;
  2282. pgsql_result_handle *pg_result;
  2283. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &result, &field, &field_len) == FAILURE) {
  2284. return;
  2285. }
  2286. ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result);
  2287. pgsql_result = pg_result->result;
  2288. Z_LVAL_P(return_value) = PQfnumber(pgsql_result, field);
  2289. Z_TYPE_P(return_value) = IS_LONG;
  2290. }
  2291. /* }}} */
  2292. /* {{{ proto mixed pg_fetch_result(resource result, [int row_number,] mixed field_name)
  2293. Returns values from a result identifier */
  2294. PHP_FUNCTION(pg_fetch_result)
  2295. {
  2296. zval *result, **field=NULL;
  2297. long row;
  2298. PGresult *pgsql_result;
  2299. pgsql_result_handle *pg_result;
  2300. int field_offset, pgsql_row, argc = ZEND_NUM_ARGS();
  2301. if (argc == 2) {
  2302. if (zend_parse_parameters(argc TSRMLS_CC, "rZ", &result, &field) == FAILURE) {
  2303. return;
  2304. }
  2305. } else {
  2306. if (zend_parse_parameters(argc TSRMLS_CC, "rlZ", &result, &row, &field) == FAILURE) {
  2307. return;
  2308. }
  2309. }
  2310. ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result);
  2311. pgsql_result = pg_result->result;
  2312. if (argc == 2) {
  2313. if (pg_result->row < 0) {
  2314. pg_result->row = 0;
  2315. }
  2316. pgsql_row = pg_result->row;
  2317. if (pgsql_row >= PQntuples(pgsql_result)) {
  2318. RETURN_FALSE;
  2319. }
  2320. } else {
  2321. pgsql_row = row;
  2322. if (pgsql_row < 0 || pgsql_row >= PQntuples(pgsql_result)) {
  2323. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to jump to row %ld on PostgreSQL result index %ld",
  2324. row, Z_LVAL_P(result));
  2325. RETURN_FALSE;
  2326. }
  2327. }
  2328. switch(Z_TYPE_PP(field)) {
  2329. case IS_STRING:
  2330. field_offset = PQfnumber(pgsql_result, Z_STRVAL_PP(field));
  2331. break;
  2332. default:
  2333. convert_to_long_ex(field);
  2334. field_offset = Z_LVAL_PP(field);
  2335. break;
  2336. }
  2337. if (field_offset<0 || field_offset>=PQnfields(pgsql_result)) {
  2338. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad column offset specified");
  2339. RETURN_FALSE;
  2340. }
  2341. if (PQgetisnull(pgsql_result, pgsql_row, field_offset)) {
  2342. Z_TYPE_P(return_value) = IS_NULL;
  2343. } else {
  2344. char *value = PQgetvalue(pgsql_result, pgsql_row, field_offset);
  2345. int value_len = PQgetlength(pgsql_result, pgsql_row, field_offset);
  2346. ZVAL_STRINGL(return_value, value, value_len, 1);
  2347. }
  2348. }
  2349. /* }}} */
  2350. /* {{{ void php_pgsql_fetch_hash */
  2351. static void php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, long result_type, int into_object)
  2352. {
  2353. zval *result, *zrow = NULL;
  2354. PGresult *pgsql_result;
  2355. pgsql_result_handle *pg_result;
  2356. int i, num_fields, pgsql_row, use_row;
  2357. long row = -1;
  2358. char *field_name;
  2359. zval *ctor_params = NULL;
  2360. zend_class_entry *ce = NULL;
  2361. if (into_object) {
  2362. char *class_name = NULL;
  2363. int class_name_len;
  2364. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|z!sz", &result, &zrow, &class_name, &class_name_len, &ctor_params) == FAILURE) {
  2365. return;
  2366. }
  2367. if (!class_name) {
  2368. ce = zend_standard_class_def;
  2369. } else {
  2370. ce = zend_fetch_class(class_name, class_name_len, ZEND_FETCH_CLASS_AUTO TSRMLS_CC);
  2371. }
  2372. if (!ce) {
  2373. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not find class '%s'", class_name);
  2374. return;
  2375. }
  2376. result_type = PGSQL_ASSOC;
  2377. } else {
  2378. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|z!l", &result, &zrow, &result_type) == FAILURE) {
  2379. return;
  2380. }
  2381. }
  2382. if (zrow == NULL) {
  2383. row = -1;
  2384. } else {
  2385. convert_to_long(zrow);
  2386. row = Z_LVAL_P(zrow);
  2387. if (row < 0) {
  2388. php_error_docref(NULL TSRMLS_CC, E_WARNING, "The row parameter must be greater or equal to zero");
  2389. RETURN_FALSE;
  2390. }
  2391. }
  2392. use_row = ZEND_NUM_ARGS() > 1 && row != -1;
  2393. if (!(result_type & PGSQL_BOTH)) {
  2394. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid result type");
  2395. RETURN_FALSE;
  2396. }
  2397. ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result);
  2398. pgsql_result = pg_result->result;
  2399. if (use_row) {
  2400. pgsql_row = row;
  2401. pg_result->row = pgsql_row;
  2402. if (pgsql_row < 0 || pgsql_row >= PQntuples(pgsql_result)) {
  2403. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to jump to row %ld on PostgreSQL result index %ld",
  2404. row, Z_LVAL_P(result));
  2405. RETURN_FALSE;
  2406. }
  2407. } else {
  2408. /* If 2nd param is NULL, use internal row counter to access next row */
  2409. pgsql_row = pg_result->row;
  2410. if (pgsql_row < 0 || pgsql_row >= PQntuples(pgsql_result)) {
  2411. RETURN_FALSE;
  2412. }
  2413. pg_result->row++;
  2414. }
  2415. array_init(return_value);
  2416. for (i = 0, num_fields = PQnfields(pgsql_result); i < num_fields; i++) {
  2417. if (PQgetisnull(pgsql_result, pgsql_row, i)) {
  2418. if (result_type & PGSQL_NUM) {
  2419. add_index_null(return_value, i);
  2420. }
  2421. if (result_type & PGSQL_ASSOC) {
  2422. field_name = PQfname(pgsql_result, i);
  2423. add_assoc_null(return_value, field_name);
  2424. }
  2425. } else {
  2426. char *element = PQgetvalue(pgsql_result, pgsql_row, i);
  2427. if (element) {
  2428. char *data;
  2429. int data_len;
  2430. int should_copy=0;
  2431. const uint element_len = strlen(element);
  2432. data = safe_estrndup(element, element_len);
  2433. data_len = element_len;
  2434. if (result_type & PGSQL_NUM) {
  2435. add_index_stringl(return_value, i, data, data_len, should_copy);
  2436. should_copy=1;
  2437. }
  2438. if (result_type & PGSQL_ASSOC) {
  2439. field_name = PQfname(pgsql_result, i);
  2440. add_assoc_stringl(return_value, field_name, data, data_len, should_copy);
  2441. }
  2442. }
  2443. }
  2444. }
  2445. if (into_object) {
  2446. zval dataset = *return_value;
  2447. zend_fcall_info fci;
  2448. zend_fcall_info_cache fcc;
  2449. zval *retval_ptr;
  2450. object_and_properties_init(return_value, ce, NULL);
  2451. zend_merge_properties(return_value, Z_ARRVAL(dataset), 1 TSRMLS_CC);
  2452. if (ce->constructor) {
  2453. fci.size = sizeof(fci);
  2454. fci.function_table = &ce->function_table;
  2455. fci.function_name = NULL;
  2456. fci.symbol_table = NULL;
  2457. fci.object_ptr = return_value;
  2458. fci.retval_ptr_ptr = &retval_ptr;
  2459. fci.params = NULL;
  2460. fci.param_count = 0;
  2461. fci.no_separation = 1;
  2462. if (ctor_params && Z_TYPE_P(ctor_params) != IS_NULL) {
  2463. if (zend_fcall_info_args(&fci, ctor_params TSRMLS_CC) == FAILURE) {
  2464. /* Two problems why we throw exceptions here: PHP is typeless
  2465. * and hence passing one argument that's not an array could be
  2466. * by mistake and the other way round is possible, too. The
  2467. * single value is an array. Also we'd have to make that one
  2468. * argument passed by reference.
  2469. */
  2470. zend_throw_exception(zend_exception_get_default(TSRMLS_C), "Parameter ctor_params must be an array", 0 TSRMLS_CC);
  2471. return;
  2472. }
  2473. }
  2474. fcc.initialized = 1;
  2475. fcc.function_handler = ce->constructor;
  2476. fcc.calling_scope = EG(scope);
  2477. fcc.called_scope = Z_OBJCE_P(return_value);
  2478. fcc.object_ptr = return_value;
  2479. if (zend_call_function(&fci, &fcc TSRMLS_CC) == FAILURE) {
  2480. zend_throw_exception_ex(zend_exception_get_default(TSRMLS_C), 0 TSRMLS_CC, "Could not execute %s::%s()", ce->name, ce->constructor->common.function_name);
  2481. } else {
  2482. if (retval_ptr) {
  2483. zval_ptr_dtor(&retval_ptr);
  2484. }
  2485. }
  2486. if (fci.params) {
  2487. efree(fci.params);
  2488. }
  2489. } else if (ctor_params) {
  2490. zend_throw_exception_ex(zend_exception_get_default(TSRMLS_C), 0 TSRMLS_CC, "Class %s does not have a constructor hence you cannot use ctor_params", ce->name);
  2491. }
  2492. }
  2493. }
  2494. /* }}} */
  2495. /* {{{ proto array pg_fetch_row(resource result [, int row [, int result_type]])
  2496. Get a row as an enumerated array */
  2497. PHP_FUNCTION(pg_fetch_row)
  2498. {
  2499. php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, PGSQL_NUM, 0);
  2500. }
  2501. /* }}} */
  2502. /* {{{ proto array pg_fetch_assoc(resource result [, int row])
  2503. Fetch a row as an assoc array */
  2504. PHP_FUNCTION(pg_fetch_assoc)
  2505. {
  2506. /* pg_fetch_assoc() is added from PHP 4.3.0. It should raise error, when
  2507. there is 3rd parameter */
  2508. if (ZEND_NUM_ARGS() > 2)
  2509. WRONG_PARAM_COUNT;
  2510. php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, PGSQL_ASSOC, 0);
  2511. }
  2512. /* }}} */
  2513. /* {{{ proto array pg_fetch_array(resource result [, int row [, int result_type]])
  2514. Fetch a row as an array */
  2515. PHP_FUNCTION(pg_fetch_array)
  2516. {
  2517. php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, PGSQL_BOTH, 0);
  2518. }
  2519. /* }}} */
  2520. /* {{{ proto object pg_fetch_object(resource result [, int row [, string class_name [, NULL|array ctor_params]]])
  2521. Fetch a row as an object */
  2522. PHP_FUNCTION(pg_fetch_object)
  2523. {
  2524. /* pg_fetch_object() allowed result_type used to be. 3rd parameter
  2525. must be allowed for compatibility */
  2526. php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, PGSQL_ASSOC, 1);
  2527. }
  2528. /* }}} */
  2529. /* {{{ proto array pg_fetch_all(resource result)
  2530. Fetch all rows into array */
  2531. PHP_FUNCTION(pg_fetch_all)
  2532. {
  2533. zval *result;
  2534. PGresult *pgsql_result;
  2535. pgsql_result_handle *pg_result;
  2536. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &result) == FAILURE) {
  2537. return;
  2538. }
  2539. ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result);
  2540. pgsql_result = pg_result->result;
  2541. array_init(return_value);
  2542. if (php_pgsql_result2array(pgsql_result, return_value TSRMLS_CC) == FAILURE) {
  2543. zval_dtor(return_value);
  2544. RETURN_FALSE;
  2545. }
  2546. }
  2547. /* }}} */
  2548. /* {{{ proto array pg_fetch_all_columns(resource result [, int column_number])
  2549. Fetch all rows into array */
  2550. PHP_FUNCTION(pg_fetch_all_columns)
  2551. {
  2552. zval *result;
  2553. PGresult *pgsql_result;
  2554. pgsql_result_handle *pg_result;
  2555. unsigned long colno=0;
  2556. int pg_numrows, pg_row;
  2557. size_t num_fields;
  2558. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &result, &colno) == FAILURE) {
  2559. RETURN_FALSE;
  2560. }
  2561. ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result);
  2562. pgsql_result = pg_result->result;
  2563. num_fields = PQnfields(pgsql_result);
  2564. if (colno >= num_fields || colno < 0) {
  2565. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid column number '%ld'", colno);
  2566. RETURN_FALSE;
  2567. }
  2568. array_init(return_value);
  2569. if ((pg_numrows = PQntuples(pgsql_result)) <= 0) {
  2570. return;
  2571. }
  2572. for (pg_row = 0; pg_row < pg_numrows; pg_row++) {
  2573. if (PQgetisnull(pgsql_result, pg_row, colno)) {
  2574. add_next_index_null(return_value);
  2575. } else {
  2576. add_next_index_string(return_value, PQgetvalue(pgsql_result, pg_row, colno), 1);
  2577. }
  2578. }
  2579. }
  2580. /* }}} */
  2581. /* {{{ proto bool pg_result_seek(resource result, int offset)
  2582. Set internal row offset */
  2583. PHP_FUNCTION(pg_result_seek)
  2584. {
  2585. zval *result;
  2586. long row;
  2587. pgsql_result_handle *pg_result;
  2588. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &result, &row) == FAILURE) {
  2589. return;
  2590. }
  2591. ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result);
  2592. if (row < 0 || row >= PQntuples(pg_result->result)) {
  2593. RETURN_FALSE;
  2594. }
  2595. /* seek to offset */
  2596. pg_result->row = row;
  2597. RETURN_TRUE;
  2598. }
  2599. /* }}} */
  2600. #define PHP_PG_DATA_LENGTH 1
  2601. #define PHP_PG_DATA_ISNULL 2
  2602. /* {{{ php_pgsql_data_info
  2603. */
  2604. static void php_pgsql_data_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type)
  2605. {
  2606. zval *result, **field;
  2607. long row;
  2608. PGresult *pgsql_result;
  2609. pgsql_result_handle *pg_result;
  2610. int field_offset, pgsql_row, argc = ZEND_NUM_ARGS();
  2611. if (argc == 2) {
  2612. if (zend_parse_parameters(argc TSRMLS_CC, "rZ", &result, &field) == FAILURE) {
  2613. return;
  2614. }
  2615. } else {
  2616. if (zend_parse_parameters(argc TSRMLS_CC, "rlZ", &result, &row, &field) == FAILURE) {
  2617. return;
  2618. }
  2619. }
  2620. ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result);
  2621. pgsql_result = pg_result->result;
  2622. if (argc == 2) {
  2623. if (pg_result->row < 0) {
  2624. pg_result->row = 0;
  2625. }
  2626. pgsql_row = pg_result->row;
  2627. if (pgsql_row < 0 || pgsql_row >= PQntuples(pgsql_result)) {
  2628. RETURN_FALSE;
  2629. }
  2630. } else {
  2631. pgsql_row = row;
  2632. if (pgsql_row < 0 || pgsql_row >= PQntuples(pgsql_result)) {
  2633. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to jump to row %ld on PostgreSQL result index %ld",
  2634. row, Z_LVAL_P(result));
  2635. RETURN_FALSE;
  2636. }
  2637. }
  2638. switch(Z_TYPE_PP(field)) {
  2639. case IS_STRING:
  2640. convert_to_string_ex(field);
  2641. field_offset = PQfnumber(pgsql_result, Z_STRVAL_PP(field));
  2642. break;
  2643. default:
  2644. convert_to_long_ex(field);
  2645. field_offset = Z_LVAL_PP(field);
  2646. break;
  2647. }
  2648. if (field_offset < 0 || field_offset >= PQnfields(pgsql_result)) {
  2649. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad column offset specified");
  2650. RETURN_FALSE;
  2651. }
  2652. switch (entry_type) {
  2653. case PHP_PG_DATA_LENGTH:
  2654. Z_LVAL_P(return_value) = PQgetlength(pgsql_result, pgsql_row, field_offset);
  2655. break;
  2656. case PHP_PG_DATA_ISNULL:
  2657. Z_LVAL_P(return_value) = PQgetisnull(pgsql_result, pgsql_row, field_offset);
  2658. break;
  2659. }
  2660. Z_TYPE_P(return_value) = IS_LONG;
  2661. }
  2662. /* }}} */
  2663. /* {{{ proto int pg_field_prtlen(resource result, [int row,] mixed field_name_or_number)
  2664. Returns the printed length */
  2665. PHP_FUNCTION(pg_field_prtlen)
  2666. {
  2667. php_pgsql_data_info(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_PG_DATA_LENGTH);
  2668. }
  2669. /* }}} */
  2670. /* {{{ proto int pg_field_is_null(resource result, [int row,] mixed field_name_or_number)
  2671. Test if a field is NULL */
  2672. PHP_FUNCTION(pg_field_is_null)
  2673. {
  2674. php_pgsql_data_info(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_PG_DATA_ISNULL);
  2675. }
  2676. /* }}} */
  2677. /* {{{ proto bool pg_free_result(resource result)
  2678. Free result memory */
  2679. PHP_FUNCTION(pg_free_result)
  2680. {
  2681. zval *result;
  2682. pgsql_result_handle *pg_result;
  2683. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &result) == FAILURE) {
  2684. return;
  2685. }
  2686. ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result);
  2687. if (Z_LVAL_P(result) == 0) {
  2688. RETURN_FALSE;
  2689. }
  2690. zend_list_delete(Z_RESVAL_P(result));
  2691. RETURN_TRUE;
  2692. }
  2693. /* }}} */
  2694. /* {{{ proto string pg_last_oid(resource result)
  2695. Returns the last object identifier */
  2696. PHP_FUNCTION(pg_last_oid)
  2697. {
  2698. zval *result;
  2699. PGresult *pgsql_result;
  2700. pgsql_result_handle *pg_result;
  2701. #ifdef HAVE_PQOIDVALUE
  2702. Oid oid;
  2703. #endif
  2704. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &result) == FAILURE) {
  2705. return;
  2706. }
  2707. ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result);
  2708. pgsql_result = pg_result->result;
  2709. #ifdef HAVE_PQOIDVALUE
  2710. oid = PQoidValue(pgsql_result);
  2711. if (oid == InvalidOid) {
  2712. RETURN_FALSE;
  2713. }
  2714. PGSQL_RETURN_OID(oid);
  2715. #else
  2716. Z_STRVAL_P(return_value) = (char *) PQoidStatus(pgsql_result);
  2717. if (Z_STRVAL_P(return_value)) {
  2718. RETURN_STRING(Z_STRVAL_P(return_value), 1);
  2719. }
  2720. RETURN_STRING("", 1);
  2721. #endif
  2722. }
  2723. /* }}} */
  2724. /* {{{ proto bool pg_trace(string filename [, string mode [, resource connection]])
  2725. Enable tracing a PostgreSQL connection */
  2726. PHP_FUNCTION(pg_trace)
  2727. {
  2728. char *z_filename, *mode = "w";
  2729. int z_filename_len, mode_len;
  2730. zval *pgsql_link = NULL;
  2731. int id = -1, argc = ZEND_NUM_ARGS();
  2732. PGconn *pgsql;
  2733. FILE *fp = NULL;
  2734. php_stream *stream;
  2735. id = PGG(default_link);
  2736. if (zend_parse_parameters(argc TSRMLS_CC, "p|sr", &z_filename, &z_filename_len, &mode, &mode_len, &pgsql_link) == FAILURE) {
  2737. return;
  2738. }
  2739. if (argc < 3) {
  2740. CHECK_DEFAULT_LINK(id);
  2741. }
  2742. if (pgsql_link == NULL && id == -1) {
  2743. RETURN_FALSE;
  2744. }
  2745. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  2746. stream = php_stream_open_wrapper(z_filename, mode, REPORT_ERRORS, NULL);
  2747. if (!stream) {
  2748. RETURN_FALSE;
  2749. }
  2750. if (FAILURE == php_stream_cast(stream, PHP_STREAM_AS_STDIO, (void**)&fp, REPORT_ERRORS)) {
  2751. php_stream_close(stream);
  2752. RETURN_FALSE;
  2753. }
  2754. php_stream_auto_cleanup(stream);
  2755. PQtrace(pgsql, fp);
  2756. RETURN_TRUE;
  2757. }
  2758. /* }}} */
  2759. /* {{{ proto bool pg_untrace([resource connection])
  2760. Disable tracing of a PostgreSQL connection */
  2761. PHP_FUNCTION(pg_untrace)
  2762. {
  2763. zval *pgsql_link = NULL;
  2764. int id = -1, argc = ZEND_NUM_ARGS();
  2765. PGconn *pgsql;
  2766. if (zend_parse_parameters(argc TSRMLS_CC, "|r", &pgsql_link) == FAILURE) {
  2767. return;
  2768. }
  2769. if (argc == 0) {
  2770. id = PGG(default_link);
  2771. CHECK_DEFAULT_LINK(id);
  2772. }
  2773. if (pgsql_link == NULL && id == -1) {
  2774. RETURN_FALSE;
  2775. }
  2776. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  2777. PQuntrace(pgsql);
  2778. RETURN_TRUE;
  2779. }
  2780. /* }}} */
  2781. /* {{{ proto mixed pg_lo_create([resource connection],[mixed large_object_oid])
  2782. Create a large object */
  2783. PHP_FUNCTION(pg_lo_create)
  2784. {
  2785. zval *pgsql_link = NULL, *oid = NULL;
  2786. PGconn *pgsql;
  2787. Oid pgsql_oid, wanted_oid = InvalidOid;
  2788. int id = -1, argc = ZEND_NUM_ARGS();
  2789. if (zend_parse_parameters(argc TSRMLS_CC, "|zz", &pgsql_link, &oid) == FAILURE) {
  2790. return;
  2791. }
  2792. if ((argc == 1) && (Z_TYPE_P(pgsql_link) != IS_RESOURCE)) {
  2793. oid = pgsql_link;
  2794. pgsql_link = NULL;
  2795. }
  2796. if (pgsql_link == NULL) {
  2797. id = PGG(default_link);
  2798. CHECK_DEFAULT_LINK(id);
  2799. if (id == -1) {
  2800. RETURN_FALSE;
  2801. }
  2802. }
  2803. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  2804. if (oid) {
  2805. #ifndef HAVE_PG_LO_CREATE
  2806. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Passing OID value is not supported. Upgrade your PostgreSQL");
  2807. #else
  2808. switch (Z_TYPE_P(oid)) {
  2809. case IS_STRING:
  2810. {
  2811. char *end_ptr;
  2812. wanted_oid = (Oid)strtoul(Z_STRVAL_P(oid), &end_ptr, 10);
  2813. if ((Z_STRVAL_P(oid)+Z_STRLEN_P(oid)) != end_ptr) {
  2814. /* wrong integer format */
  2815. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "invalid OID value passed");
  2816. RETURN_FALSE;
  2817. }
  2818. }
  2819. break;
  2820. case IS_LONG:
  2821. if (Z_LVAL_P(oid) < (long)InvalidOid) {
  2822. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "invalid OID value passed");
  2823. RETURN_FALSE;
  2824. }
  2825. wanted_oid = (Oid)Z_LVAL_P(oid);
  2826. break;
  2827. default:
  2828. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "invalid OID value passed");
  2829. RETURN_FALSE;
  2830. }
  2831. if ((pgsql_oid = lo_create(pgsql, wanted_oid)) == InvalidOid) {
  2832. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to create PostgreSQL large object");
  2833. RETURN_FALSE;
  2834. }
  2835. PGSQL_RETURN_OID(pgsql_oid);
  2836. #endif
  2837. }
  2838. if ((pgsql_oid = lo_creat(pgsql, INV_READ|INV_WRITE)) == InvalidOid) {
  2839. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to create PostgreSQL large object");
  2840. RETURN_FALSE;
  2841. }
  2842. PGSQL_RETURN_OID(pgsql_oid);
  2843. }
  2844. /* }}} */
  2845. /* {{{ proto bool pg_lo_unlink([resource connection,] string large_object_oid)
  2846. Delete a large object */
  2847. PHP_FUNCTION(pg_lo_unlink)
  2848. {
  2849. zval *pgsql_link = NULL;
  2850. long oid_long;
  2851. char *oid_string, *end_ptr;
  2852. int oid_strlen;
  2853. PGconn *pgsql;
  2854. Oid oid;
  2855. int id = -1;
  2856. int argc = ZEND_NUM_ARGS();
  2857. /* accept string type since Oid type is unsigned int */
  2858. if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
  2859. "rs", &pgsql_link, &oid_string, &oid_strlen) == SUCCESS) {
  2860. oid = (Oid)strtoul(oid_string, &end_ptr, 10);
  2861. if ((oid_string+oid_strlen) != end_ptr) {
  2862. /* wrong integer format */
  2863. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Wrong OID value passed");
  2864. RETURN_FALSE;
  2865. }
  2866. }
  2867. else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
  2868. "rl", &pgsql_link, &oid_long) == SUCCESS) {
  2869. if (oid_long <= InvalidOid) {
  2870. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Invalid OID specified");
  2871. RETURN_FALSE;
  2872. }
  2873. oid = (Oid)oid_long;
  2874. }
  2875. else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
  2876. "s", &oid_string, &oid_strlen) == SUCCESS) {
  2877. oid = (Oid)strtoul(oid_string, &end_ptr, 10);
  2878. if ((oid_string+oid_strlen) != end_ptr) {
  2879. /* wrong integer format */
  2880. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Wrong OID value passed");
  2881. RETURN_FALSE;
  2882. }
  2883. id = PGG(default_link);
  2884. CHECK_DEFAULT_LINK(id);
  2885. }
  2886. else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
  2887. "l", &oid_long) == SUCCESS) {
  2888. if (oid_long <= InvalidOid) {
  2889. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Invalid OID is specified");
  2890. RETURN_FALSE;
  2891. }
  2892. oid = (Oid)oid_long;
  2893. id = PGG(default_link);
  2894. CHECK_DEFAULT_LINK(id);
  2895. }
  2896. else {
  2897. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Requires 1 or 2 arguments");
  2898. RETURN_FALSE;
  2899. }
  2900. if (pgsql_link == NULL && id == -1) {
  2901. RETURN_FALSE;
  2902. }
  2903. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  2904. if (lo_unlink(pgsql, oid) == -1) {
  2905. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to delete PostgreSQL large object %u", oid);
  2906. RETURN_FALSE;
  2907. }
  2908. RETURN_TRUE;
  2909. }
  2910. /* }}} */
  2911. /* {{{ proto resource pg_lo_open([resource connection,] int large_object_oid, string mode)
  2912. Open a large object and return fd */
  2913. PHP_FUNCTION(pg_lo_open)
  2914. {
  2915. zval *pgsql_link = NULL;
  2916. long oid_long;
  2917. char *oid_string, *end_ptr, *mode_string;
  2918. int oid_strlen, mode_strlen;
  2919. PGconn *pgsql;
  2920. Oid oid;
  2921. int id = -1, pgsql_mode=0, pgsql_lofd;
  2922. int create=0;
  2923. pgLofp *pgsql_lofp;
  2924. int argc = ZEND_NUM_ARGS();
  2925. /* accept string type since Oid is unsigned int */
  2926. if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
  2927. "rss", &pgsql_link, &oid_string, &oid_strlen, &mode_string, &mode_strlen) == SUCCESS) {
  2928. oid = (Oid)strtoul(oid_string, &end_ptr, 10);
  2929. if ((oid_string+oid_strlen) != end_ptr) {
  2930. /* wrong integer format */
  2931. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Wrong OID value passed");
  2932. RETURN_FALSE;
  2933. }
  2934. }
  2935. else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
  2936. "rls", &pgsql_link, &oid_long, &mode_string, &mode_strlen) == SUCCESS) {
  2937. if (oid_long <= InvalidOid) {
  2938. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Invalid OID specified");
  2939. RETURN_FALSE;
  2940. }
  2941. oid = (Oid)oid_long;
  2942. }
  2943. else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
  2944. "ss", &oid_string, &oid_strlen, &mode_string, &mode_strlen) == SUCCESS) {
  2945. oid = (Oid)strtoul(oid_string, &end_ptr, 10);
  2946. if ((oid_string+oid_strlen) != end_ptr) {
  2947. /* wrong integer format */
  2948. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Wrong OID value passed");
  2949. RETURN_FALSE;
  2950. }
  2951. id = PGG(default_link);
  2952. CHECK_DEFAULT_LINK(id);
  2953. }
  2954. else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
  2955. "ls", &oid_long, &mode_string, &mode_strlen) == SUCCESS) {
  2956. if (oid_long <= InvalidOid) {
  2957. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Invalid OID specified");
  2958. RETURN_FALSE;
  2959. }
  2960. oid = (Oid)oid_long;
  2961. id = PGG(default_link);
  2962. CHECK_DEFAULT_LINK(id);
  2963. }
  2964. else {
  2965. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Requires 1 or 2 arguments");
  2966. RETURN_FALSE;
  2967. }
  2968. if (pgsql_link == NULL && id == -1) {
  2969. RETURN_FALSE;
  2970. }
  2971. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  2972. /* r/w/+ is little bit more PHP-like than INV_READ/INV_WRITE and a lot of
  2973. faster to type. Unfortunately, doesn't behave the same way as fopen()...
  2974. (Jouni)
  2975. */
  2976. if (strchr(mode_string, 'r') == mode_string) {
  2977. pgsql_mode |= INV_READ;
  2978. if (strchr(mode_string, '+') == mode_string+1) {
  2979. pgsql_mode |= INV_WRITE;
  2980. }
  2981. }
  2982. if (strchr(mode_string, 'w') == mode_string) {
  2983. pgsql_mode |= INV_WRITE;
  2984. create = 1;
  2985. if (strchr(mode_string, '+') == mode_string+1) {
  2986. pgsql_mode |= INV_READ;
  2987. }
  2988. }
  2989. pgsql_lofp = (pgLofp *) emalloc(sizeof(pgLofp));
  2990. if ((pgsql_lofd = lo_open(pgsql, oid, pgsql_mode)) == -1) {
  2991. if (create) {
  2992. if ((oid = lo_creat(pgsql, INV_READ|INV_WRITE)) == 0) {
  2993. efree(pgsql_lofp);
  2994. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to create PostgreSQL large object");
  2995. RETURN_FALSE;
  2996. } else {
  2997. if ((pgsql_lofd = lo_open(pgsql, oid, pgsql_mode)) == -1) {
  2998. if (lo_unlink(pgsql, oid) == -1) {
  2999. efree(pgsql_lofp);
  3000. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Something is really messed up! Your database is badly corrupted in a way NOT related to PHP");
  3001. RETURN_FALSE;
  3002. }
  3003. efree(pgsql_lofp);
  3004. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to open PostgreSQL large object");
  3005. RETURN_FALSE;
  3006. } else {
  3007. pgsql_lofp->conn = pgsql;
  3008. pgsql_lofp->lofd = pgsql_lofd;
  3009. Z_LVAL_P(return_value) = zend_list_insert(pgsql_lofp, le_lofp TSRMLS_CC);
  3010. Z_TYPE_P(return_value) = IS_LONG;
  3011. }
  3012. }
  3013. } else {
  3014. efree(pgsql_lofp);
  3015. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to open PostgreSQL large object");
  3016. RETURN_FALSE;
  3017. }
  3018. } else {
  3019. pgsql_lofp->conn = pgsql;
  3020. pgsql_lofp->lofd = pgsql_lofd;
  3021. ZEND_REGISTER_RESOURCE(return_value, pgsql_lofp, le_lofp);
  3022. }
  3023. }
  3024. /* }}} */
  3025. /* {{{ proto bool pg_lo_close(resource large_object)
  3026. Close a large object */
  3027. PHP_FUNCTION(pg_lo_close)
  3028. {
  3029. zval *pgsql_lofp;
  3030. pgLofp *pgsql;
  3031. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pgsql_lofp) == FAILURE) {
  3032. return;
  3033. }
  3034. ZEND_FETCH_RESOURCE(pgsql, pgLofp *, &pgsql_lofp, -1, "PostgreSQL large object", le_lofp);
  3035. if (lo_close((PGconn *)pgsql->conn, pgsql->lofd) < 0) {
  3036. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to close PostgreSQL large object descriptor %d", pgsql->lofd);
  3037. RETVAL_FALSE;
  3038. } else {
  3039. RETVAL_TRUE;
  3040. }
  3041. zend_list_delete(Z_RESVAL_P(pgsql_lofp));
  3042. return;
  3043. }
  3044. /* }}} */
  3045. #define PGSQL_LO_READ_BUF_SIZE 8192
  3046. /* {{{ proto string pg_lo_read(resource large_object [, int len])
  3047. Read a large object */
  3048. PHP_FUNCTION(pg_lo_read)
  3049. {
  3050. zval *pgsql_id;
  3051. long len;
  3052. int buf_len = PGSQL_LO_READ_BUF_SIZE, nbytes, argc = ZEND_NUM_ARGS();
  3053. char *buf;
  3054. pgLofp *pgsql;
  3055. if (zend_parse_parameters(argc TSRMLS_CC, "r|l", &pgsql_id, &len) == FAILURE) {
  3056. return;
  3057. }
  3058. ZEND_FETCH_RESOURCE(pgsql, pgLofp *, &pgsql_id, -1, "PostgreSQL large object", le_lofp);
  3059. if (argc > 1) {
  3060. buf_len = len;
  3061. }
  3062. buf = (char *) safe_emalloc(sizeof(char), (buf_len+1), 0);
  3063. if ((nbytes = lo_read((PGconn *)pgsql->conn, pgsql->lofd, buf, buf_len))<0) {
  3064. efree(buf);
  3065. RETURN_FALSE;
  3066. }
  3067. buf[nbytes] = '\0';
  3068. RETURN_STRINGL(buf, nbytes, 0);
  3069. }
  3070. /* }}} */
  3071. /* {{{ proto int pg_lo_write(resource large_object, string buf [, int len])
  3072. Write a large object */
  3073. PHP_FUNCTION(pg_lo_write)
  3074. {
  3075. zval *pgsql_id;
  3076. char *str;
  3077. long z_len;
  3078. int str_len, nbytes;
  3079. int len;
  3080. pgLofp *pgsql;
  3081. int argc = ZEND_NUM_ARGS();
  3082. if (zend_parse_parameters(argc TSRMLS_CC, "rs|l", &pgsql_id, &str, &str_len, &z_len) == FAILURE) {
  3083. return;
  3084. }
  3085. if (argc > 2) {
  3086. if (z_len > str_len) {
  3087. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot write more than buffer size %d. Tried to write %ld", str_len, z_len);
  3088. RETURN_FALSE;
  3089. }
  3090. if (z_len < 0) {
  3091. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Buffer size must be larger than 0, but %ld was specified", z_len);
  3092. RETURN_FALSE;
  3093. }
  3094. len = z_len;
  3095. }
  3096. else {
  3097. len = str_len;
  3098. }
  3099. ZEND_FETCH_RESOURCE(pgsql, pgLofp *, &pgsql_id, -1, "PostgreSQL large object", le_lofp);
  3100. if ((nbytes = lo_write((PGconn *)pgsql->conn, pgsql->lofd, str, len)) == -1) {
  3101. RETURN_FALSE;
  3102. }
  3103. RETURN_LONG(nbytes);
  3104. }
  3105. /* }}} */
  3106. /* {{{ proto int pg_lo_read_all(resource large_object)
  3107. Read a large object and send straight to browser */
  3108. PHP_FUNCTION(pg_lo_read_all)
  3109. {
  3110. zval *pgsql_id;
  3111. int tbytes;
  3112. volatile int nbytes;
  3113. char buf[PGSQL_LO_READ_BUF_SIZE];
  3114. pgLofp *pgsql;
  3115. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pgsql_id) == FAILURE) {
  3116. return;
  3117. }
  3118. ZEND_FETCH_RESOURCE(pgsql, pgLofp *, &pgsql_id, -1, "PostgreSQL large object", le_lofp);
  3119. tbytes = 0;
  3120. while ((nbytes = lo_read((PGconn *)pgsql->conn, pgsql->lofd, buf, PGSQL_LO_READ_BUF_SIZE))>0) {
  3121. PHPWRITE(buf, nbytes);
  3122. tbytes += nbytes;
  3123. }
  3124. RETURN_LONG(tbytes);
  3125. }
  3126. /* }}} */
  3127. /* {{{ proto int pg_lo_import([resource connection, ] string filename [, mixed oid])
  3128. Import large object direct from filesystem */
  3129. PHP_FUNCTION(pg_lo_import)
  3130. {
  3131. zval *pgsql_link = NULL, *oid = NULL;
  3132. char *file_in;
  3133. int id = -1, name_len;
  3134. int argc = ZEND_NUM_ARGS();
  3135. PGconn *pgsql;
  3136. Oid returned_oid;
  3137. if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
  3138. "rp|z", &pgsql_link, &file_in, &name_len, &oid) == SUCCESS) {
  3139. ;
  3140. }
  3141. else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
  3142. "p|z", &file_in, &name_len, &oid) == SUCCESS) {
  3143. id = PGG(default_link);
  3144. CHECK_DEFAULT_LINK(id);
  3145. }
  3146. /* old calling convention, deprecated since PHP 4.2 */
  3147. else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
  3148. "pr", &file_in, &name_len, &pgsql_link ) == SUCCESS) {
  3149. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Old API is used");
  3150. }
  3151. else {
  3152. WRONG_PARAM_COUNT;
  3153. }
  3154. if (php_check_open_basedir(file_in TSRMLS_CC)) {
  3155. RETURN_FALSE;
  3156. }
  3157. if (pgsql_link == NULL && id == -1) {
  3158. RETURN_FALSE;
  3159. }
  3160. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  3161. if (oid) {
  3162. #ifndef HAVE_PG_LO_IMPORT_WITH_OID
  3163. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "OID value passing not supported");
  3164. #else
  3165. Oid wanted_oid;
  3166. switch (Z_TYPE_P(oid)) {
  3167. case IS_STRING:
  3168. {
  3169. char *end_ptr;
  3170. wanted_oid = (Oid)strtoul(Z_STRVAL_P(oid), &end_ptr, 10);
  3171. if ((Z_STRVAL_P(oid)+Z_STRLEN_P(oid)) != end_ptr) {
  3172. /* wrong integer format */
  3173. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "invalid OID value passed");
  3174. RETURN_FALSE;
  3175. }
  3176. }
  3177. break;
  3178. case IS_LONG:
  3179. if (Z_LVAL_P(oid) < (long)InvalidOid) {
  3180. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "invalid OID value passed");
  3181. RETURN_FALSE;
  3182. }
  3183. wanted_oid = (Oid)Z_LVAL_P(oid);
  3184. break;
  3185. default:
  3186. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "invalid OID value passed");
  3187. RETURN_FALSE;
  3188. }
  3189. returned_oid = lo_import_with_oid(pgsql, file_in, wanted_oid);
  3190. if (returned_oid == InvalidOid) {
  3191. RETURN_FALSE;
  3192. }
  3193. PGSQL_RETURN_OID(returned_oid);
  3194. #endif
  3195. }
  3196. returned_oid = lo_import(pgsql, file_in);
  3197. if (returned_oid == InvalidOid) {
  3198. RETURN_FALSE;
  3199. }
  3200. PGSQL_RETURN_OID(returned_oid);
  3201. }
  3202. /* }}} */
  3203. /* {{{ proto bool pg_lo_export([resource connection, ] int objoid, string filename)
  3204. Export large object direct to filesystem */
  3205. PHP_FUNCTION(pg_lo_export)
  3206. {
  3207. zval *pgsql_link = NULL;
  3208. char *file_out, *oid_string, *end_ptr;
  3209. int oid_strlen;
  3210. int id = -1, name_len;
  3211. long oid_long;
  3212. Oid oid;
  3213. PGconn *pgsql;
  3214. int argc = ZEND_NUM_ARGS();
  3215. /* allow string to handle large OID value correctly */
  3216. if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
  3217. "rlp", &pgsql_link, &oid_long, &file_out, &name_len) == SUCCESS) {
  3218. if (oid_long <= InvalidOid) {
  3219. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Invalid OID specified");
  3220. RETURN_FALSE;
  3221. }
  3222. oid = (Oid)oid_long;
  3223. }
  3224. else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
  3225. "rss", &pgsql_link, &oid_string, &oid_strlen, &file_out, &name_len) == SUCCESS) {
  3226. oid = (Oid)strtoul(oid_string, &end_ptr, 10);
  3227. if ((oid_string+oid_strlen) != end_ptr) {
  3228. /* wrong integer format */
  3229. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Wrong OID value passed");
  3230. RETURN_FALSE;
  3231. }
  3232. }
  3233. else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
  3234. "lp", &oid_long, &file_out, &name_len) == SUCCESS) {
  3235. if (oid_long <= InvalidOid) {
  3236. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Invalid OID specified");
  3237. RETURN_FALSE;
  3238. }
  3239. oid = (Oid)oid_long;
  3240. id = PGG(default_link);
  3241. CHECK_DEFAULT_LINK(id);
  3242. }
  3243. else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
  3244. "sp", &oid_string, &oid_strlen, &file_out, &name_len) == SUCCESS) {
  3245. oid = (Oid)strtoul(oid_string, &end_ptr, 10);
  3246. if ((oid_string+oid_strlen) != end_ptr) {
  3247. /* wrong integer format */
  3248. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Wrong OID value passed");
  3249. RETURN_FALSE;
  3250. }
  3251. id = PGG(default_link);
  3252. CHECK_DEFAULT_LINK(id);
  3253. }
  3254. else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
  3255. "spr", &oid_string, &oid_strlen, &file_out, &name_len, &pgsql_link) == SUCCESS) {
  3256. oid = (Oid)strtoul(oid_string, &end_ptr, 10);
  3257. if ((oid_string+oid_strlen) != end_ptr) {
  3258. /* wrong integer format */
  3259. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Wrong OID value passed");
  3260. RETURN_FALSE;
  3261. }
  3262. }
  3263. else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
  3264. "lpr", &oid_long, &file_out, &name_len, &pgsql_link) == SUCCESS) {
  3265. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Old API is used");
  3266. if (oid_long <= InvalidOid) {
  3267. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Invalid OID specified");
  3268. RETURN_FALSE;
  3269. }
  3270. oid = (Oid)oid_long;
  3271. }
  3272. else {
  3273. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Requires 2 or 3 arguments");
  3274. RETURN_FALSE;
  3275. }
  3276. if (php_check_open_basedir(file_out TSRMLS_CC)) {
  3277. RETURN_FALSE;
  3278. }
  3279. if (pgsql_link == NULL && id == -1) {
  3280. RETURN_FALSE;
  3281. }
  3282. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  3283. if (lo_export(pgsql, oid, file_out) == -1) {
  3284. RETURN_FALSE;
  3285. }
  3286. RETURN_TRUE;
  3287. }
  3288. /* }}} */
  3289. /* {{{ proto bool pg_lo_seek(resource large_object, int offset [, int whence])
  3290. Seeks position of large object */
  3291. PHP_FUNCTION(pg_lo_seek)
  3292. {
  3293. zval *pgsql_id = NULL;
  3294. long result, offset = 0, whence = SEEK_CUR;
  3295. pgLofp *pgsql;
  3296. int argc = ZEND_NUM_ARGS();
  3297. if (zend_parse_parameters(argc TSRMLS_CC, "rl|l", &pgsql_id, &offset, &whence) == FAILURE) {
  3298. return;
  3299. }
  3300. if (whence != SEEK_SET && whence != SEEK_CUR && whence != SEEK_END) {
  3301. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid whence parameter");
  3302. return;
  3303. }
  3304. ZEND_FETCH_RESOURCE(pgsql, pgLofp *, &pgsql_id, -1, "PostgreSQL large object", le_lofp);
  3305. #if HAVE_PG_LO64
  3306. if (PQserverVersion((PGconn *)pgsql->conn) >= 90300) {
  3307. result = lo_lseek64((PGconn *)pgsql->conn, pgsql->lofd, offset, whence);
  3308. } else {
  3309. result = lo_lseek((PGconn *)pgsql->conn, pgsql->lofd, offset, whence);
  3310. }
  3311. #else
  3312. result = lo_lseek((PGconn *)pgsql->conn, pgsql->lofd, offset, whence);
  3313. #endif
  3314. if (result > -1) {
  3315. RETURN_TRUE;
  3316. } else {
  3317. RETURN_FALSE;
  3318. }
  3319. }
  3320. /* }}} */
  3321. /* {{{ proto int pg_lo_tell(resource large_object)
  3322. Returns current position of large object */
  3323. PHP_FUNCTION(pg_lo_tell)
  3324. {
  3325. zval *pgsql_id = NULL;
  3326. long offset = 0;
  3327. pgLofp *pgsql;
  3328. int argc = ZEND_NUM_ARGS();
  3329. if (zend_parse_parameters(argc TSRMLS_CC, "r", &pgsql_id) == FAILURE) {
  3330. return;
  3331. }
  3332. ZEND_FETCH_RESOURCE(pgsql, pgLofp *, &pgsql_id, -1, "PostgreSQL large object", le_lofp);
  3333. #if HAVE_PG_LO64
  3334. if (PQserverVersion((PGconn *)pgsql->conn) >= 90300) {
  3335. offset = lo_tell64((PGconn *)pgsql->conn, pgsql->lofd);
  3336. } else {
  3337. offset = lo_tell((PGconn *)pgsql->conn, pgsql->lofd);
  3338. }
  3339. #else
  3340. offset = lo_tell((PGconn *)pgsql->conn, pgsql->lofd);
  3341. #endif
  3342. RETURN_LONG(offset);
  3343. }
  3344. /* }}} */
  3345. #if HAVE_PG_LO_TRUNCATE
  3346. /* {{{ proto bool pg_lo_truncate(resource large_object, int size)
  3347. Truncate large object to size */
  3348. PHP_FUNCTION(pg_lo_truncate)
  3349. {
  3350. zval *pgsql_id = NULL;
  3351. size_t size;
  3352. pgLofp *pgsql;
  3353. int argc = ZEND_NUM_ARGS();
  3354. int result;
  3355. if (zend_parse_parameters(argc TSRMLS_CC, "rl", &pgsql_id, &size) == FAILURE) {
  3356. return;
  3357. }
  3358. ZEND_FETCH_RESOURCE(pgsql, pgLofp *, &pgsql_id, -1, "PostgreSQL large object", le_lofp);
  3359. #if HAVE_PG_LO64
  3360. if (PQserverVersion((PGconn *)pgsql->conn) >= 90300) {
  3361. result = lo_truncate64((PGconn *)pgsql->conn, pgsql->lofd, size);
  3362. } else {
  3363. result = lo_truncate((PGconn *)pgsql->conn, pgsql->lofd, size);
  3364. }
  3365. #else
  3366. result = lo_truncate((PGconn *)pgsql->conn, pgsql->lofd, size);
  3367. #endif
  3368. if (!result) {
  3369. RETURN_TRUE;
  3370. } else {
  3371. RETURN_FALSE;
  3372. }
  3373. }
  3374. /* }}} */
  3375. #endif
  3376. #if HAVE_PQSETERRORVERBOSITY
  3377. /* {{{ proto int pg_set_error_verbosity([resource connection,] int verbosity)
  3378. Set error verbosity */
  3379. PHP_FUNCTION(pg_set_error_verbosity)
  3380. {
  3381. zval *pgsql_link = NULL;
  3382. long verbosity;
  3383. int id = -1, argc = ZEND_NUM_ARGS();
  3384. PGconn *pgsql;
  3385. if (argc == 1) {
  3386. if (zend_parse_parameters(argc TSRMLS_CC, "l", &verbosity) == FAILURE) {
  3387. return;
  3388. }
  3389. id = PGG(default_link);
  3390. CHECK_DEFAULT_LINK(id);
  3391. } else {
  3392. if (zend_parse_parameters(argc TSRMLS_CC, "rl", &pgsql_link, &verbosity) == FAILURE) {
  3393. return;
  3394. }
  3395. }
  3396. if (pgsql_link == NULL && id == -1) {
  3397. RETURN_FALSE;
  3398. }
  3399. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  3400. if (verbosity & (PQERRORS_TERSE|PQERRORS_DEFAULT|PQERRORS_VERBOSE)) {
  3401. Z_LVAL_P(return_value) = PQsetErrorVerbosity(pgsql, verbosity);
  3402. Z_TYPE_P(return_value) = IS_LONG;
  3403. } else {
  3404. RETURN_FALSE;
  3405. }
  3406. }
  3407. /* }}} */
  3408. #endif
  3409. #ifdef HAVE_PQCLIENTENCODING
  3410. /* {{{ proto int pg_set_client_encoding([resource connection,] string encoding)
  3411. Set client encoding */
  3412. PHP_FUNCTION(pg_set_client_encoding)
  3413. {
  3414. char *encoding;
  3415. int encoding_len;
  3416. zval *pgsql_link = NULL;
  3417. int id = -1, argc = ZEND_NUM_ARGS();
  3418. PGconn *pgsql;
  3419. if (argc == 1) {
  3420. if (zend_parse_parameters(argc TSRMLS_CC, "s", &encoding, &encoding_len) == FAILURE) {
  3421. return;
  3422. }
  3423. id = PGG(default_link);
  3424. CHECK_DEFAULT_LINK(id);
  3425. } else {
  3426. if (zend_parse_parameters(argc TSRMLS_CC, "rs", &pgsql_link, &encoding, &encoding_len) == FAILURE) {
  3427. return;
  3428. }
  3429. }
  3430. if (pgsql_link == NULL && id == -1) {
  3431. RETURN_FALSE;
  3432. }
  3433. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  3434. Z_LVAL_P(return_value) = PQsetClientEncoding(pgsql, encoding);
  3435. Z_TYPE_P(return_value) = IS_LONG;
  3436. }
  3437. /* }}} */
  3438. /* {{{ proto string pg_client_encoding([resource connection])
  3439. Get the current client encoding */
  3440. PHP_FUNCTION(pg_client_encoding)
  3441. {
  3442. zval *pgsql_link = NULL;
  3443. int id = -1, argc = ZEND_NUM_ARGS();
  3444. PGconn *pgsql;
  3445. if (zend_parse_parameters(argc TSRMLS_CC, "|r", &pgsql_link) == FAILURE) {
  3446. return;
  3447. }
  3448. if (argc == 0) {
  3449. id = PGG(default_link);
  3450. CHECK_DEFAULT_LINK(id);
  3451. }
  3452. if (pgsql_link == NULL && id == -1) {
  3453. RETURN_FALSE;
  3454. }
  3455. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  3456. /* Just do the same as found in PostgreSQL sources... */
  3457. Z_STRVAL_P(return_value) = (char *) pg_encoding_to_char(PQclientEncoding(pgsql));
  3458. Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
  3459. Z_STRVAL_P(return_value) = (char *) estrdup(Z_STRVAL_P(return_value));
  3460. Z_TYPE_P(return_value) = IS_STRING;
  3461. }
  3462. /* }}} */
  3463. #endif
  3464. #if !HAVE_PQGETCOPYDATA
  3465. #define COPYBUFSIZ 8192
  3466. #endif
  3467. /* {{{ proto bool pg_end_copy([resource connection])
  3468. Sync with backend. Completes the Copy command */
  3469. PHP_FUNCTION(pg_end_copy)
  3470. {
  3471. zval *pgsql_link = NULL;
  3472. int id = -1, argc = ZEND_NUM_ARGS();
  3473. PGconn *pgsql;
  3474. int result = 0;
  3475. if (zend_parse_parameters(argc TSRMLS_CC, "|r", &pgsql_link) == FAILURE) {
  3476. return;
  3477. }
  3478. if (argc == 0) {
  3479. id = PGG(default_link);
  3480. CHECK_DEFAULT_LINK(id);
  3481. }
  3482. if (pgsql_link == NULL && id == -1) {
  3483. RETURN_FALSE;
  3484. }
  3485. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  3486. result = PQendcopy(pgsql);
  3487. if (result!=0) {
  3488. PHP_PQ_ERROR("Query failed: %s", pgsql);
  3489. RETURN_FALSE;
  3490. }
  3491. RETURN_TRUE;
  3492. }
  3493. /* }}} */
  3494. /* {{{ proto bool pg_put_line([resource connection,] string query)
  3495. Send null-terminated string to backend server*/
  3496. PHP_FUNCTION(pg_put_line)
  3497. {
  3498. char *query;
  3499. zval *pgsql_link = NULL;
  3500. int query_len, id = -1;
  3501. PGconn *pgsql;
  3502. int result = 0, argc = ZEND_NUM_ARGS();
  3503. if (argc == 1) {
  3504. if (zend_parse_parameters(argc TSRMLS_CC, "s", &query, &query_len) == FAILURE) {
  3505. return;
  3506. }
  3507. id = PGG(default_link);
  3508. CHECK_DEFAULT_LINK(id);
  3509. } else {
  3510. if (zend_parse_parameters(argc TSRMLS_CC, "rs", &pgsql_link, &query, &query_len) == FAILURE) {
  3511. return;
  3512. }
  3513. }
  3514. if (pgsql_link == NULL && id == -1) {
  3515. RETURN_FALSE;
  3516. }
  3517. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  3518. result = PQputline(pgsql, query);
  3519. if (result==EOF) {
  3520. PHP_PQ_ERROR("Query failed: %s", pgsql);
  3521. RETURN_FALSE;
  3522. }
  3523. RETURN_TRUE;
  3524. }
  3525. /* }}} */
  3526. /* {{{ proto array pg_copy_to(resource connection, string table_name [, string delimiter [, string null_as]])
  3527. Copy table to array */
  3528. PHP_FUNCTION(pg_copy_to)
  3529. {
  3530. zval *pgsql_link;
  3531. char *table_name, *pg_delim = NULL, *pg_null_as = NULL;
  3532. int table_name_len, pg_delim_len, pg_null_as_len, free_pg_null = 0;
  3533. char *query;
  3534. int id = -1;
  3535. PGconn *pgsql;
  3536. PGresult *pgsql_result;
  3537. ExecStatusType status;
  3538. int copydone = 0;
  3539. #if !HAVE_PQGETCOPYDATA
  3540. char copybuf[COPYBUFSIZ];
  3541. #endif
  3542. char *csv = (char *)NULL;
  3543. int ret;
  3544. int argc = ZEND_NUM_ARGS();
  3545. if (zend_parse_parameters(argc TSRMLS_CC, "rs|ss",
  3546. &pgsql_link, &table_name, &table_name_len,
  3547. &pg_delim, &pg_delim_len, &pg_null_as, &pg_null_as_len) == FAILURE) {
  3548. return;
  3549. }
  3550. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  3551. if (!pg_delim) {
  3552. pg_delim = "\t";
  3553. }
  3554. if (!pg_null_as) {
  3555. pg_null_as = safe_estrdup("\\\\N");
  3556. free_pg_null = 1;
  3557. }
  3558. spprintf(&query, 0, "COPY %s TO STDOUT DELIMITER E'%c' NULL AS E'%s'", table_name, *pg_delim, pg_null_as);
  3559. while ((pgsql_result = PQgetResult(pgsql))) {
  3560. PQclear(pgsql_result);
  3561. }
  3562. pgsql_result = PQexec(pgsql, query);
  3563. if (free_pg_null) {
  3564. efree(pg_null_as);
  3565. }
  3566. efree(query);
  3567. if (pgsql_result) {
  3568. status = PQresultStatus(pgsql_result);
  3569. } else {
  3570. status = (ExecStatusType) PQstatus(pgsql);
  3571. }
  3572. switch (status) {
  3573. case PGRES_COPY_OUT:
  3574. if (pgsql_result) {
  3575. PQclear(pgsql_result);
  3576. array_init(return_value);
  3577. #if HAVE_PQGETCOPYDATA
  3578. while (!copydone)
  3579. {
  3580. ret = PQgetCopyData(pgsql, &csv, 0);
  3581. switch (ret) {
  3582. case -1:
  3583. copydone = 1;
  3584. break;
  3585. case 0:
  3586. case -2:
  3587. PHP_PQ_ERROR("getline failed: %s", pgsql);
  3588. RETURN_FALSE;
  3589. break;
  3590. default:
  3591. add_next_index_string(return_value, csv, 1);
  3592. PQfreemem(csv);
  3593. break;
  3594. }
  3595. }
  3596. #else
  3597. while (!copydone)
  3598. {
  3599. if ((ret = PQgetline(pgsql, copybuf, COPYBUFSIZ))) {
  3600. PHP_PQ_ERROR("getline failed: %s", pgsql);
  3601. RETURN_FALSE;
  3602. }
  3603. if (copybuf[0] == '\\' &&
  3604. copybuf[1] == '.' &&
  3605. copybuf[2] == '\0')
  3606. {
  3607. copydone = 1;
  3608. }
  3609. else
  3610. {
  3611. if (csv == (char *)NULL) {
  3612. csv = estrdup(copybuf);
  3613. } else {
  3614. csv = (char *)erealloc(csv, strlen(csv) + sizeof(char)*(COPYBUFSIZ+1));
  3615. strcat(csv, copybuf);
  3616. }
  3617. switch (ret)
  3618. {
  3619. case EOF:
  3620. copydone = 1;
  3621. case 0:
  3622. add_next_index_string(return_value, csv, 1);
  3623. efree(csv);
  3624. csv = (char *)NULL;
  3625. break;
  3626. case 1:
  3627. break;
  3628. }
  3629. }
  3630. }
  3631. if (PQendcopy(pgsql)) {
  3632. PHP_PQ_ERROR("endcopy failed: %s", pgsql);
  3633. RETURN_FALSE;
  3634. }
  3635. #endif
  3636. while ((pgsql_result = PQgetResult(pgsql))) {
  3637. PQclear(pgsql_result);
  3638. }
  3639. } else {
  3640. PQclear(pgsql_result);
  3641. RETURN_FALSE;
  3642. }
  3643. break;
  3644. default:
  3645. PQclear(pgsql_result);
  3646. PHP_PQ_ERROR("Copy command failed: %s", pgsql);
  3647. RETURN_FALSE;
  3648. break;
  3649. }
  3650. }
  3651. /* }}} */
  3652. /* {{{ proto bool pg_copy_from(resource connection, string table_name , array rows [, string delimiter [, string null_as]])
  3653. Copy table from array */
  3654. PHP_FUNCTION(pg_copy_from)
  3655. {
  3656. zval *pgsql_link = NULL, *pg_rows;
  3657. zval **tmp;
  3658. char *table_name, *pg_delim = NULL, *pg_null_as = NULL;
  3659. int table_name_len, pg_delim_len, pg_null_as_len;
  3660. int pg_null_as_free = 0;
  3661. char *query;
  3662. HashPosition pos;
  3663. int id = -1;
  3664. PGconn *pgsql;
  3665. PGresult *pgsql_result;
  3666. ExecStatusType status;
  3667. int argc = ZEND_NUM_ARGS();
  3668. if (zend_parse_parameters(argc TSRMLS_CC, "rsa|ss",
  3669. &pgsql_link, &table_name, &table_name_len, &pg_rows,
  3670. &pg_delim, &pg_delim_len, &pg_null_as, &pg_null_as_len) == FAILURE) {
  3671. return;
  3672. }
  3673. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  3674. if (!pg_delim) {
  3675. pg_delim = "\t";
  3676. }
  3677. if (!pg_null_as) {
  3678. pg_null_as = safe_estrdup("\\\\N");
  3679. pg_null_as_free = 1;
  3680. }
  3681. spprintf(&query, 0, "COPY %s FROM STDIN DELIMITER E'%c' NULL AS E'%s'", table_name, *pg_delim, pg_null_as);
  3682. while ((pgsql_result = PQgetResult(pgsql))) {
  3683. PQclear(pgsql_result);
  3684. }
  3685. pgsql_result = PQexec(pgsql, query);
  3686. if (pg_null_as_free) {
  3687. efree(pg_null_as);
  3688. }
  3689. efree(query);
  3690. if (pgsql_result) {
  3691. status = PQresultStatus(pgsql_result);
  3692. } else {
  3693. status = (ExecStatusType) PQstatus(pgsql);
  3694. }
  3695. switch (status) {
  3696. case PGRES_COPY_IN:
  3697. if (pgsql_result) {
  3698. int command_failed = 0;
  3699. PQclear(pgsql_result);
  3700. zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(pg_rows), &pos);
  3701. #if HAVE_PQPUTCOPYDATA
  3702. while (zend_hash_get_current_data_ex(Z_ARRVAL_P(pg_rows), (void **) &tmp, &pos) == SUCCESS) {
  3703. zval *value;
  3704. ALLOC_ZVAL(value);
  3705. INIT_PZVAL_COPY(value, *tmp);
  3706. zval_copy_ctor(value);
  3707. convert_to_string_ex(&value);
  3708. query = (char *)emalloc(Z_STRLEN_P(value) + 2);
  3709. strlcpy(query, Z_STRVAL_P(value), Z_STRLEN_P(value) + 2);
  3710. if(Z_STRLEN_P(value) > 0 && *(query + Z_STRLEN_P(value) - 1) != '\n') {
  3711. strlcat(query, "\n", Z_STRLEN_P(value) + 2);
  3712. }
  3713. if (PQputCopyData(pgsql, query, strlen(query)) != 1) {
  3714. efree(query);
  3715. zval_dtor(value);
  3716. efree(value);
  3717. PHP_PQ_ERROR("copy failed: %s", pgsql);
  3718. RETURN_FALSE;
  3719. }
  3720. efree(query);
  3721. zval_dtor(value);
  3722. efree(value);
  3723. zend_hash_move_forward_ex(Z_ARRVAL_P(pg_rows), &pos);
  3724. }
  3725. if (PQputCopyEnd(pgsql, NULL) != 1) {
  3726. PHP_PQ_ERROR("putcopyend failed: %s", pgsql);
  3727. RETURN_FALSE;
  3728. }
  3729. #else
  3730. while (zend_hash_get_current_data_ex(Z_ARRVAL_P(pg_rows), (void **) &tmp, &pos) == SUCCESS) {
  3731. zval *value;
  3732. ALLOC_ZVAL(value);
  3733. INIT_PZVAL_COPY(value, *tmp);
  3734. zval_copy_ctor(value);
  3735. convert_to_string_ex(&value);
  3736. query = (char *)emalloc(Z_STRLEN_P(value) + 2);
  3737. strlcpy(query, Z_STRVAL_P(value), Z_STRLEN_P(value) + 2);
  3738. if(Z_STRLEN_P(value) > 0 && *(query + Z_STRLEN_P(value) - 1) != '\n') {
  3739. strlcat(query, "\n", Z_STRLEN_P(value) + 2);
  3740. }
  3741. if (PQputline(pgsql, query)==EOF) {
  3742. efree(query);
  3743. zval_dtor(value);
  3744. efree(value);
  3745. PHP_PQ_ERROR("copy failed: %s", pgsql);
  3746. RETURN_FALSE;
  3747. }
  3748. efree(query);
  3749. zval_dtor(value);
  3750. efree(value);
  3751. zend_hash_move_forward_ex(Z_ARRVAL_P(pg_rows), &pos);
  3752. }
  3753. if (PQputline(pgsql, "\\.\n") == EOF) {
  3754. PHP_PQ_ERROR("putline failed: %s", pgsql);
  3755. RETURN_FALSE;
  3756. }
  3757. if (PQendcopy(pgsql)) {
  3758. PHP_PQ_ERROR("endcopy failed: %s", pgsql);
  3759. RETURN_FALSE;
  3760. }
  3761. #endif
  3762. while ((pgsql_result = PQgetResult(pgsql))) {
  3763. if (PGRES_COMMAND_OK != PQresultStatus(pgsql_result)) {
  3764. PHP_PQ_ERROR("Copy command failed: %s", pgsql);
  3765. command_failed = 1;
  3766. }
  3767. PQclear(pgsql_result);
  3768. }
  3769. if (command_failed) {
  3770. RETURN_FALSE;
  3771. }
  3772. } else {
  3773. PQclear(pgsql_result);
  3774. RETURN_FALSE;
  3775. }
  3776. RETURN_TRUE;
  3777. break;
  3778. default:
  3779. PQclear(pgsql_result);
  3780. PHP_PQ_ERROR("Copy command failed: %s", pgsql);
  3781. RETURN_FALSE;
  3782. break;
  3783. }
  3784. }
  3785. /* }}} */
  3786. #ifdef HAVE_PQESCAPE
  3787. /* {{{ proto string pg_escape_string([resource connection,] string data)
  3788. Escape string for text/char type */
  3789. PHP_FUNCTION(pg_escape_string)
  3790. {
  3791. char *from = NULL, *to = NULL;
  3792. zval *pgsql_link;
  3793. #ifdef HAVE_PQESCAPE_CONN
  3794. PGconn *pgsql;
  3795. #endif
  3796. int to_len;
  3797. int from_len;
  3798. int id = -1;
  3799. switch (ZEND_NUM_ARGS()) {
  3800. case 1:
  3801. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &from, &from_len) == FAILURE) {
  3802. return;
  3803. }
  3804. pgsql_link = NULL;
  3805. id = PGG(default_link);
  3806. break;
  3807. default:
  3808. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &pgsql_link, &from, &from_len) == FAILURE) {
  3809. return;
  3810. }
  3811. break;
  3812. }
  3813. to = (char *) safe_emalloc_string(from_len, 2, 1);
  3814. #ifdef HAVE_PQESCAPE_CONN
  3815. if (pgsql_link != NULL || id != -1) {
  3816. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  3817. to_len = (int) PQescapeStringConn(pgsql, to, from, (size_t)from_len, NULL);
  3818. } else
  3819. #endif
  3820. to_len = (int) PQescapeString(to, from, (size_t)from_len);
  3821. RETURN_STRINGL(to, to_len, 0);
  3822. }
  3823. /* }}} */
  3824. /* {{{ proto string pg_escape_bytea([resource connection,] string data)
  3825. Escape binary for bytea type */
  3826. PHP_FUNCTION(pg_escape_bytea)
  3827. {
  3828. char *from = NULL, *to = NULL;
  3829. size_t to_len;
  3830. int from_len, id = -1;
  3831. #ifdef HAVE_PQESCAPE_BYTEA_CONN
  3832. PGconn *pgsql;
  3833. #endif
  3834. zval *pgsql_link;
  3835. switch (ZEND_NUM_ARGS()) {
  3836. case 1:
  3837. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &from, &from_len) == FAILURE) {
  3838. return;
  3839. }
  3840. pgsql_link = NULL;
  3841. id = PGG(default_link);
  3842. break;
  3843. default:
  3844. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &pgsql_link, &from, &from_len) == FAILURE) {
  3845. return;
  3846. }
  3847. break;
  3848. }
  3849. #ifdef HAVE_PQESCAPE_BYTEA_CONN
  3850. if (pgsql_link != NULL || id != -1) {
  3851. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  3852. to = (char *)PQescapeByteaConn(pgsql, (unsigned char *)from, (size_t)from_len, &to_len);
  3853. } else
  3854. #endif
  3855. to = (char *)PQescapeBytea((unsigned char*)from, from_len, &to_len);
  3856. RETVAL_STRINGL_CHECK(to, to_len-1, 1); /* to_len includes additional '\0' */
  3857. PQfreemem(to);
  3858. }
  3859. /* }}} */
  3860. #if !HAVE_PQUNESCAPEBYTEA
  3861. /* PQunescapeBytea() from PostgreSQL 7.3 to provide bytea unescape feature to 7.2 users.
  3862. Renamed to php_pgsql_unescape_bytea() */
  3863. /*
  3864. * PQunescapeBytea - converts the null terminated string representation
  3865. * of a bytea, strtext, into binary, filling a buffer. It returns a
  3866. * pointer to the buffer which is NULL on error, and the size of the
  3867. * buffer in retbuflen. The pointer may subsequently be used as an
  3868. * argument to the function free(3). It is the reverse of PQescapeBytea.
  3869. *
  3870. * The following transformations are reversed:
  3871. * '\0' == ASCII 0 == \000
  3872. * '\'' == ASCII 39 == \'
  3873. * '\\' == ASCII 92 == \\
  3874. *
  3875. * States:
  3876. * 0 normal 0->1->2->3->4
  3877. * 1 \ 1->5
  3878. * 2 \0 1->6
  3879. * 3 \00
  3880. * 4 \000
  3881. * 5 \'
  3882. * 6 \\
  3883. */
  3884. static unsigned char * php_pgsql_unescape_bytea(unsigned char *strtext, size_t *retbuflen)
  3885. {
  3886. size_t buflen;
  3887. unsigned char *buffer,
  3888. *sp,
  3889. *bp;
  3890. unsigned int state = 0;
  3891. if (strtext == NULL)
  3892. return NULL;
  3893. buflen = strlen(strtext); /* will shrink, also we discover if
  3894. * strtext */
  3895. buffer = (unsigned char *) emalloc(buflen); /* isn't NULL terminated */
  3896. for (bp = buffer, sp = strtext; *sp != '\0'; bp++, sp++)
  3897. {
  3898. switch (state)
  3899. {
  3900. case 0:
  3901. if (*sp == '\\')
  3902. state = 1;
  3903. *bp = *sp;
  3904. break;
  3905. case 1:
  3906. if (*sp == '\'') /* state=5 */
  3907. { /* replace \' with 39 */
  3908. bp--;
  3909. *bp = '\'';
  3910. buflen--;
  3911. state = 0;
  3912. }
  3913. else if (*sp == '\\') /* state=6 */
  3914. { /* replace \\ with 92 */
  3915. bp--;
  3916. *bp = '\\';
  3917. buflen--;
  3918. state = 0;
  3919. }
  3920. else
  3921. {
  3922. if (isdigit(*sp))
  3923. state = 2;
  3924. else
  3925. state = 0;
  3926. *bp = *sp;
  3927. }
  3928. break;
  3929. case 2:
  3930. if (isdigit(*sp))
  3931. state = 3;
  3932. else
  3933. state = 0;
  3934. *bp = *sp;
  3935. break;
  3936. case 3:
  3937. if (isdigit(*sp)) /* state=4 */
  3938. {
  3939. unsigned char *start, *end, buf[4]; /* 000 + '\0' */
  3940. bp -= 3;
  3941. memcpy(buf, sp-2, 3);
  3942. buf[3] = '\0';
  3943. start = buf;
  3944. *bp = (unsigned char)strtoul(start, (char **)&end, 8);
  3945. buflen -= 3;
  3946. state = 0;
  3947. }
  3948. else
  3949. {
  3950. *bp = *sp;
  3951. state = 0;
  3952. }
  3953. break;
  3954. }
  3955. }
  3956. buffer = erealloc(buffer, buflen+1);
  3957. buffer[buflen] = '\0';
  3958. *retbuflen = buflen;
  3959. return buffer;
  3960. }
  3961. #endif
  3962. /* {{{ proto string pg_unescape_bytea(string data)
  3963. Unescape binary for bytea type */
  3964. PHP_FUNCTION(pg_unescape_bytea)
  3965. {
  3966. char *from = NULL, *to = NULL, *tmp = NULL;
  3967. size_t to_len;
  3968. int from_len;
  3969. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s",
  3970. &from, &from_len) == FAILURE) {
  3971. return;
  3972. }
  3973. #if HAVE_PQUNESCAPEBYTEA
  3974. tmp = (char *)PQunescapeBytea((unsigned char*)from, &to_len);
  3975. to = estrndup(tmp, to_len);
  3976. PQfreemem(tmp);
  3977. #else
  3978. to = (char *)php_pgsql_unescape_bytea((unsigned char*)from, &to_len);
  3979. #endif
  3980. if (!to) {
  3981. php_error_docref(NULL TSRMLS_CC, E_WARNING,"Invalid parameter");
  3982. RETURN_FALSE;
  3983. }
  3984. RETVAL_STRINGL(to, to_len, 0);
  3985. }
  3986. /* }}} */
  3987. #endif
  3988. #ifdef HAVE_PQESCAPE
  3989. static void php_pgsql_escape_internal(INTERNAL_FUNCTION_PARAMETERS, int escape_literal) {
  3990. char *from = NULL, *to = NULL;
  3991. zval *pgsql_link = NULL;
  3992. PGconn *pgsql;
  3993. int from_len;
  3994. int id = -1;
  3995. char *tmp;
  3996. switch (ZEND_NUM_ARGS()) {
  3997. case 1:
  3998. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &from, &from_len) == FAILURE) {
  3999. return;
  4000. }
  4001. pgsql_link = NULL;
  4002. id = PGG(default_link);
  4003. break;
  4004. default:
  4005. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &pgsql_link, &from, &from_len) == FAILURE) {
  4006. return;
  4007. }
  4008. break;
  4009. }
  4010. if (pgsql_link == NULL && id == -1) {
  4011. php_error_docref(NULL TSRMLS_CC, E_WARNING,"Cannot get default pgsql link");
  4012. RETURN_FALSE;
  4013. }
  4014. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  4015. if (pgsql == NULL) {
  4016. php_error_docref(NULL TSRMLS_CC, E_WARNING,"Cannot get pgsql link");
  4017. RETURN_FALSE;
  4018. }
  4019. if (escape_literal) {
  4020. tmp = PGSQLescapeLiteral(pgsql, from, (size_t)from_len);
  4021. } else {
  4022. tmp = PGSQLescapeIdentifier(pgsql, from, (size_t)from_len);
  4023. }
  4024. if (!tmp) {
  4025. php_error_docref(NULL TSRMLS_CC, E_WARNING,"Failed to escape");
  4026. RETURN_FALSE;
  4027. }
  4028. to = estrdup(tmp);
  4029. PGSQLfree(tmp);
  4030. RETVAL_STRINGL_CHECK(to, strlen(to), 0);
  4031. }
  4032. /* {{{ proto string pg_escape_literal([resource connection,] string data)
  4033. Escape parameter as string literal (i.e. parameter) */
  4034. PHP_FUNCTION(pg_escape_literal)
  4035. {
  4036. php_pgsql_escape_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
  4037. }
  4038. /* }}} */
  4039. /* {{{ proto string pg_escape_identifier([resource connection,] string data)
  4040. Escape identifier (i.e. table name, field name) */
  4041. PHP_FUNCTION(pg_escape_identifier)
  4042. {
  4043. php_pgsql_escape_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
  4044. }
  4045. /* }}} */
  4046. #endif
  4047. /* {{{ proto string pg_result_error(resource result)
  4048. Get error message associated with result */
  4049. PHP_FUNCTION(pg_result_error)
  4050. {
  4051. zval *result;
  4052. PGresult *pgsql_result;
  4053. pgsql_result_handle *pg_result;
  4054. char *err = NULL;
  4055. if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r",
  4056. &result) == FAILURE) {
  4057. RETURN_FALSE;
  4058. }
  4059. ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result);
  4060. pgsql_result = pg_result->result;
  4061. if (!pgsql_result) {
  4062. RETURN_FALSE;
  4063. }
  4064. err = (char *)PQresultErrorMessage(pgsql_result);
  4065. RETURN_STRING(err,1);
  4066. }
  4067. /* }}} */
  4068. #if HAVE_PQRESULTERRORFIELD
  4069. /* {{{ proto string pg_result_error_field(resource result, int fieldcode)
  4070. Get error message field associated with result */
  4071. PHP_FUNCTION(pg_result_error_field)
  4072. {
  4073. zval *result;
  4074. long fieldcode;
  4075. PGresult *pgsql_result;
  4076. pgsql_result_handle *pg_result;
  4077. char *field = NULL;
  4078. if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "rl",
  4079. &result, &fieldcode) == FAILURE) {
  4080. RETURN_FALSE;
  4081. }
  4082. ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result);
  4083. pgsql_result = pg_result->result;
  4084. if (!pgsql_result) {
  4085. RETURN_FALSE;
  4086. }
  4087. if (fieldcode & (PG_DIAG_SEVERITY|PG_DIAG_SQLSTATE|PG_DIAG_MESSAGE_PRIMARY|PG_DIAG_MESSAGE_DETAIL
  4088. |PG_DIAG_MESSAGE_HINT|PG_DIAG_STATEMENT_POSITION
  4089. #if PG_DIAG_INTERNAL_POSITION
  4090. |PG_DIAG_INTERNAL_POSITION
  4091. #endif
  4092. #if PG_DIAG_INTERNAL_QUERY
  4093. |PG_DIAG_INTERNAL_QUERY
  4094. #endif
  4095. |PG_DIAG_CONTEXT|PG_DIAG_SOURCE_FILE|PG_DIAG_SOURCE_LINE
  4096. |PG_DIAG_SOURCE_FUNCTION)) {
  4097. field = (char *)PQresultErrorField(pgsql_result, fieldcode);
  4098. if (field == NULL) {
  4099. RETURN_NULL();
  4100. } else {
  4101. RETURN_STRING(field, 1);
  4102. }
  4103. } else {
  4104. RETURN_FALSE;
  4105. }
  4106. }
  4107. /* }}} */
  4108. #endif
  4109. /* {{{ proto int pg_connection_status(resource connection)
  4110. Get connection status */
  4111. PHP_FUNCTION(pg_connection_status)
  4112. {
  4113. zval *pgsql_link = NULL;
  4114. int id = -1;
  4115. PGconn *pgsql;
  4116. if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r",
  4117. &pgsql_link) == FAILURE) {
  4118. RETURN_FALSE;
  4119. }
  4120. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  4121. RETURN_LONG(PQstatus(pgsql));
  4122. }
  4123. /* }}} */
  4124. #if HAVE_PGTRANSACTIONSTATUS
  4125. /* {{{ proto int pg_transaction_status(resource connection)
  4126. Get transaction status */
  4127. PHP_FUNCTION(pg_transaction_status)
  4128. {
  4129. zval *pgsql_link = NULL;
  4130. int id = -1;
  4131. PGconn *pgsql;
  4132. if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r",
  4133. &pgsql_link) == FAILURE) {
  4134. RETURN_FALSE;
  4135. }
  4136. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  4137. RETURN_LONG(PQtransactionStatus(pgsql));
  4138. }
  4139. #endif
  4140. /* }}} */
  4141. /* {{{ proto bool pg_connection_reset(resource connection)
  4142. Reset connection (reconnect) */
  4143. PHP_FUNCTION(pg_connection_reset)
  4144. {
  4145. zval *pgsql_link;
  4146. int id = -1;
  4147. PGconn *pgsql;
  4148. if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r",
  4149. &pgsql_link) == FAILURE) {
  4150. RETURN_FALSE;
  4151. }
  4152. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  4153. PQreset(pgsql);
  4154. if (PQstatus(pgsql) == CONNECTION_BAD) {
  4155. RETURN_FALSE;
  4156. }
  4157. RETURN_TRUE;
  4158. }
  4159. /* }}} */
  4160. #define PHP_PG_ASYNC_IS_BUSY 1
  4161. #define PHP_PG_ASYNC_REQUEST_CANCEL 2
  4162. /* {{{ php_pgsql_flush_query
  4163. */
  4164. static int php_pgsql_flush_query(PGconn *pgsql TSRMLS_DC)
  4165. {
  4166. PGresult *res;
  4167. int leftover = 0;
  4168. if (PQ_SETNONBLOCKING(pgsql, 1)) {
  4169. php_error_docref(NULL TSRMLS_CC, E_NOTICE,"Cannot set connection to nonblocking mode");
  4170. return -1;
  4171. }
  4172. while ((res = PQgetResult(pgsql))) {
  4173. PQclear(res);
  4174. leftover++;
  4175. }
  4176. PQ_SETNONBLOCKING(pgsql, 0);
  4177. return leftover;
  4178. }
  4179. /* }}} */
  4180. /* {{{ php_pgsql_do_async
  4181. */
  4182. static void php_pgsql_do_async(INTERNAL_FUNCTION_PARAMETERS, int entry_type)
  4183. {
  4184. zval *pgsql_link;
  4185. int id = -1;
  4186. PGconn *pgsql;
  4187. PGresult *pgsql_result;
  4188. if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r",
  4189. &pgsql_link) == FAILURE) {
  4190. RETURN_FALSE;
  4191. }
  4192. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  4193. if (PQ_SETNONBLOCKING(pgsql, 1)) {
  4194. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to nonblocking mode");
  4195. RETURN_FALSE;
  4196. }
  4197. switch(entry_type) {
  4198. case PHP_PG_ASYNC_IS_BUSY:
  4199. PQconsumeInput(pgsql);
  4200. Z_LVAL_P(return_value) = PQisBusy(pgsql);
  4201. Z_TYPE_P(return_value) = IS_LONG;
  4202. break;
  4203. case PHP_PG_ASYNC_REQUEST_CANCEL:
  4204. Z_LVAL_P(return_value) = PQrequestCancel(pgsql);
  4205. Z_TYPE_P(return_value) = IS_LONG;
  4206. while ((pgsql_result = PQgetResult(pgsql))) {
  4207. PQclear(pgsql_result);
  4208. }
  4209. break;
  4210. default:
  4211. php_error_docref(NULL TSRMLS_CC, E_ERROR, "PostgreSQL module error, please report this error");
  4212. break;
  4213. }
  4214. if (PQ_SETNONBLOCKING(pgsql, 0)) {
  4215. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to blocking mode");
  4216. }
  4217. convert_to_boolean_ex(&return_value);
  4218. }
  4219. /* }}} */
  4220. /* {{{ proto bool pg_cancel_query(resource connection)
  4221. Cancel request */
  4222. PHP_FUNCTION(pg_cancel_query)
  4223. {
  4224. php_pgsql_do_async(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_PG_ASYNC_REQUEST_CANCEL);
  4225. }
  4226. /* }}} */
  4227. /* {{{ proto bool pg_connection_busy(resource connection)
  4228. Get connection is busy or not */
  4229. PHP_FUNCTION(pg_connection_busy)
  4230. {
  4231. php_pgsql_do_async(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_PG_ASYNC_IS_BUSY);
  4232. }
  4233. /* }}} */
  4234. static int _php_pgsql_link_has_results(PGconn *pgsql)
  4235. {
  4236. PGresult *result;
  4237. while ((result = PQgetResult(pgsql))) {
  4238. PQclear(result);
  4239. return 1;
  4240. }
  4241. return 0;
  4242. }
  4243. /* {{{ proto bool pg_send_query(resource connection, string query)
  4244. Send asynchronous query */
  4245. PHP_FUNCTION(pg_send_query)
  4246. {
  4247. zval *pgsql_link;
  4248. char *query;
  4249. int len;
  4250. int id = -1;
  4251. PGconn *pgsql;
  4252. int is_non_blocking;
  4253. int ret;
  4254. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &pgsql_link, &query, &len) == FAILURE) {
  4255. return;
  4256. }
  4257. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  4258. is_non_blocking = PQisnonblocking(pgsql);
  4259. if (is_non_blocking == 0 && PQ_SETNONBLOCKING(pgsql, 1) == -1) {
  4260. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to nonblocking mode");
  4261. RETURN_FALSE;
  4262. }
  4263. if (_php_pgsql_link_has_results(pgsql)) {
  4264. php_error_docref(NULL TSRMLS_CC, E_NOTICE,
  4265. "There are results on this connection. Call pg_get_result() until it returns FALSE");
  4266. }
  4267. if (is_non_blocking) {
  4268. if (!PQsendQuery(pgsql, query)) {
  4269. RETURN_FALSE;
  4270. }
  4271. ret = PQflush(pgsql);
  4272. } else {
  4273. if (!PQsendQuery(pgsql, query)) {
  4274. if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
  4275. PQreset(pgsql);
  4276. }
  4277. if (!PQsendQuery(pgsql, query)) {
  4278. RETURN_FALSE;
  4279. }
  4280. }
  4281. /* Wait to finish sending buffer */
  4282. while ((ret = PQflush(pgsql))) {
  4283. if (ret == -1) {
  4284. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Could not empty PostgreSQL send buffer");
  4285. break;
  4286. }
  4287. usleep(10000);
  4288. }
  4289. if (PQ_SETNONBLOCKING(pgsql, 0)) {
  4290. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to blocking mode");
  4291. }
  4292. }
  4293. if (ret == 0) {
  4294. RETURN_TRUE;
  4295. } else if (ret == -1) {
  4296. RETURN_FALSE;
  4297. } else {
  4298. RETURN_LONG(0);
  4299. }
  4300. }
  4301. /* }}} */
  4302. #if HAVE_PQSENDQUERYPARAMS
  4303. /* {{{ proto bool pg_send_query_params(resource connection, string query, array params)
  4304. Send asynchronous parameterized query */
  4305. PHP_FUNCTION(pg_send_query_params)
  4306. {
  4307. zval *pgsql_link, *pv_param_arr, **tmp;
  4308. int num_params = 0;
  4309. char **params = NULL;
  4310. char *query;
  4311. int query_len, id = -1;
  4312. PGconn *pgsql;
  4313. int is_non_blocking;
  4314. int ret;
  4315. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsa/", &pgsql_link, &query, &query_len, &pv_param_arr) == FAILURE) {
  4316. return;
  4317. }
  4318. if (pgsql_link == NULL && id == -1) {
  4319. RETURN_FALSE;
  4320. }
  4321. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  4322. is_non_blocking = PQisnonblocking(pgsql);
  4323. if (is_non_blocking == 0 && PQ_SETNONBLOCKING(pgsql, 1) == -1) {
  4324. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to nonblocking mode");
  4325. RETURN_FALSE;
  4326. }
  4327. if (_php_pgsql_link_has_results(pgsql)) {
  4328. php_error_docref(NULL TSRMLS_CC, E_NOTICE,
  4329. "There are results on this connection. Call pg_get_result() until it returns FALSE");
  4330. }
  4331. zend_hash_internal_pointer_reset(Z_ARRVAL_P(pv_param_arr));
  4332. num_params = zend_hash_num_elements(Z_ARRVAL_P(pv_param_arr));
  4333. if (num_params > 0) {
  4334. int i = 0;
  4335. params = (char **)safe_emalloc(sizeof(char *), num_params, 0);
  4336. for(i = 0; i < num_params; i++) {
  4337. if (zend_hash_get_current_data(Z_ARRVAL_P(pv_param_arr), (void **) &tmp) == FAILURE) {
  4338. php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error getting parameter");
  4339. _php_pgsql_free_params(params, num_params);
  4340. RETURN_FALSE;
  4341. }
  4342. if (Z_TYPE_PP(tmp) == IS_NULL) {
  4343. params[i] = NULL;
  4344. } else {
  4345. zval tmp_val = **tmp;
  4346. zval_copy_ctor(&tmp_val);
  4347. convert_to_string(&tmp_val);
  4348. if (Z_TYPE(tmp_val) != IS_STRING) {
  4349. php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error converting parameter");
  4350. zval_dtor(&tmp_val);
  4351. _php_pgsql_free_params(params, num_params);
  4352. RETURN_FALSE;
  4353. }
  4354. params[i] = estrndup(Z_STRVAL(tmp_val), Z_STRLEN(tmp_val));
  4355. zval_dtor(&tmp_val);
  4356. }
  4357. zend_hash_move_forward(Z_ARRVAL_P(pv_param_arr));
  4358. }
  4359. }
  4360. if (PQsendQueryParams(pgsql, query, num_params, NULL, (const char * const *)params, NULL, NULL, 0)) {
  4361. _php_pgsql_free_params(params, num_params);
  4362. } else if (is_non_blocking) {
  4363. _php_pgsql_free_params(params, num_params);
  4364. RETURN_FALSE;
  4365. } else {
  4366. if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
  4367. PQreset(pgsql);
  4368. }
  4369. if (!PQsendQueryParams(pgsql, query, num_params, NULL, (const char * const *)params, NULL, NULL, 0)) {
  4370. _php_pgsql_free_params(params, num_params);
  4371. RETURN_FALSE;
  4372. }
  4373. }
  4374. if (is_non_blocking) {
  4375. ret = PQflush(pgsql);
  4376. } else {
  4377. /* Wait to finish sending buffer */
  4378. while ((ret = PQflush(pgsql))) {
  4379. if (ret == -1) {
  4380. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Could not empty PostgreSQL send buffer");
  4381. break;
  4382. }
  4383. usleep(10000);
  4384. }
  4385. if (PQ_SETNONBLOCKING(pgsql, 0) != 0) {
  4386. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to blocking mode");
  4387. }
  4388. }
  4389. if (ret == 0) {
  4390. RETURN_TRUE;
  4391. } else if (ret == -1) {
  4392. RETURN_FALSE;
  4393. } else {
  4394. RETURN_LONG(0);
  4395. }
  4396. }
  4397. /* }}} */
  4398. #endif
  4399. #if HAVE_PQSENDPREPARE
  4400. /* {{{ proto bool pg_send_prepare(resource connection, string stmtname, string query)
  4401. Asynchronously prepare a query for future execution */
  4402. PHP_FUNCTION(pg_send_prepare)
  4403. {
  4404. zval *pgsql_link;
  4405. char *query, *stmtname;
  4406. int stmtname_len, query_len, id = -1;
  4407. PGconn *pgsql;
  4408. int is_non_blocking;
  4409. int ret;
  4410. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rss", &pgsql_link, &stmtname, &stmtname_len, &query, &query_len) == FAILURE) {
  4411. return;
  4412. }
  4413. if (pgsql_link == NULL && id == -1) {
  4414. RETURN_FALSE;
  4415. }
  4416. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  4417. is_non_blocking = PQisnonblocking(pgsql);
  4418. if (is_non_blocking == 0 && PQ_SETNONBLOCKING(pgsql, 1) == -1) {
  4419. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to nonblocking mode");
  4420. RETURN_FALSE;
  4421. }
  4422. if (_php_pgsql_link_has_results(pgsql)) {
  4423. php_error_docref(NULL TSRMLS_CC, E_NOTICE,
  4424. "There are results on this connection. Call pg_get_result() until it returns FALSE");
  4425. }
  4426. if (!PQsendPrepare(pgsql, stmtname, query, 0, NULL)) {
  4427. if (is_non_blocking) {
  4428. RETURN_FALSE;
  4429. } else {
  4430. if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
  4431. PQreset(pgsql);
  4432. }
  4433. if (!PQsendPrepare(pgsql, stmtname, query, 0, NULL)) {
  4434. RETURN_FALSE;
  4435. }
  4436. }
  4437. }
  4438. if (is_non_blocking) {
  4439. ret = PQflush(pgsql);
  4440. } else {
  4441. /* Wait to finish sending buffer */
  4442. while ((ret = PQflush(pgsql))) {
  4443. if (ret == -1) {
  4444. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Could not empty PostgreSQL send buffer");
  4445. break;
  4446. }
  4447. usleep(10000);
  4448. }
  4449. if (PQ_SETNONBLOCKING(pgsql, 0) != 0) {
  4450. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to blocking mode");
  4451. }
  4452. }
  4453. if (ret == 0) {
  4454. RETURN_TRUE;
  4455. } else if (ret == -1) {
  4456. RETURN_FALSE;
  4457. } else {
  4458. RETURN_LONG(0);
  4459. }
  4460. }
  4461. /* }}} */
  4462. #endif
  4463. #if HAVE_PQSENDQUERYPREPARED
  4464. /* {{{ proto bool pg_send_execute(resource connection, string stmtname, array params)
  4465. Executes prevriously prepared stmtname asynchronously */
  4466. PHP_FUNCTION(pg_send_execute)
  4467. {
  4468. zval *pgsql_link;
  4469. zval *pv_param_arr, **tmp;
  4470. int num_params = 0;
  4471. char **params = NULL;
  4472. char *stmtname;
  4473. int stmtname_len, id = -1;
  4474. PGconn *pgsql;
  4475. int is_non_blocking;
  4476. int ret;
  4477. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsa", &pgsql_link, &stmtname, &stmtname_len, &pv_param_arr) == FAILURE) {
  4478. return;
  4479. }
  4480. if (pgsql_link == NULL && id == -1) {
  4481. RETURN_FALSE;
  4482. }
  4483. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  4484. is_non_blocking = PQisnonblocking(pgsql);
  4485. if (is_non_blocking == 0 && PQ_SETNONBLOCKING(pgsql, 1) == -1) {
  4486. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to nonblocking mode");
  4487. RETURN_FALSE;
  4488. }
  4489. if (_php_pgsql_link_has_results(pgsql)) {
  4490. php_error_docref(NULL TSRMLS_CC, E_NOTICE,
  4491. "There are results on this connection. Call pg_get_result() until it returns FALSE");
  4492. }
  4493. zend_hash_internal_pointer_reset(Z_ARRVAL_P(pv_param_arr));
  4494. num_params = zend_hash_num_elements(Z_ARRVAL_P(pv_param_arr));
  4495. if (num_params > 0) {
  4496. int i = 0;
  4497. params = (char **)safe_emalloc(sizeof(char *), num_params, 0);
  4498. for (i = 0; i < num_params; i++) {
  4499. if (zend_hash_get_current_data(Z_ARRVAL_P(pv_param_arr), (void **) &tmp) == FAILURE) {
  4500. php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error getting parameter");
  4501. _php_pgsql_free_params(params, num_params);
  4502. RETURN_FALSE;
  4503. }
  4504. if (Z_TYPE_PP(tmp) == IS_NULL) {
  4505. params[i] = NULL;
  4506. } else {
  4507. zval tmp_val = **tmp;
  4508. zval_copy_ctor(&tmp_val);
  4509. convert_to_string(&tmp_val);
  4510. if (Z_TYPE(tmp_val) != IS_STRING) {
  4511. php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error converting parameter");
  4512. zval_dtor(&tmp_val);
  4513. _php_pgsql_free_params(params, num_params);
  4514. RETURN_FALSE;
  4515. }
  4516. params[i] = estrndup(Z_STRVAL(tmp_val), Z_STRLEN(tmp_val));
  4517. zval_dtor(&tmp_val);
  4518. }
  4519. zend_hash_move_forward(Z_ARRVAL_P(pv_param_arr));
  4520. }
  4521. }
  4522. if (PQsendQueryPrepared(pgsql, stmtname, num_params, (const char * const *)params, NULL, NULL, 0)) {
  4523. _php_pgsql_free_params(params, num_params);
  4524. } else if (is_non_blocking) {
  4525. _php_pgsql_free_params(params, num_params);
  4526. RETURN_FALSE;
  4527. } else {
  4528. if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
  4529. PQreset(pgsql);
  4530. }
  4531. if (!PQsendQueryPrepared(pgsql, stmtname, num_params, (const char * const *)params, NULL, NULL, 0)) {
  4532. _php_pgsql_free_params(params, num_params);
  4533. RETURN_FALSE;
  4534. }
  4535. }
  4536. if (is_non_blocking) {
  4537. ret = PQflush(pgsql);
  4538. } else {
  4539. /* Wait to finish sending buffer */
  4540. while ((ret = PQflush(pgsql))) {
  4541. if (ret == -1) {
  4542. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Could not empty PostgreSQL send buffer");
  4543. break;
  4544. }
  4545. usleep(10000);
  4546. }
  4547. if (PQ_SETNONBLOCKING(pgsql, 0) != 0) {
  4548. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to blocking mode");
  4549. }
  4550. }
  4551. if (ret == 0) {
  4552. RETURN_TRUE;
  4553. } else if (ret == -1) {
  4554. RETURN_FALSE;
  4555. } else {
  4556. RETURN_LONG(0);
  4557. }
  4558. }
  4559. /* }}} */
  4560. #endif
  4561. /* {{{ proto resource pg_get_result(resource connection)
  4562. Get asynchronous query result */
  4563. PHP_FUNCTION(pg_get_result)
  4564. {
  4565. zval *pgsql_link;
  4566. int id = -1;
  4567. PGconn *pgsql;
  4568. PGresult *pgsql_result;
  4569. pgsql_result_handle *pg_result;
  4570. if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r", &pgsql_link) == FAILURE) {
  4571. RETURN_FALSE;
  4572. }
  4573. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  4574. pgsql_result = PQgetResult(pgsql);
  4575. if (!pgsql_result) {
  4576. /* no result */
  4577. RETURN_FALSE;
  4578. }
  4579. pg_result = (pgsql_result_handle *) emalloc(sizeof(pgsql_result_handle));
  4580. pg_result->conn = pgsql;
  4581. pg_result->result = pgsql_result;
  4582. pg_result->row = 0;
  4583. ZEND_REGISTER_RESOURCE(return_value, pg_result, le_result);
  4584. }
  4585. /* }}} */
  4586. /* {{{ proto mixed pg_result_status(resource result[, long result_type])
  4587. Get status of query result */
  4588. PHP_FUNCTION(pg_result_status)
  4589. {
  4590. zval *result;
  4591. long result_type = PGSQL_STATUS_LONG;
  4592. ExecStatusType status;
  4593. PGresult *pgsql_result;
  4594. pgsql_result_handle *pg_result;
  4595. if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r|l",
  4596. &result, &result_type) == FAILURE) {
  4597. RETURN_FALSE;
  4598. }
  4599. ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result);
  4600. pgsql_result = pg_result->result;
  4601. if (result_type == PGSQL_STATUS_LONG) {
  4602. status = PQresultStatus(pgsql_result);
  4603. RETURN_LONG((int)status);
  4604. }
  4605. else if (result_type == PGSQL_STATUS_STRING) {
  4606. RETURN_STRING(PQcmdStatus(pgsql_result), 1);
  4607. }
  4608. else {
  4609. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Optional 2nd parameter should be PGSQL_STATUS_LONG or PGSQL_STATUS_STRING");
  4610. RETURN_FALSE;
  4611. }
  4612. }
  4613. /* }}} */
  4614. /* {{{ proto array pg_get_notify([resource connection[, result_type]])
  4615. Get asynchronous notification */
  4616. PHP_FUNCTION(pg_get_notify)
  4617. {
  4618. zval *pgsql_link;
  4619. int id = -1;
  4620. long result_type = PGSQL_ASSOC;
  4621. PGconn *pgsql;
  4622. PGnotify *pgsql_notify;
  4623. if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r|l",
  4624. &pgsql_link, &result_type) == FAILURE) {
  4625. RETURN_FALSE;
  4626. }
  4627. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  4628. if (!(result_type & PGSQL_BOTH)) {
  4629. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid result type");
  4630. RETURN_FALSE;
  4631. }
  4632. PQconsumeInput(pgsql);
  4633. pgsql_notify = PQnotifies(pgsql);
  4634. if (!pgsql_notify) {
  4635. /* no notify message */
  4636. RETURN_FALSE;
  4637. }
  4638. array_init(return_value);
  4639. if (result_type & PGSQL_NUM) {
  4640. add_index_string(return_value, 0, pgsql_notify->relname, 1);
  4641. add_index_long(return_value, 1, pgsql_notify->be_pid);
  4642. #if HAVE_PQPROTOCOLVERSION && HAVE_PQPARAMETERSTATUS
  4643. if (PQprotocolVersion(pgsql) >= 3 && atof(PQparameterStatus(pgsql, "server_version")) >= 9.0) {
  4644. #else
  4645. if (atof(PG_VERSION) >= 9.0) {
  4646. #endif
  4647. #if HAVE_PQPARAMETERSTATUS
  4648. add_index_string(return_value, 2, pgsql_notify->extra, 1);
  4649. #endif
  4650. }
  4651. }
  4652. if (result_type & PGSQL_ASSOC) {
  4653. add_assoc_string(return_value, "message", pgsql_notify->relname, 1);
  4654. add_assoc_long(return_value, "pid", pgsql_notify->be_pid);
  4655. #if HAVE_PQPROTOCOLVERSION && HAVE_PQPARAMETERSTATUS
  4656. if (PQprotocolVersion(pgsql) >= 3 && atof(PQparameterStatus(pgsql, "server_version")) >= 9.0) {
  4657. #else
  4658. if (atof(PG_VERSION) >= 9.0) {
  4659. #endif
  4660. #if HAVE_PQPARAMETERSTATUS
  4661. add_assoc_string(return_value, "payload", pgsql_notify->extra, 1);
  4662. #endif
  4663. }
  4664. }
  4665. PQfreemem(pgsql_notify);
  4666. }
  4667. /* }}} */
  4668. /* {{{ proto int pg_get_pid([resource connection)
  4669. Get backend(server) pid */
  4670. PHP_FUNCTION(pg_get_pid)
  4671. {
  4672. zval *pgsql_link;
  4673. int id = -1;
  4674. PGconn *pgsql;
  4675. if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r",
  4676. &pgsql_link) == FAILURE) {
  4677. RETURN_FALSE;
  4678. }
  4679. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  4680. RETURN_LONG(PQbackendPID(pgsql));
  4681. }
  4682. /* }}} */
  4683. static size_t php_pgsql_fd_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC)
  4684. {
  4685. return 0;
  4686. }
  4687. static size_t php_pgsql_fd_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
  4688. {
  4689. return 0;
  4690. }
  4691. static int php_pgsql_fd_close(php_stream *stream, int close_handle TSRMLS_DC)
  4692. {
  4693. return EOF;
  4694. }
  4695. static int php_pgsql_fd_flush(php_stream *stream TSRMLS_DC)
  4696. {
  4697. return FAILURE;
  4698. }
  4699. static int php_pgsql_fd_set_option(php_stream *stream, int option, int value, void *ptrparam TSRMLS_DC)
  4700. {
  4701. PGconn *pgsql = (PGconn *) stream->abstract;
  4702. switch (option) {
  4703. case PHP_STREAM_OPTION_BLOCKING:
  4704. return PQ_SETNONBLOCKING(pgsql, value);
  4705. default:
  4706. return FAILURE;
  4707. }
  4708. }
  4709. static int php_pgsql_fd_cast(php_stream *stream, int cast_as, void **ret TSRMLS_DC)
  4710. {
  4711. PGconn *pgsql = (PGconn *) stream->abstract;
  4712. int fd_number;
  4713. switch (cast_as) {
  4714. case PHP_STREAM_AS_FD_FOR_SELECT:
  4715. case PHP_STREAM_AS_FD:
  4716. case PHP_STREAM_AS_SOCKETD:
  4717. if (ret) {
  4718. fd_number = PQsocket(pgsql);
  4719. if (fd_number == -1) {
  4720. return FAILURE;
  4721. }
  4722. *(php_socket_t *)ret = fd_number;
  4723. return SUCCESS;
  4724. }
  4725. default:
  4726. return FAILURE;
  4727. }
  4728. }
  4729. /* {{{ proto resource pg_socket(resource)
  4730. Get a read-only handle to the socket underlying the pgsql connection */
  4731. PHP_FUNCTION(pg_socket)
  4732. {
  4733. zval *pgsql_link;
  4734. php_stream *stream;
  4735. PGconn *pgsql;
  4736. int id = -1;
  4737. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pgsql_link) == FAILURE) {
  4738. return;
  4739. }
  4740. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  4741. stream = php_stream_alloc(&php_stream_pgsql_fd_ops, pgsql, NULL, "r");
  4742. if (stream) {
  4743. php_stream_to_zval(stream, return_value);
  4744. return;
  4745. }
  4746. RETURN_FALSE;
  4747. }
  4748. /* }}} */
  4749. /* {{{ proto bool pg_consume_input(resource)
  4750. Reads input on the connection */
  4751. PHP_FUNCTION(pg_consume_input)
  4752. {
  4753. zval *pgsql_link;
  4754. int id = -1;
  4755. PGconn *pgsql;
  4756. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pgsql_link) == FAILURE) {
  4757. return;
  4758. }
  4759. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  4760. RETURN_BOOL(PQconsumeInput(pgsql));
  4761. }
  4762. /* }}} */
  4763. /* {{{ proto mixed pg_flush(resource)
  4764. Flush outbound query data on the connection */
  4765. PHP_FUNCTION(pg_flush)
  4766. {
  4767. zval *pgsql_link;
  4768. int id = -1;
  4769. PGconn *pgsql;
  4770. int ret;
  4771. int is_non_blocking;
  4772. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pgsql_link) == FAILURE) {
  4773. return;
  4774. }
  4775. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  4776. is_non_blocking = PQisnonblocking(pgsql);
  4777. if (is_non_blocking == 0 && PQ_SETNONBLOCKING(pgsql, 1) == -1) {
  4778. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to nonblocking mode");
  4779. RETURN_FALSE;
  4780. }
  4781. ret = PQflush(pgsql);
  4782. if (is_non_blocking == 0 && PQ_SETNONBLOCKING(pgsql, 0) == -1) {
  4783. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Failed resetting connection to blocking mode");
  4784. }
  4785. switch (ret) {
  4786. case 0: RETURN_TRUE; break;
  4787. case 1: RETURN_LONG(0); break;
  4788. default: RETURN_FALSE;
  4789. }
  4790. }
  4791. /* }}} */
  4792. /* {{{ php_pgsql_meta_data
  4793. * TODO: Add meta_data cache for better performance
  4794. */
  4795. PHP_PGSQL_API int php_pgsql_meta_data(PGconn *pg_link, const char *table_name, zval *meta, zend_bool extended TSRMLS_DC)
  4796. {
  4797. PGresult *pg_result;
  4798. char *src, *tmp_name, *tmp_name2 = NULL;
  4799. char *escaped;
  4800. smart_str querystr = {0};
  4801. size_t new_len;
  4802. int i, num_rows;
  4803. zval *elem;
  4804. if (!*table_name) {
  4805. php_error_docref(NULL TSRMLS_CC, E_WARNING, "The table name must be specified");
  4806. return FAILURE;
  4807. }
  4808. src = estrdup(table_name);
  4809. tmp_name = php_strtok_r(src, ".", &tmp_name2);
  4810. if (!tmp_name) {
  4811. efree(src);
  4812. php_error_docref(NULL TSRMLS_CC, E_WARNING, "The table name must be specified");
  4813. return FAILURE;
  4814. }
  4815. if (!tmp_name2 || !*tmp_name2) {
  4816. /* Default schema */
  4817. tmp_name2 = tmp_name;
  4818. tmp_name = "public";
  4819. }
  4820. if (extended) {
  4821. smart_str_appends(&querystr,
  4822. "SELECT a.attname, a.attnum, t.typname, a.attlen, a.attnotNULL, a.atthasdef, a.attndims, t.typtype, "
  4823. "d.description "
  4824. "FROM pg_class as c "
  4825. " JOIN pg_attribute a ON (a.attrelid = c.oid) "
  4826. " JOIN pg_type t ON (a.atttypid = t.oid) "
  4827. " JOIN pg_namespace n ON (c.relnamespace = n.oid) "
  4828. " LEFT JOIN pg_description d ON (d.objoid=a.attrelid AND d.objsubid=a.attnum AND c.oid=d.objoid) "
  4829. "WHERE a.attnum > 0 AND c.relname = '");
  4830. } else {
  4831. smart_str_appends(&querystr,
  4832. "SELECT a.attname, a.attnum, t.typname, a.attlen, a.attnotnull, a.atthasdef, a.attndims, t.typtype "
  4833. "FROM pg_class as c "
  4834. " JOIN pg_attribute a ON (a.attrelid = c.oid) "
  4835. " JOIN pg_type t ON (a.atttypid = t.oid) "
  4836. " JOIN pg_namespace n ON (c.relnamespace = n.oid) "
  4837. "WHERE a.attnum > 0 AND c.relname = '");
  4838. }
  4839. escaped = (char *)safe_emalloc(strlen(tmp_name2), 2, 1);
  4840. new_len = PQescapeStringConn(pg_link, escaped, tmp_name2, strlen(tmp_name2), NULL);
  4841. if (new_len) {
  4842. smart_str_appendl(&querystr, escaped, new_len);
  4843. }
  4844. efree(escaped);
  4845. smart_str_appends(&querystr, "' AND n.nspname = '");
  4846. escaped = (char *)safe_emalloc(strlen(tmp_name), 2, 1);
  4847. new_len = PQescapeStringConn(pg_link, escaped, tmp_name, strlen(tmp_name), NULL);
  4848. if (new_len) {
  4849. smart_str_appendl(&querystr, escaped, new_len);
  4850. }
  4851. efree(escaped);
  4852. smart_str_appends(&querystr, "' ORDER BY a.attnum;");
  4853. smart_str_0(&querystr);
  4854. efree(src);
  4855. pg_result = PQexec(pg_link, querystr.c);
  4856. if (PQresultStatus(pg_result) != PGRES_TUPLES_OK || (num_rows = PQntuples(pg_result)) == 0) {
  4857. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Table '%s' doesn't exists", table_name);
  4858. smart_str_free(&querystr);
  4859. PQclear(pg_result);
  4860. return FAILURE;
  4861. }
  4862. smart_str_free(&querystr);
  4863. for (i = 0; i < num_rows; i++) {
  4864. char *name;
  4865. MAKE_STD_ZVAL(elem);
  4866. array_init(elem);
  4867. /* pg_attribute.attnum */
  4868. add_assoc_long(elem, "num", atoi(PQgetvalue(pg_result,i,1)));
  4869. /* pg_type.typname */
  4870. add_assoc_string(elem, "type", PQgetvalue(pg_result,i,2), 1);
  4871. /* pg_attribute.attlen */
  4872. add_assoc_long(elem, "len", atoi(PQgetvalue(pg_result,i,3)));
  4873. /* pg_attribute.attnonull */
  4874. add_assoc_bool(elem, "not null", !strcmp(PQgetvalue(pg_result,i,4), "t"));
  4875. /* pg_attribute.atthasdef */
  4876. add_assoc_bool(elem, "has default", !strcmp(PQgetvalue(pg_result,i,5), "t"));
  4877. /* pg_attribute.attndims */
  4878. add_assoc_long(elem, "array dims", atoi(PQgetvalue(pg_result,i,6)));
  4879. /* pg_type.typtype */
  4880. add_assoc_bool(elem, "is enum", !strcmp(PQgetvalue(pg_result,i,7), "e"));
  4881. if (extended) {
  4882. /* pg_type.typtype */
  4883. add_assoc_bool(elem, "is base", !strcmp(PQgetvalue(pg_result,i,7), "b"));
  4884. add_assoc_bool(elem, "is composite", !strcmp(PQgetvalue(pg_result,i,7), "c"));
  4885. add_assoc_bool(elem, "is pesudo", !strcmp(PQgetvalue(pg_result,i,7), "p"));
  4886. /* pg_description.description */
  4887. add_assoc_string(elem, "description", PQgetvalue(pg_result,i,8), 1);
  4888. }
  4889. /* pg_attribute.attname */
  4890. name = PQgetvalue(pg_result,i,0);
  4891. add_assoc_zval(meta, name, elem);
  4892. }
  4893. PQclear(pg_result);
  4894. return SUCCESS;
  4895. }
  4896. /* }}} */
  4897. /* {{{ proto array pg_meta_data(resource db, string table [, bool extended])
  4898. Get meta_data */
  4899. PHP_FUNCTION(pg_meta_data)
  4900. {
  4901. zval *pgsql_link;
  4902. char *table_name;
  4903. uint table_name_len;
  4904. zend_bool extended=0;
  4905. PGconn *pgsql;
  4906. int id = -1;
  4907. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|b",
  4908. &pgsql_link, &table_name, &table_name_len, &extended) == FAILURE) {
  4909. return;
  4910. }
  4911. ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  4912. array_init(return_value);
  4913. if (php_pgsql_meta_data(pgsql, table_name, return_value, extended TSRMLS_CC) == FAILURE) {
  4914. zval_dtor(return_value); /* destroy array */
  4915. RETURN_FALSE;
  4916. }
  4917. }
  4918. /* }}} */
  4919. /* {{{ php_pgsql_get_data_type
  4920. */
  4921. static php_pgsql_data_type php_pgsql_get_data_type(const char *type_name, size_t len)
  4922. {
  4923. /* This is stupid way to do. I'll fix it when I decied how to support
  4924. user defined types. (Yasuo) */
  4925. /* boolean */
  4926. if (!strcmp(type_name, "bool")|| !strcmp(type_name, "boolean"))
  4927. return PG_BOOL;
  4928. /* object id */
  4929. if (!strcmp(type_name, "oid"))
  4930. return PG_OID;
  4931. /* integer */
  4932. if (!strcmp(type_name, "int2") || !strcmp(type_name, "smallint"))
  4933. return PG_INT2;
  4934. if (!strcmp(type_name, "int4") || !strcmp(type_name, "integer"))
  4935. return PG_INT4;
  4936. if (!strcmp(type_name, "int8") || !strcmp(type_name, "bigint"))
  4937. return PG_INT8;
  4938. /* real and other */
  4939. if (!strcmp(type_name, "float4") || !strcmp(type_name, "real"))
  4940. return PG_FLOAT4;
  4941. if (!strcmp(type_name, "float8") || !strcmp(type_name, "double precision"))
  4942. return PG_FLOAT8;
  4943. if (!strcmp(type_name, "numeric"))
  4944. return PG_NUMERIC;
  4945. if (!strcmp(type_name, "money"))
  4946. return PG_MONEY;
  4947. /* character */
  4948. if (!strcmp(type_name, "text"))
  4949. return PG_TEXT;
  4950. if (!strcmp(type_name, "bpchar") || !strcmp(type_name, "character"))
  4951. return PG_CHAR;
  4952. if (!strcmp(type_name, "varchar") || !strcmp(type_name, "character varying"))
  4953. return PG_VARCHAR;
  4954. /* time and interval */
  4955. if (!strcmp(type_name, "abstime"))
  4956. return PG_UNIX_TIME;
  4957. if (!strcmp(type_name, "reltime"))
  4958. return PG_UNIX_TIME_INTERVAL;
  4959. if (!strcmp(type_name, "tinterval"))
  4960. return PG_UNIX_TIME_INTERVAL;
  4961. if (!strcmp(type_name, "date"))
  4962. return PG_DATE;
  4963. if (!strcmp(type_name, "time"))
  4964. return PG_TIME;
  4965. if (!strcmp(type_name, "time with time zone") || !strcmp(type_name, "timetz"))
  4966. return PG_TIME_WITH_TIMEZONE;
  4967. if (!strcmp(type_name, "timestamp without time zone") || !strcmp(type_name, "timestamp"))
  4968. return PG_TIMESTAMP;
  4969. if (!strcmp(type_name, "timestamp with time zone") || !strcmp(type_name, "timestamptz"))
  4970. return PG_TIMESTAMP_WITH_TIMEZONE;
  4971. if (!strcmp(type_name, "interval"))
  4972. return PG_INTERVAL;
  4973. /* binary */
  4974. if (!strcmp(type_name, "bytea"))
  4975. return PG_BYTEA;
  4976. /* network */
  4977. if (!strcmp(type_name, "cidr"))
  4978. return PG_CIDR;
  4979. if (!strcmp(type_name, "inet"))
  4980. return PG_INET;
  4981. if (!strcmp(type_name, "macaddr"))
  4982. return PG_MACADDR;
  4983. /* bit */
  4984. if (!strcmp(type_name, "bit"))
  4985. return PG_BIT;
  4986. if (!strcmp(type_name, "bit varying"))
  4987. return PG_VARBIT;
  4988. /* geometric */
  4989. if (!strcmp(type_name, "line"))
  4990. return PG_LINE;
  4991. if (!strcmp(type_name, "lseg"))
  4992. return PG_LSEG;
  4993. if (!strcmp(type_name, "box"))
  4994. return PG_BOX;
  4995. if (!strcmp(type_name, "path"))
  4996. return PG_PATH;
  4997. if (!strcmp(type_name, "point"))
  4998. return PG_POINT;
  4999. if (!strcmp(type_name, "polygon"))
  5000. return PG_POLYGON;
  5001. if (!strcmp(type_name, "circle"))
  5002. return PG_CIRCLE;
  5003. return PG_UNKNOWN;
  5004. }
  5005. /* }}} */
  5006. /* {{{ php_pgsql_convert_match
  5007. * test field value with regular expression specified.
  5008. */
  5009. static int php_pgsql_convert_match(const char *str, size_t str_len, const char *regex , int icase TSRMLS_DC)
  5010. {
  5011. regex_t re;
  5012. regmatch_t *subs;
  5013. int regopt = REG_EXTENDED;
  5014. int regerr, ret = SUCCESS;
  5015. int i;
  5016. /* Check invalid chars for POSIX regex */
  5017. for (i = 0; i < str_len; i++) {
  5018. if (str[i] == '\n' ||
  5019. str[i] == '\r' ||
  5020. str[i] == '\0' ) {
  5021. return FAILURE;
  5022. }
  5023. }
  5024. if (icase) {
  5025. regopt |= REG_ICASE;
  5026. }
  5027. regerr = regcomp(&re, regex, regopt);
  5028. if (regerr) {
  5029. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot compile regex");
  5030. regfree(&re);
  5031. return FAILURE;
  5032. }
  5033. subs = (regmatch_t *)ecalloc(sizeof(regmatch_t), re.re_nsub+1);
  5034. regerr = regexec(&re, str, re.re_nsub+1, subs, 0);
  5035. if (regerr == REG_NOMATCH) {
  5036. ret = FAILURE;
  5037. }
  5038. else if (regerr) {
  5039. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot exec regex");
  5040. ret = FAILURE;
  5041. }
  5042. regfree(&re);
  5043. efree(subs);
  5044. return ret;
  5045. }
  5046. /* }}} */
  5047. /* {{{ php_pgsql_add_quote
  5048. * add quotes around string.
  5049. */
  5050. static int php_pgsql_add_quotes(zval *src, zend_bool should_free TSRMLS_DC)
  5051. {
  5052. smart_str str = {0};
  5053. assert(Z_TYPE_P(src) == IS_STRING);
  5054. assert(should_free == 1 || should_free == 0);
  5055. smart_str_appendc(&str, 'E');
  5056. smart_str_appendc(&str, '\'');
  5057. smart_str_appendl(&str, Z_STRVAL_P(src), Z_STRLEN_P(src));
  5058. smart_str_appendc(&str, '\'');
  5059. smart_str_0(&str);
  5060. if (should_free) {
  5061. efree(Z_STRVAL_P(src));
  5062. }
  5063. Z_STRVAL_P(src) = str.c;
  5064. Z_STRLEN_P(src) = str.len;
  5065. return SUCCESS;
  5066. }
  5067. /* }}} */
  5068. #define PGSQL_CONV_CHECK_IGNORE() \
  5069. if (!err && Z_TYPE_P(new_val) == IS_STRING && !strcmp(Z_STRVAL_P(new_val), "NULL")) { \
  5070. /* if new_value is string "NULL" and field has default value, remove element to use default value */ \
  5071. if (!(opt & PGSQL_CONV_IGNORE_DEFAULT) && Z_BVAL_PP(has_default)) { \
  5072. zval_dtor(new_val); \
  5073. FREE_ZVAL(new_val); \
  5074. skip_field = 1; \
  5075. } \
  5076. /* raise error if it's not null and cannot be ignored */ \
  5077. else if (!(opt & PGSQL_CONV_IGNORE_NOT_NULL) && Z_BVAL_PP(not_null)) { \
  5078. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected NULL for 'NOT NULL' field '%s'", field ); \
  5079. err = 1; \
  5080. } \
  5081. }
  5082. /* {{{ php_pgsql_convert
  5083. * check and convert array values (fieldname=>vlaue pair) for sql
  5084. */
  5085. PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, const zval *values, zval *result, ulong opt TSRMLS_DC)
  5086. {
  5087. HashPosition pos;
  5088. char *field = NULL;
  5089. uint field_len = -1;
  5090. ulong num_idx = -1;
  5091. zval *meta, **def, **type, **not_null, **has_default, **is_enum, **val, *new_val;
  5092. int key_type, err = 0, skip_field;
  5093. php_pgsql_data_type data_type;
  5094. assert(pg_link != NULL);
  5095. assert(Z_TYPE_P(values) == IS_ARRAY);
  5096. assert(Z_TYPE_P(result) == IS_ARRAY);
  5097. assert(!(opt & ~PGSQL_CONV_OPTS));
  5098. if (!table_name) {
  5099. return FAILURE;
  5100. }
  5101. MAKE_STD_ZVAL(meta);
  5102. array_init(meta);
  5103. /* table_name is escaped by php_pgsql_meta_data */
  5104. if (php_pgsql_meta_data(pg_link, table_name, meta, 0 TSRMLS_CC) == FAILURE) {
  5105. zval_dtor(meta);
  5106. FREE_ZVAL(meta);
  5107. return FAILURE;
  5108. }
  5109. for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(values), &pos);
  5110. zend_hash_get_current_data_ex(Z_ARRVAL_P(values), (void **)&val, &pos) == SUCCESS;
  5111. zend_hash_move_forward_ex(Z_ARRVAL_P(values), &pos)) {
  5112. skip_field = 0;
  5113. new_val = NULL;
  5114. if ((key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(values), &field, &field_len, &num_idx, 0, &pos)) == HASH_KEY_NON_EXISTENT) {
  5115. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to get array key type");
  5116. err = 1;
  5117. }
  5118. if (!err && key_type == HASH_KEY_IS_LONG) {
  5119. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Accepts only string key for values");
  5120. err = 1;
  5121. }
  5122. if (!err && key_type == HASH_KEY_NON_EXISTENT) {
  5123. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Accepts only string key for values");
  5124. err = 1;
  5125. }
  5126. if (!err && zend_hash_find(Z_ARRVAL_P(meta), field, field_len, (void **)&def) == FAILURE) {
  5127. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Invalid field name (%s) in values", field);
  5128. err = 1;
  5129. }
  5130. if (!err && zend_hash_find(Z_ARRVAL_PP(def), "type", sizeof("type"), (void **)&type) == FAILURE) {
  5131. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected broken meta data. Missing 'type'");
  5132. err = 1;
  5133. }
  5134. if (!err && zend_hash_find(Z_ARRVAL_PP(def), "not null", sizeof("not null"), (void **)&not_null) == FAILURE) {
  5135. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected broken meta data. Missing 'not null'");
  5136. err = 1;
  5137. }
  5138. if (!err && zend_hash_find(Z_ARRVAL_PP(def), "has default", sizeof("has default"), (void **)&has_default) == FAILURE) {
  5139. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected broken meta data. Missing 'has default'");
  5140. err = 1;
  5141. }
  5142. if (!err && zend_hash_find(Z_ARRVAL_PP(def), "is enum", sizeof("is enum"), (void **)&is_enum) == FAILURE) {
  5143. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected broken meta data. Missing 'is enum'");
  5144. err = 1;
  5145. }
  5146. if (!err && (Z_TYPE_PP(val) == IS_ARRAY || Z_TYPE_PP(val) == IS_OBJECT)) {
  5147. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects scalar values as field values");
  5148. err = 1;
  5149. }
  5150. if (err) {
  5151. break; /* break out for() */
  5152. }
  5153. ALLOC_INIT_ZVAL(new_val);
  5154. if (Z_BVAL_PP(is_enum)) {
  5155. /* enums need to be treated like strings */
  5156. data_type = PG_TEXT;
  5157. }
  5158. else {
  5159. data_type = php_pgsql_get_data_type(Z_STRVAL_PP(type), Z_STRLEN_PP(type));
  5160. }
  5161. switch(data_type)
  5162. {
  5163. case PG_BOOL:
  5164. switch (Z_TYPE_PP(val)) {
  5165. case IS_STRING:
  5166. if (Z_STRLEN_PP(val) == 0) {
  5167. ZVAL_STRING(new_val, "NULL", 1);
  5168. }
  5169. else {
  5170. if (!strcmp(Z_STRVAL_PP(val), "t") || !strcmp(Z_STRVAL_PP(val), "T") ||
  5171. !strcmp(Z_STRVAL_PP(val), "y") || !strcmp(Z_STRVAL_PP(val), "Y") ||
  5172. !strcmp(Z_STRVAL_PP(val), "true") || !strcmp(Z_STRVAL_PP(val), "True") ||
  5173. !strcmp(Z_STRVAL_PP(val), "yes") || !strcmp(Z_STRVAL_PP(val), "Yes") ||
  5174. !strcmp(Z_STRVAL_PP(val), "1")) {
  5175. ZVAL_STRINGL(new_val, "'t'", sizeof("'t'")-1, 1);
  5176. }
  5177. else if (!strcmp(Z_STRVAL_PP(val), "f") || !strcmp(Z_STRVAL_PP(val), "F") ||
  5178. !strcmp(Z_STRVAL_PP(val), "n") || !strcmp(Z_STRVAL_PP(val), "N") ||
  5179. !strcmp(Z_STRVAL_PP(val), "false") || !strcmp(Z_STRVAL_PP(val), "False") ||
  5180. !strcmp(Z_STRVAL_PP(val), "no") || !strcmp(Z_STRVAL_PP(val), "No") ||
  5181. !strcmp(Z_STRVAL_PP(val), "0")) {
  5182. ZVAL_STRINGL(new_val, "'f'", sizeof("'f'")-1, 1);
  5183. }
  5184. else {
  5185. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected invalid value (%s) for PostgreSQL %s field (%s)", Z_STRVAL_PP(val), Z_STRVAL_PP(type), field);
  5186. err = 1;
  5187. }
  5188. }
  5189. break;
  5190. case IS_LONG:
  5191. case IS_BOOL:
  5192. if (Z_LVAL_PP(val)) {
  5193. ZVAL_STRINGL(new_val, "'t'", sizeof("'t'")-1, 1);
  5194. }
  5195. else {
  5196. ZVAL_STRINGL(new_val, "'f'", sizeof("'f'")-1, 1);
  5197. }
  5198. break;
  5199. case IS_NULL:
  5200. ZVAL_STRINGL(new_val, "NULL", sizeof("NULL")-1, 1);
  5201. break;
  5202. default:
  5203. err = 1;
  5204. }
  5205. PGSQL_CONV_CHECK_IGNORE();
  5206. if (err) {
  5207. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects string, null, long or boolelan value for PostgreSQL '%s' (%s)", Z_STRVAL_PP(type), field);
  5208. }
  5209. break;
  5210. case PG_OID:
  5211. case PG_INT2:
  5212. case PG_INT4:
  5213. case PG_INT8:
  5214. switch (Z_TYPE_PP(val)) {
  5215. case IS_STRING:
  5216. if (Z_STRLEN_PP(val) == 0) {
  5217. ZVAL_STRINGL(new_val, "NULL", sizeof("NULL")-1, 1);
  5218. }
  5219. else {
  5220. /* FIXME: better regex must be used */
  5221. if (php_pgsql_convert_match(Z_STRVAL_PP(val), Z_STRLEN_PP(val), "^([+-]{0,1}[0-9]+)$", 0 TSRMLS_CC) == FAILURE) {
  5222. err = 1;
  5223. }
  5224. else {
  5225. ZVAL_STRINGL(new_val, Z_STRVAL_PP(val), Z_STRLEN_PP(val), 1);
  5226. }
  5227. }
  5228. break;
  5229. case IS_DOUBLE:
  5230. ZVAL_DOUBLE(new_val, Z_DVAL_PP(val));
  5231. convert_to_long_ex(&new_val);
  5232. break;
  5233. case IS_LONG:
  5234. ZVAL_LONG(new_val, Z_LVAL_PP(val));
  5235. break;
  5236. case IS_NULL:
  5237. ZVAL_STRINGL(new_val, "NULL", sizeof("NULL")-1, 1);
  5238. break;
  5239. default:
  5240. err = 1;
  5241. }
  5242. PGSQL_CONV_CHECK_IGNORE();
  5243. if (err) {
  5244. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL, string, long or double value for pgsql '%s' (%s)", Z_STRVAL_PP(type), field);
  5245. }
  5246. break;
  5247. case PG_NUMERIC:
  5248. case PG_MONEY:
  5249. case PG_FLOAT4:
  5250. case PG_FLOAT8:
  5251. switch (Z_TYPE_PP(val)) {
  5252. case IS_STRING:
  5253. if (Z_STRLEN_PP(val) == 0) {
  5254. ZVAL_STRINGL(new_val, "NULL", sizeof("NULL")-1, 1);
  5255. }
  5256. else {
  5257. /* better regex? */
  5258. if (php_pgsql_convert_match(Z_STRVAL_PP(val), Z_STRLEN_PP(val), "^[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?$", 0 TSRMLS_CC) == FAILURE) {
  5259. if (php_pgsql_convert_match(Z_STRVAL_PP(val), Z_STRLEN_PP(val), "^[+-]{0,1}(inf)(inity){0,1}$", 1 TSRMLS_CC) == FAILURE) {
  5260. err = 1;
  5261. } else {
  5262. ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
  5263. php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
  5264. }
  5265. }
  5266. else {
  5267. ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
  5268. }
  5269. }
  5270. break;
  5271. case IS_LONG:
  5272. ZVAL_LONG(new_val, Z_LVAL_PP(val));
  5273. break;
  5274. case IS_DOUBLE:
  5275. ZVAL_DOUBLE(new_val, Z_DVAL_PP(val));
  5276. break;
  5277. case IS_NULL:
  5278. ZVAL_STRINGL(new_val, "NULL", sizeof("NULL")-1, 1);
  5279. break;
  5280. default:
  5281. err = 1;
  5282. }
  5283. PGSQL_CONV_CHECK_IGNORE();
  5284. if (err) {
  5285. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL, string, long or double value for PostgreSQL '%s' (%s)", Z_STRVAL_PP(type), field);
  5286. }
  5287. break;
  5288. /* Exotic types are handled as string also.
  5289. Please feel free to add more valitions. Invalid query fails
  5290. at execution anyway. */
  5291. case PG_TEXT:
  5292. case PG_CHAR:
  5293. case PG_VARCHAR:
  5294. /* bit */
  5295. case PG_BIT:
  5296. case PG_VARBIT:
  5297. /* geometric */
  5298. case PG_LINE:
  5299. case PG_LSEG:
  5300. case PG_POINT:
  5301. case PG_BOX:
  5302. case PG_PATH:
  5303. case PG_POLYGON:
  5304. case PG_CIRCLE:
  5305. /* unknown. JSON, Array etc */
  5306. case PG_UNKNOWN:
  5307. switch (Z_TYPE_PP(val)) {
  5308. case IS_STRING:
  5309. if (Z_STRLEN_PP(val) == 0) {
  5310. if (opt & PGSQL_CONV_FORCE_NULL) {
  5311. ZVAL_STRINGL(new_val, "NULL", sizeof("NULL")-1, 1);
  5312. } else {
  5313. ZVAL_STRINGL(new_val, "''", sizeof("''")-1, 1);
  5314. }
  5315. }
  5316. else {
  5317. char *tmp;
  5318. /* PostgreSQL ignores \0 */
  5319. Z_TYPE_P(new_val) = IS_STRING;
  5320. tmp = (char *)safe_emalloc(Z_STRLEN_PP(val), 2, 1);
  5321. /* better to use PGSQLescapeLiteral since PGescapeStringConn does not handle special \ */
  5322. Z_STRLEN_P(new_val) = (int)PQescapeStringConn(pg_link, tmp, Z_STRVAL_PP(val), Z_STRLEN_PP(val), NULL);
  5323. Z_STRVAL_P(new_val) = tmp;
  5324. php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
  5325. }
  5326. break;
  5327. case IS_LONG:
  5328. ZVAL_LONG(new_val, Z_LVAL_PP(val));
  5329. convert_to_string_ex(&new_val);
  5330. break;
  5331. case IS_DOUBLE:
  5332. ZVAL_DOUBLE(new_val, Z_DVAL_PP(val));
  5333. convert_to_string_ex(&new_val);
  5334. break;
  5335. case IS_NULL:
  5336. ZVAL_STRINGL(new_val, "NULL", sizeof("NULL")-1, 1);
  5337. break;
  5338. default:
  5339. err = 1;
  5340. }
  5341. PGSQL_CONV_CHECK_IGNORE();
  5342. if (err) {
  5343. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL, string, long or double value for PostgreSQL '%s' (%s)", Z_STRVAL_PP(type), field);
  5344. }
  5345. break;
  5346. case PG_UNIX_TIME:
  5347. case PG_UNIX_TIME_INTERVAL:
  5348. /* these are the actallay a integer */
  5349. switch (Z_TYPE_PP(val)) {
  5350. case IS_STRING:
  5351. if (Z_STRLEN_PP(val) == 0) {
  5352. ZVAL_STRINGL(new_val, "NULL", sizeof("NULL")-1, 1);
  5353. }
  5354. else {
  5355. /* better regex? */
  5356. if (php_pgsql_convert_match(Z_STRVAL_PP(val), Z_STRLEN_PP(val), "^[0-9]+$", 0 TSRMLS_CC) == FAILURE) {
  5357. err = 1;
  5358. }
  5359. else {
  5360. ZVAL_STRINGL(new_val, Z_STRVAL_PP(val), Z_STRLEN_PP(val), 1);
  5361. convert_to_long_ex(&new_val);
  5362. }
  5363. }
  5364. break;
  5365. case IS_DOUBLE:
  5366. ZVAL_DOUBLE(new_val, Z_DVAL_PP(val));
  5367. convert_to_long_ex(&new_val);
  5368. break;
  5369. case IS_LONG:
  5370. ZVAL_LONG(new_val, Z_LVAL_PP(val));
  5371. break;
  5372. case IS_NULL:
  5373. ZVAL_STRINGL(new_val, "NULL", sizeof("NULL")-1, 1);
  5374. break;
  5375. default:
  5376. err = 1;
  5377. }
  5378. PGSQL_CONV_CHECK_IGNORE();
  5379. if (err) {
  5380. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL, string, long or double value for '%s' (%s)", Z_STRVAL_PP(type), field);
  5381. }
  5382. break;
  5383. case PG_CIDR:
  5384. case PG_INET:
  5385. switch (Z_TYPE_PP(val)) {
  5386. case IS_STRING:
  5387. if (Z_STRLEN_PP(val) == 0) {
  5388. ZVAL_STRINGL(new_val, "NULL", sizeof("NULL")-1, 1);
  5389. }
  5390. else {
  5391. /* better regex? IPV6 and IPV4 */
  5392. if (php_pgsql_convert_match(Z_STRVAL_PP(val), Z_STRLEN_PP(val), "^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]).){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]).){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$", 0 TSRMLS_CC) == FAILURE) {
  5393. err = 1;
  5394. }
  5395. else {
  5396. ZVAL_STRINGL(new_val, Z_STRVAL_PP(val), Z_STRLEN_PP(val), 1);
  5397. php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
  5398. }
  5399. }
  5400. break;
  5401. case IS_NULL:
  5402. ZVAL_STRINGL(new_val, "NULL", sizeof("NULL")-1, 1);
  5403. break;
  5404. default:
  5405. err = 1;
  5406. }
  5407. PGSQL_CONV_CHECK_IGNORE();
  5408. if (err) {
  5409. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL or string for '%s' (%s)", Z_STRVAL_PP(type), field);
  5410. }
  5411. break;
  5412. case PG_TIME_WITH_TIMEZONE:
  5413. case PG_TIMESTAMP:
  5414. case PG_TIMESTAMP_WITH_TIMEZONE:
  5415. switch(Z_TYPE_PP(val)) {
  5416. case IS_STRING:
  5417. if (Z_STRLEN_PP(val) == 0) {
  5418. ZVAL_STRINGL(new_val, "NULL", sizeof("NULL")-1, 1);
  5419. } else if (!strcasecmp(Z_STRVAL_PP(val), "now()")) {
  5420. ZVAL_STRINGL(new_val, "NOW()", sizeof("NOW()")-1, 1);
  5421. } else {
  5422. /* better regex? */
  5423. if (php_pgsql_convert_match(Z_STRVAL_PP(val), Z_STRLEN_PP(val), "^([0-9]{4}[/-][0-9]{1,2}[/-][0-9]{1,2})([ \\t]+(([0-9]{1,2}:[0-9]{1,2}){1}(:[0-9]{1,2}){0,1}(\\.[0-9]+){0,1}([ \\t]*([+-][0-9]{1,4}(:[0-9]{1,2}){0,1}|[-a-zA-Z_/+]{1,50})){0,1})){0,1}$", 1 TSRMLS_CC) == FAILURE) {
  5424. err = 1;
  5425. } else {
  5426. ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
  5427. php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
  5428. }
  5429. }
  5430. break;
  5431. case IS_NULL:
  5432. ZVAL_STRINGL(new_val, "NULL", sizeof("NULL")-1, 1);
  5433. break;
  5434. default:
  5435. err = 1;
  5436. }
  5437. PGSQL_CONV_CHECK_IGNORE();
  5438. if (err) {
  5439. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL or string for PostgreSQL %s field (%s)", Z_STRVAL_PP(type), field);
  5440. }
  5441. break;
  5442. case PG_DATE:
  5443. switch(Z_TYPE_PP(val)) {
  5444. case IS_STRING:
  5445. if (Z_STRLEN_PP(val) == 0) {
  5446. ZVAL_STRINGL(new_val, "NULL", sizeof("NULL")-1, 1);
  5447. }
  5448. else {
  5449. /* FIXME: better regex must be used */
  5450. if (php_pgsql_convert_match(Z_STRVAL_PP(val), Z_STRLEN_PP(val), "^([0-9]{4}[/-][0-9]{1,2}[/-][0-9]{1,2})$", 1 TSRMLS_CC) == FAILURE) {
  5451. err = 1;
  5452. }
  5453. else {
  5454. ZVAL_STRINGL(new_val, Z_STRVAL_PP(val), Z_STRLEN_PP(val), 1);
  5455. php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
  5456. }
  5457. }
  5458. break;
  5459. case IS_NULL:
  5460. ZVAL_STRINGL(new_val, "NULL", sizeof("NULL")-1, 1);
  5461. break;
  5462. default:
  5463. err = 1;
  5464. }
  5465. PGSQL_CONV_CHECK_IGNORE();
  5466. if (err) {
  5467. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL or string for PostgreSQL %s field (%s)", Z_STRVAL_PP(type), field);
  5468. }
  5469. break;
  5470. case PG_TIME:
  5471. switch(Z_TYPE_PP(val)) {
  5472. case IS_STRING:
  5473. if (Z_STRLEN_PP(val) == 0) {
  5474. ZVAL_STRINGL(new_val, "NULL", sizeof("NULL")-1, 1);
  5475. }
  5476. else {
  5477. /* FIXME: better regex must be used */
  5478. if (php_pgsql_convert_match(Z_STRVAL_PP(val), Z_STRLEN_PP(val), "^(([0-9]{1,2}:[0-9]{1,2}){1}(:[0-9]{1,2}){0,1})){0,1}$", 1 TSRMLS_CC) == FAILURE) {
  5479. err = 1;
  5480. }
  5481. else {
  5482. ZVAL_STRINGL(new_val, Z_STRVAL_PP(val), Z_STRLEN_PP(val), 1);
  5483. php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
  5484. }
  5485. }
  5486. break;
  5487. case IS_NULL:
  5488. ZVAL_STRINGL(new_val, "NULL", sizeof("NULL")-1, 1);
  5489. break;
  5490. default:
  5491. err = 1;
  5492. }
  5493. PGSQL_CONV_CHECK_IGNORE();
  5494. if (err) {
  5495. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL or string for PostgreSQL %s field (%s)", Z_STRVAL_PP(type), field);
  5496. }
  5497. break;
  5498. case PG_INTERVAL:
  5499. switch(Z_TYPE_PP(val)) {
  5500. case IS_STRING:
  5501. if (Z_STRLEN_PP(val) == 0) {
  5502. ZVAL_STRING(new_val, "NULL", 1);
  5503. }
  5504. else {
  5505. /* From the Postgres docs:
  5506. interval values can be written with the following syntax:
  5507. [@] quantity unit [quantity unit...] [direction]
  5508. Where: quantity is a number (possibly signed); unit is second, minute, hour,
  5509. day, week, month, year, decade, century, millennium, or abbreviations or
  5510. plurals of these units [note not *all* abbreviations] ; direction can be
  5511. ago or empty. The at sign (@) is optional noise.
  5512. ...
  5513. Quantities of days, hours, minutes, and seconds can be specified without explicit
  5514. unit markings. For example, '1 12:59:10' is read the same as '1 day 12 hours 59 min 10
  5515. sec'.
  5516. */
  5517. if (php_pgsql_convert_match(Z_STRVAL_PP(val), Z_STRLEN_PP(val),
  5518. "^(@?[ \\t]+)?("
  5519. /* Textual time units and their abbreviations: */
  5520. "(([-+]?[ \\t]+)?"
  5521. "[0-9]+(\\.[0-9]*)?[ \\t]*"
  5522. "(millenniums|millennia|millennium|mil|mils|"
  5523. "centuries|century|cent|c|"
  5524. "decades|decade|dec|decs|"
  5525. "years|year|y|"
  5526. "months|month|mon|"
  5527. "weeks|week|w|"
  5528. "days|day|d|"
  5529. "hours|hour|hr|hrs|h|"
  5530. "minutes|minute|mins|min|m|"
  5531. "seconds|second|secs|sec|s))+|"
  5532. /* Textual time units plus (dd)* hh[:mm[:ss]] */
  5533. "((([-+]?[ \\t]+)?"
  5534. "[0-9]+(\\.[0-9]*)?[ \\t]*"
  5535. "(millenniums|millennia|millennium|mil|mils|"
  5536. "centuries|century|cent|c|"
  5537. "decades|decade|dec|decs|"
  5538. "years|year|y|"
  5539. "months|month|mon|"
  5540. "weeks|week|w|"
  5541. "days|day|d))+"
  5542. "([-+]?[ \\t]+"
  5543. "([0-9]+[ \\t]+)+" /* dd */
  5544. "(([0-9]{1,2}:){0,2}[0-9]{0,2})" /* hh:[mm:[ss]] */
  5545. ")?))"
  5546. "([ \\t]+ago)?$",
  5547. 1 TSRMLS_CC) == FAILURE) {
  5548. err = 1;
  5549. }
  5550. else {
  5551. ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
  5552. php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
  5553. }
  5554. }
  5555. break;
  5556. case IS_NULL:
  5557. ZVAL_STRING(new_val, "NULL", 1);
  5558. break;
  5559. default:
  5560. err = 1;
  5561. }
  5562. PGSQL_CONV_CHECK_IGNORE();
  5563. if (err) {
  5564. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL or string for PostgreSQL %s field (%s)", Z_STRVAL_PP(type), field);
  5565. }
  5566. break;
  5567. #ifdef HAVE_PQESCAPE
  5568. case PG_BYTEA:
  5569. switch (Z_TYPE_PP(val)) {
  5570. case IS_STRING:
  5571. if (Z_STRLEN_PP(val) == 0) {
  5572. ZVAL_STRING(new_val, "NULL", 1);
  5573. }
  5574. else {
  5575. unsigned char *tmp;
  5576. size_t to_len;
  5577. smart_str s = {0};
  5578. #ifdef HAVE_PQESCAPE_BYTEA_CONN
  5579. tmp = PQescapeByteaConn(pg_link, (unsigned char *)Z_STRVAL_PP(val), Z_STRLEN_PP(val), &to_len);
  5580. #else
  5581. tmp = PQescapeBytea(Z_STRVAL_PP(val), (unsigned char *)Z_STRLEN_PP(val), &to_len);
  5582. #endif
  5583. Z_TYPE_P(new_val) = IS_STRING;
  5584. Z_STRLEN_P(new_val) = to_len-1; /* PQescapeBytea's to_len includes additional '\0' */
  5585. Z_STRVAL_P(new_val) = emalloc(to_len);
  5586. memcpy(Z_STRVAL_P(new_val), tmp, to_len);
  5587. PQfreemem(tmp);
  5588. php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
  5589. smart_str_appendl(&s, Z_STRVAL_P(new_val), Z_STRLEN_P(new_val));
  5590. smart_str_0(&s);
  5591. efree(Z_STRVAL_P(new_val));
  5592. Z_STRVAL_P(new_val) = s.c;
  5593. Z_STRLEN_P(new_val) = s.len;
  5594. }
  5595. break;
  5596. case IS_LONG:
  5597. ZVAL_LONG(new_val, Z_LVAL_PP(val));
  5598. convert_to_string_ex(&new_val);
  5599. break;
  5600. case IS_DOUBLE:
  5601. ZVAL_DOUBLE(new_val, Z_DVAL_PP(val));
  5602. convert_to_string_ex(&new_val);
  5603. break;
  5604. case IS_NULL:
  5605. ZVAL_STRINGL(new_val, "NULL", sizeof("NULL")-1, 1);
  5606. break;
  5607. default:
  5608. err = 1;
  5609. }
  5610. PGSQL_CONV_CHECK_IGNORE();
  5611. if (err) {
  5612. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL, string, long or double value for PostgreSQL '%s' (%s)", Z_STRVAL_PP(type), field);
  5613. }
  5614. break;
  5615. #endif
  5616. case PG_MACADDR:
  5617. switch(Z_TYPE_PP(val)) {
  5618. case IS_STRING:
  5619. if (Z_STRLEN_PP(val) == 0) {
  5620. ZVAL_STRINGL(new_val, "NULL", sizeof("NULL")-1, 1);
  5621. }
  5622. else {
  5623. if (php_pgsql_convert_match(Z_STRVAL_PP(val), Z_STRLEN_PP(val), "^([0-9a-f]{2,2}:){5,5}[0-9a-f]{2,2}$", 1 TSRMLS_CC) == FAILURE) {
  5624. err = 1;
  5625. }
  5626. else {
  5627. ZVAL_STRINGL(new_val, Z_STRVAL_PP(val), Z_STRLEN_PP(val), 1);
  5628. php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
  5629. }
  5630. }
  5631. break;
  5632. case IS_NULL:
  5633. ZVAL_STRINGL(new_val, "NULL", sizeof("NULL")-1, 1);
  5634. break;
  5635. default:
  5636. err = 1;
  5637. }
  5638. PGSQL_CONV_CHECK_IGNORE();
  5639. if (err) {
  5640. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL or string for PostgreSQL %s field (%s)", Z_STRVAL_PP(type), field);
  5641. }
  5642. break;
  5643. default:
  5644. /* should not happen */
  5645. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Unknown or system data type '%s' for '%s'. Report error", Z_STRVAL_PP(type), field);
  5646. err = 1;
  5647. break;
  5648. } /* switch */
  5649. if (err) {
  5650. zval_dtor(new_val);
  5651. FREE_ZVAL(new_val);
  5652. break; /* break out for() */
  5653. }
  5654. /* If field is NULL and HAS DEFAULT, should be skipped */
  5655. if (!skip_field) {
  5656. char *escaped;
  5657. size_t field_len = strlen(field);
  5658. if (_php_pgsql_detect_identifier_escape(field, field_len) == SUCCESS) {
  5659. add_assoc_zval(result, field, new_val);
  5660. } else {
  5661. escaped = PGSQLescapeIdentifier(pg_link, field, field_len);
  5662. add_assoc_zval(result, escaped, new_val);
  5663. PGSQLfree(escaped);
  5664. }
  5665. }
  5666. } /* for */
  5667. zval_dtor(meta);
  5668. FREE_ZVAL(meta);
  5669. if (err) {
  5670. /* shouldn't destroy & free zval here */
  5671. return FAILURE;
  5672. }
  5673. return SUCCESS;
  5674. }
  5675. /* }}} */
  5676. /* {{{ proto array pg_convert(resource db, string table, array values[, int options])
  5677. Check and convert values for PostgreSQL SQL statement */
  5678. PHP_FUNCTION(pg_convert)
  5679. {
  5680. zval *pgsql_link, *values;
  5681. char *table_name;
  5682. int table_name_len;
  5683. ulong option = 0;
  5684. PGconn *pg_link;
  5685. int id = -1;
  5686. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
  5687. "rsa|l", &pgsql_link, &table_name, &table_name_len, &values, &option) == FAILURE) {
  5688. return;
  5689. }
  5690. if (option & ~PGSQL_CONV_OPTS) {
  5691. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid option is specified");
  5692. RETURN_FALSE;
  5693. }
  5694. if (!table_name_len) {
  5695. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Table name is invalid");
  5696. RETURN_FALSE;
  5697. }
  5698. ZEND_FETCH_RESOURCE2(pg_link, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  5699. if (php_pgsql_flush_query(pg_link TSRMLS_CC)) {
  5700. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected unhandled result(s) in connection");
  5701. }
  5702. array_init(return_value);
  5703. if (php_pgsql_convert(pg_link, table_name, values, return_value, option TSRMLS_CC) == FAILURE) {
  5704. zval_dtor(return_value);
  5705. RETURN_FALSE;
  5706. }
  5707. }
  5708. /* }}} */
  5709. static int do_exec(smart_str *querystr, int expect, PGconn *pg_link, ulong opt TSRMLS_DC)
  5710. {
  5711. if (opt & PGSQL_DML_ASYNC) {
  5712. if (PQsendQuery(pg_link, querystr->c)) {
  5713. return 0;
  5714. }
  5715. }
  5716. else {
  5717. PGresult *pg_result;
  5718. pg_result = PQexec(pg_link, querystr->c);
  5719. if (PQresultStatus(pg_result) == expect) {
  5720. PQclear(pg_result);
  5721. return 0;
  5722. } else {
  5723. php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", PQresultErrorMessage(pg_result));
  5724. PQclear(pg_result);
  5725. }
  5726. }
  5727. return -1;
  5728. }
  5729. static inline void build_tablename(smart_str *querystr, PGconn *pg_link, const char *table)
  5730. {
  5731. char *table_copy, *escaped, *tmp;
  5732. const char *token;
  5733. size_t len;
  5734. /* schame.table should be "schame"."table" */
  5735. table_copy = estrdup(table);
  5736. token = php_strtok_r(table_copy, ".", &tmp);
  5737. if (token == NULL) {
  5738. token = table;
  5739. }
  5740. len = strlen(token);
  5741. if (_php_pgsql_detect_identifier_escape(token, len) == SUCCESS) {
  5742. smart_str_appendl(querystr, token, len);
  5743. } else {
  5744. escaped = PGSQLescapeIdentifier(pg_link, token, len);
  5745. smart_str_appends(querystr, escaped);
  5746. PGSQLfree(escaped);
  5747. }
  5748. if (tmp && *tmp) {
  5749. len = strlen(tmp);
  5750. /* "schema"."table" format */
  5751. if (_php_pgsql_detect_identifier_escape(tmp, len) == SUCCESS) {
  5752. smart_str_appendc(querystr, '.');
  5753. smart_str_appendl(querystr, tmp, len);
  5754. } else {
  5755. escaped = PGSQLescapeIdentifier(pg_link, tmp, len);
  5756. smart_str_appendc(querystr, '.');
  5757. smart_str_appends(querystr, escaped);
  5758. PGSQLfree(escaped);
  5759. }
  5760. }
  5761. efree(table_copy);
  5762. }
  5763. /* {{{ php_pgsql_insert
  5764. */
  5765. PHP_PGSQL_API int php_pgsql_insert(PGconn *pg_link, const char *table, zval *var_array, ulong opt, char **sql TSRMLS_DC)
  5766. {
  5767. zval **val, *converted = NULL;
  5768. char buf[256];
  5769. char *fld, *tmp;
  5770. smart_str querystr = {0};
  5771. int key_type, ret = FAILURE;
  5772. uint fld_len;
  5773. ulong num_idx;
  5774. HashPosition pos;
  5775. assert(pg_link != NULL);
  5776. assert(table != NULL);
  5777. assert(Z_TYPE_P(var_array) == IS_ARRAY);
  5778. if (zend_hash_num_elements(Z_ARRVAL_P(var_array)) == 0) {
  5779. smart_str_appends(&querystr, "INSERT INTO ");
  5780. build_tablename(&querystr, pg_link, table);
  5781. smart_str_appends(&querystr, " DEFAULT VALUES");
  5782. goto no_values;
  5783. }
  5784. /* convert input array if needed */
  5785. if (!(opt & (PGSQL_DML_NO_CONV|PGSQL_DML_ESCAPE))) {
  5786. MAKE_STD_ZVAL(converted);
  5787. array_init(converted);
  5788. if (php_pgsql_convert(pg_link, table, var_array, converted, (opt & PGSQL_CONV_OPTS) TSRMLS_CC) == FAILURE) {
  5789. goto cleanup;
  5790. }
  5791. var_array = converted;
  5792. }
  5793. smart_str_appends(&querystr, "INSERT INTO ");
  5794. build_tablename(&querystr, pg_link, table);
  5795. smart_str_appends(&querystr, " (");
  5796. zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(var_array), &pos);
  5797. while ((key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(var_array), &fld,
  5798. &fld_len, &num_idx, 0, &pos)) != HASH_KEY_NON_EXISTENT) {
  5799. if (key_type == HASH_KEY_IS_LONG) {
  5800. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects associative array for values to be inserted");
  5801. goto cleanup;
  5802. }
  5803. if (opt & PGSQL_DML_ESCAPE) {
  5804. tmp = PGSQLescapeIdentifier(pg_link, fld, fld_len);
  5805. smart_str_appends(&querystr, tmp);
  5806. PGSQLfree(tmp);
  5807. } else {
  5808. smart_str_appendl(&querystr, fld, fld_len - 1);
  5809. }
  5810. smart_str_appendc(&querystr, ',');
  5811. zend_hash_move_forward_ex(Z_ARRVAL_P(var_array), &pos);
  5812. }
  5813. querystr.len--;
  5814. smart_str_appends(&querystr, ") VALUES (");
  5815. /* make values string */
  5816. for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(var_array), &pos);
  5817. zend_hash_get_current_data_ex(Z_ARRVAL_P(var_array), (void **)&val, &pos) == SUCCESS;
  5818. zend_hash_move_forward_ex(Z_ARRVAL_P(var_array), &pos)) {
  5819. /* we can avoid the key_type check here, because we tested it in the other loop */
  5820. switch(Z_TYPE_PP(val)) {
  5821. case IS_STRING:
  5822. if (opt & PGSQL_DML_ESCAPE) {
  5823. size_t new_len;
  5824. char *tmp;
  5825. tmp = (char *)safe_emalloc(Z_STRLEN_PP(val), 2, 1);
  5826. new_len = PQescapeStringConn(pg_link, tmp, Z_STRVAL_PP(val), Z_STRLEN_PP(val), NULL);
  5827. smart_str_appendc(&querystr, '\'');
  5828. smart_str_appendl(&querystr, tmp, new_len);
  5829. smart_str_appendc(&querystr, '\'');
  5830. efree(tmp);
  5831. } else {
  5832. smart_str_appendl(&querystr, Z_STRVAL_PP(val), Z_STRLEN_PP(val));
  5833. }
  5834. break;
  5835. case IS_LONG:
  5836. smart_str_append_long(&querystr, Z_LVAL_PP(val));
  5837. break;
  5838. case IS_DOUBLE:
  5839. smart_str_appendl(&querystr, buf, snprintf(buf, sizeof(buf), "%F", Z_DVAL_PP(val)));
  5840. break;
  5841. case IS_NULL:
  5842. smart_str_appendl(&querystr, "NULL", sizeof("NULL")-1);
  5843. break;
  5844. default:
  5845. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Expects scaler values. type = %d", Z_TYPE_PP(val));
  5846. goto cleanup;
  5847. break;
  5848. }
  5849. smart_str_appendc(&querystr, ',');
  5850. }
  5851. /* Remove the trailing "," */
  5852. querystr.len--;
  5853. smart_str_appends(&querystr, ");");
  5854. no_values:
  5855. smart_str_0(&querystr);
  5856. if ((opt & (PGSQL_DML_EXEC|PGSQL_DML_ASYNC)) &&
  5857. do_exec(&querystr, PGRES_COMMAND_OK, pg_link, (opt & PGSQL_CONV_OPTS) TSRMLS_CC) == 0) {
  5858. ret = SUCCESS;
  5859. }
  5860. else if (opt & PGSQL_DML_STRING) {
  5861. ret = SUCCESS;
  5862. }
  5863. cleanup:
  5864. if (!(opt & PGSQL_DML_NO_CONV) && converted) {
  5865. zval_dtor(converted);
  5866. FREE_ZVAL(converted);
  5867. }
  5868. if (ret == SUCCESS && (opt & PGSQL_DML_STRING)) {
  5869. *sql = querystr.c;
  5870. }
  5871. else {
  5872. smart_str_free(&querystr);
  5873. }
  5874. return ret;
  5875. }
  5876. /* }}} */
  5877. /* {{{ proto mixed pg_insert(resource db, string table, array values[, int options])
  5878. Insert values (filed=>value) to table */
  5879. PHP_FUNCTION(pg_insert)
  5880. {
  5881. zval *pgsql_link, *values;
  5882. char *table, *sql = NULL;
  5883. int table_len;
  5884. ulong option = PGSQL_DML_EXEC, return_sql;
  5885. PGconn *pg_link;
  5886. PGresult *pg_result;
  5887. ExecStatusType status;
  5888. pgsql_result_handle *pgsql_handle;
  5889. int id = -1, argc = ZEND_NUM_ARGS();
  5890. if (zend_parse_parameters(argc TSRMLS_CC, "rsa|l",
  5891. &pgsql_link, &table, &table_len, &values, &option) == FAILURE) {
  5892. return;
  5893. }
  5894. if (option & ~(PGSQL_CONV_OPTS|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_ASYNC|PGSQL_DML_STRING|PGSQL_DML_ESCAPE)) {
  5895. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid option is specified");
  5896. RETURN_FALSE;
  5897. }
  5898. ZEND_FETCH_RESOURCE2(pg_link, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  5899. if (php_pgsql_flush_query(pg_link TSRMLS_CC)) {
  5900. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected unhandled result(s) in connection");
  5901. }
  5902. return_sql = option & PGSQL_DML_STRING;
  5903. if (option & PGSQL_DML_EXEC) {
  5904. /* return resource when executed */
  5905. option = option & ~PGSQL_DML_EXEC;
  5906. if (php_pgsql_insert(pg_link, table, values, option|PGSQL_DML_STRING, &sql TSRMLS_CC) == FAILURE) {
  5907. RETURN_FALSE;
  5908. }
  5909. pg_result = PQexec(pg_link, sql);
  5910. if ((PGG(auto_reset_persistent) & 2) && PQstatus(pg_link) != CONNECTION_OK) {
  5911. PQclear(pg_result);
  5912. PQreset(pg_link);
  5913. pg_result = PQexec(pg_link, sql);
  5914. }
  5915. efree(sql);
  5916. if (pg_result) {
  5917. status = PQresultStatus(pg_result);
  5918. } else {
  5919. status = (ExecStatusType) PQstatus(pg_link);
  5920. }
  5921. switch (status) {
  5922. case PGRES_EMPTY_QUERY:
  5923. case PGRES_BAD_RESPONSE:
  5924. case PGRES_NONFATAL_ERROR:
  5925. case PGRES_FATAL_ERROR:
  5926. PHP_PQ_ERROR("Query failed: %s", pg_link);
  5927. PQclear(pg_result);
  5928. RETURN_FALSE;
  5929. break;
  5930. case PGRES_COMMAND_OK: /* successful command that did not return rows */
  5931. default:
  5932. if (pg_result) {
  5933. pgsql_handle = (pgsql_result_handle *) emalloc(sizeof(pgsql_result_handle));
  5934. pgsql_handle->conn = pg_link;
  5935. pgsql_handle->result = pg_result;
  5936. pgsql_handle->row = 0;
  5937. ZEND_REGISTER_RESOURCE(return_value, pgsql_handle, le_result);
  5938. return;
  5939. } else {
  5940. PQclear(pg_result);
  5941. RETURN_FALSE;
  5942. }
  5943. break;
  5944. }
  5945. } else if (php_pgsql_insert(pg_link, table, values, option, &sql TSRMLS_CC) == FAILURE) {
  5946. RETURN_FALSE;
  5947. }
  5948. if (return_sql) {
  5949. RETURN_STRING(sql, 0);
  5950. }
  5951. RETURN_TRUE;
  5952. }
  5953. /* }}} */
  5954. static inline int build_assignment_string(PGconn *pg_link, smart_str *querystr, HashTable *ht, int where_cond, const char *pad, int pad_len, ulong opt TSRMLS_DC)
  5955. {
  5956. HashPosition pos;
  5957. uint fld_len;
  5958. int key_type;
  5959. ulong num_idx;
  5960. char *fld, *tmp;
  5961. char buf[256];
  5962. zval **val;
  5963. for (zend_hash_internal_pointer_reset_ex(ht, &pos);
  5964. zend_hash_get_current_data_ex(ht, (void **)&val, &pos) == SUCCESS;
  5965. zend_hash_move_forward_ex(ht, &pos)) {
  5966. key_type = zend_hash_get_current_key_ex(ht, &fld, &fld_len, &num_idx, 0, &pos);
  5967. if (key_type == HASH_KEY_IS_LONG) {
  5968. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects associative array for values to be inserted");
  5969. return -1;
  5970. }
  5971. if (opt & PGSQL_DML_ESCAPE) {
  5972. tmp = PGSQLescapeIdentifier(pg_link, fld, fld_len);
  5973. smart_str_appends(querystr, tmp);
  5974. PGSQLfree(tmp);
  5975. } else {
  5976. smart_str_appendl(querystr, fld, fld_len - 1);
  5977. }
  5978. if (where_cond && (Z_TYPE_PP(val) == IS_BOOL || (Z_TYPE_PP(val) == IS_STRING && !strcmp(Z_STRVAL_PP(val), "NULL")))) {
  5979. smart_str_appends(querystr, " IS ");
  5980. } else {
  5981. smart_str_appendc(querystr, '=');
  5982. }
  5983. switch(Z_TYPE_PP(val)) {
  5984. case IS_STRING:
  5985. if (opt & PGSQL_DML_ESCAPE) {
  5986. size_t new_len;
  5987. tmp = (char *)safe_emalloc(Z_STRLEN_PP(val), 2, 1);
  5988. new_len = PQescapeStringConn(pg_link, tmp, Z_STRVAL_PP(val), Z_STRLEN_PP(val), NULL);
  5989. smart_str_appendc(querystr, '\'');
  5990. smart_str_appendl(querystr, tmp, new_len);
  5991. smart_str_appendc(querystr, '\'');
  5992. efree(tmp);
  5993. } else {
  5994. smart_str_appendl(querystr, Z_STRVAL_PP(val), Z_STRLEN_PP(val));
  5995. }
  5996. break;
  5997. case IS_LONG:
  5998. smart_str_append_long(querystr, Z_LVAL_PP(val));
  5999. break;
  6000. case IS_DOUBLE:
  6001. smart_str_appendl(querystr, buf, MIN(snprintf(buf, sizeof(buf), "%F", Z_DVAL_PP(val)), sizeof(buf)-1));
  6002. break;
  6003. case IS_NULL:
  6004. smart_str_appendl(querystr, "NULL", sizeof("NULL")-1);
  6005. break;
  6006. default:
  6007. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Expects scaler values. type=%d", Z_TYPE_PP(val));
  6008. return -1;
  6009. }
  6010. smart_str_appendl(querystr, pad, pad_len);
  6011. }
  6012. querystr->len -= pad_len;
  6013. return 0;
  6014. }
  6015. /* {{{ php_pgsql_update
  6016. */
  6017. PHP_PGSQL_API int php_pgsql_update(PGconn *pg_link, const char *table, zval *var_array, zval *ids_array, ulong opt, char **sql TSRMLS_DC)
  6018. {
  6019. zval *var_converted = NULL, *ids_converted = NULL;
  6020. smart_str querystr = {0};
  6021. int ret = FAILURE;
  6022. assert(pg_link != NULL);
  6023. assert(table != NULL);
  6024. assert(Z_TYPE_P(var_array) == IS_ARRAY);
  6025. assert(Z_TYPE_P(ids_array) == IS_ARRAY);
  6026. assert(!(opt & ~(PGSQL_CONV_OPTS|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_STRING|PGSQL_DML_ESCAPE)));
  6027. if (zend_hash_num_elements(Z_ARRVAL_P(var_array)) == 0
  6028. || zend_hash_num_elements(Z_ARRVAL_P(ids_array)) == 0) {
  6029. return FAILURE;
  6030. }
  6031. if (!(opt & (PGSQL_DML_NO_CONV|PGSQL_DML_ESCAPE))) {
  6032. MAKE_STD_ZVAL(var_converted);
  6033. array_init(var_converted);
  6034. if (php_pgsql_convert(pg_link, table, var_array, var_converted, (opt & PGSQL_CONV_OPTS) TSRMLS_CC) == FAILURE) {
  6035. goto cleanup;
  6036. }
  6037. var_array = var_converted;
  6038. MAKE_STD_ZVAL(ids_converted);
  6039. array_init(ids_converted);
  6040. if (php_pgsql_convert(pg_link, table, ids_array, ids_converted, (opt & PGSQL_CONV_OPTS) TSRMLS_CC) == FAILURE) {
  6041. goto cleanup;
  6042. }
  6043. ids_array = ids_converted;
  6044. }
  6045. smart_str_appends(&querystr, "UPDATE ");
  6046. build_tablename(&querystr, pg_link, table);
  6047. smart_str_appends(&querystr, " SET ");
  6048. if (build_assignment_string(pg_link, &querystr, Z_ARRVAL_P(var_array), 0, ",", 1, opt TSRMLS_CC))
  6049. goto cleanup;
  6050. smart_str_appends(&querystr, " WHERE ");
  6051. if (build_assignment_string(pg_link, &querystr, Z_ARRVAL_P(ids_array), 1, " AND ", sizeof(" AND ")-1, opt TSRMLS_CC))
  6052. goto cleanup;
  6053. smart_str_appendc(&querystr, ';');
  6054. smart_str_0(&querystr);
  6055. if ((opt & PGSQL_DML_EXEC) && do_exec(&querystr, PGRES_COMMAND_OK, pg_link, opt TSRMLS_CC) == 0) {
  6056. ret = SUCCESS;
  6057. } else if (opt & PGSQL_DML_STRING) {
  6058. ret = SUCCESS;
  6059. }
  6060. cleanup:
  6061. if (var_converted) {
  6062. zval_dtor(var_converted);
  6063. FREE_ZVAL(var_converted);
  6064. }
  6065. if (ids_converted) {
  6066. zval_dtor(ids_converted);
  6067. FREE_ZVAL(ids_converted);
  6068. }
  6069. if (ret == SUCCESS && (opt & PGSQL_DML_STRING)) {
  6070. *sql = querystr.c;
  6071. }
  6072. else {
  6073. smart_str_free(&querystr);
  6074. }
  6075. return ret;
  6076. }
  6077. /* }}} */
  6078. /* {{{ proto mixed pg_update(resource db, string table, array fields, array ids[, int options])
  6079. Update table using values (field=>value) and ids (id=>value) */
  6080. PHP_FUNCTION(pg_update)
  6081. {
  6082. zval *pgsql_link, *values, *ids;
  6083. char *table, *sql = NULL;
  6084. int table_len;
  6085. ulong option = PGSQL_DML_EXEC;
  6086. PGconn *pg_link;
  6087. int id = -1, argc = ZEND_NUM_ARGS();
  6088. if (zend_parse_parameters(argc TSRMLS_CC, "rsaa|l",
  6089. &pgsql_link, &table, &table_len, &values, &ids, &option) == FAILURE) {
  6090. return;
  6091. }
  6092. if (option & ~(PGSQL_CONV_OPTS|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_STRING|PGSQL_DML_ESCAPE)) {
  6093. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid option is specified");
  6094. RETURN_FALSE;
  6095. }
  6096. ZEND_FETCH_RESOURCE2(pg_link, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  6097. if (php_pgsql_flush_query(pg_link TSRMLS_CC)) {
  6098. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected unhandled result(s) in connection");
  6099. }
  6100. if (php_pgsql_update(pg_link, table, values, ids, option, &sql TSRMLS_CC) == FAILURE) {
  6101. RETURN_FALSE;
  6102. }
  6103. if (option & PGSQL_DML_STRING) {
  6104. RETURN_STRING(sql, 0);
  6105. }
  6106. RETURN_TRUE;
  6107. }
  6108. /* }}} */
  6109. /* {{{ php_pgsql_delete
  6110. */
  6111. PHP_PGSQL_API int php_pgsql_delete(PGconn *pg_link, const char *table, zval *ids_array, ulong opt, char **sql TSRMLS_DC)
  6112. {
  6113. zval *ids_converted = NULL;
  6114. smart_str querystr = {0};
  6115. int ret = FAILURE;
  6116. assert(pg_link != NULL);
  6117. assert(table != NULL);
  6118. assert(Z_TYPE_P(ids_array) == IS_ARRAY);
  6119. assert(!(opt & ~(PGSQL_CONV_FORCE_NULL|PGSQL_DML_EXEC|PGSQL_DML_STRING|PGSQL_DML_ESCAPE)));
  6120. if (zend_hash_num_elements(Z_ARRVAL_P(ids_array)) == 0) {
  6121. return FAILURE;
  6122. }
  6123. if (!(opt & (PGSQL_DML_NO_CONV|PGSQL_DML_ESCAPE))) {
  6124. MAKE_STD_ZVAL(ids_converted);
  6125. array_init(ids_converted);
  6126. if (php_pgsql_convert(pg_link, table, ids_array, ids_converted, (opt & PGSQL_CONV_OPTS) TSRMLS_CC) == FAILURE) {
  6127. goto cleanup;
  6128. }
  6129. ids_array = ids_converted;
  6130. }
  6131. smart_str_appends(&querystr, "DELETE FROM ");
  6132. build_tablename(&querystr, pg_link, table);
  6133. smart_str_appends(&querystr, " WHERE ");
  6134. if (build_assignment_string(pg_link, &querystr, Z_ARRVAL_P(ids_array), 1, " AND ", sizeof(" AND ")-1, opt TSRMLS_CC))
  6135. goto cleanup;
  6136. smart_str_appendc(&querystr, ';');
  6137. smart_str_0(&querystr);
  6138. if ((opt & PGSQL_DML_EXEC) && do_exec(&querystr, PGRES_COMMAND_OK, pg_link, opt TSRMLS_CC) == 0) {
  6139. ret = SUCCESS;
  6140. } else if (opt & PGSQL_DML_STRING) {
  6141. ret = SUCCESS;
  6142. }
  6143. cleanup:
  6144. if (ids_converted) {
  6145. zval_dtor(ids_converted);
  6146. FREE_ZVAL(ids_converted);
  6147. }
  6148. if (ret == SUCCESS && (opt & PGSQL_DML_STRING)) {
  6149. *sql = querystr.c;
  6150. }
  6151. else {
  6152. smart_str_free(&querystr);
  6153. }
  6154. return ret;
  6155. }
  6156. /* }}} */
  6157. /* {{{ proto mixed pg_delete(resource db, string table, array ids[, int options])
  6158. Delete records has ids (id=>value) */
  6159. PHP_FUNCTION(pg_delete)
  6160. {
  6161. zval *pgsql_link, *ids;
  6162. char *table, *sql = NULL;
  6163. int table_len;
  6164. ulong option = PGSQL_DML_EXEC;
  6165. PGconn *pg_link;
  6166. int id = -1, argc = ZEND_NUM_ARGS();
  6167. if (zend_parse_parameters(argc TSRMLS_CC, "rsa|l",
  6168. &pgsql_link, &table, &table_len, &ids, &option) == FAILURE) {
  6169. return;
  6170. }
  6171. if (option & ~(PGSQL_CONV_FORCE_NULL|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_STRING|PGSQL_DML_ESCAPE)) {
  6172. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid option is specified");
  6173. RETURN_FALSE;
  6174. }
  6175. ZEND_FETCH_RESOURCE2(pg_link, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  6176. if (php_pgsql_flush_query(pg_link TSRMLS_CC)) {
  6177. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected unhandled result(s) in connection");
  6178. }
  6179. if (php_pgsql_delete(pg_link, table, ids, option, &sql TSRMLS_CC) == FAILURE) {
  6180. RETURN_FALSE;
  6181. }
  6182. if (option & PGSQL_DML_STRING) {
  6183. RETURN_STRING(sql, 0);
  6184. }
  6185. RETURN_TRUE;
  6186. }
  6187. /* }}} */
  6188. /* {{{ php_pgsql_result2array
  6189. */
  6190. PHP_PGSQL_API int php_pgsql_result2array(PGresult *pg_result, zval *ret_array TSRMLS_DC)
  6191. {
  6192. zval *row;
  6193. char *field_name;
  6194. size_t num_fields;
  6195. int pg_numrows, pg_row;
  6196. uint i;
  6197. assert(Z_TYPE_P(ret_array) == IS_ARRAY);
  6198. if ((pg_numrows = PQntuples(pg_result)) <= 0) {
  6199. return FAILURE;
  6200. }
  6201. for (pg_row = 0; pg_row < pg_numrows; pg_row++) {
  6202. MAKE_STD_ZVAL(row);
  6203. array_init(row);
  6204. add_index_zval(ret_array, pg_row, row);
  6205. for (i = 0, num_fields = PQnfields(pg_result); i < num_fields; i++) {
  6206. if (PQgetisnull(pg_result, pg_row, i)) {
  6207. field_name = PQfname(pg_result, i);
  6208. add_assoc_null(row, field_name);
  6209. } else {
  6210. char *element = PQgetvalue(pg_result, pg_row, i);
  6211. if (element) {
  6212. char *data;
  6213. size_t data_len;
  6214. const size_t element_len = strlen(element);
  6215. data = safe_estrndup(element, element_len);
  6216. data_len = element_len;
  6217. field_name = PQfname(pg_result, i);
  6218. add_assoc_stringl(row, field_name, data, data_len, 0);
  6219. }
  6220. }
  6221. }
  6222. }
  6223. return SUCCESS;
  6224. }
  6225. /* }}} */
  6226. /* {{{ php_pgsql_select
  6227. */
  6228. PHP_PGSQL_API int php_pgsql_select(PGconn *pg_link, const char *table, zval *ids_array, zval *ret_array, ulong opt, char **sql TSRMLS_DC)
  6229. {
  6230. zval *ids_converted = NULL;
  6231. smart_str querystr = {0};
  6232. int ret = FAILURE;
  6233. PGresult *pg_result;
  6234. assert(pg_link != NULL);
  6235. assert(table != NULL);
  6236. assert(Z_TYPE_P(ids_array) == IS_ARRAY);
  6237. assert(Z_TYPE_P(ret_array) == IS_ARRAY);
  6238. assert(!(opt & ~(PGSQL_CONV_OPTS|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_ASYNC|PGSQL_DML_STRING|PGSQL_DML_ESCAPE)));
  6239. if (zend_hash_num_elements(Z_ARRVAL_P(ids_array)) == 0) {
  6240. return FAILURE;
  6241. }
  6242. if (!(opt & (PGSQL_DML_NO_CONV|PGSQL_DML_ESCAPE))) {
  6243. MAKE_STD_ZVAL(ids_converted);
  6244. array_init(ids_converted);
  6245. if (php_pgsql_convert(pg_link, table, ids_array, ids_converted, (opt & PGSQL_CONV_OPTS) TSRMLS_CC) == FAILURE) {
  6246. goto cleanup;
  6247. }
  6248. ids_array = ids_converted;
  6249. }
  6250. smart_str_appends(&querystr, "SELECT * FROM ");
  6251. build_tablename(&querystr, pg_link, table);
  6252. smart_str_appends(&querystr, " WHERE ");
  6253. if (build_assignment_string(pg_link, &querystr, Z_ARRVAL_P(ids_array), 1, " AND ", sizeof(" AND ")-1, opt TSRMLS_CC))
  6254. goto cleanup;
  6255. smart_str_appendc(&querystr, ';');
  6256. smart_str_0(&querystr);
  6257. pg_result = PQexec(pg_link, querystr.c);
  6258. if (PQresultStatus(pg_result) == PGRES_TUPLES_OK) {
  6259. ret = php_pgsql_result2array(pg_result, ret_array TSRMLS_CC);
  6260. } else {
  6261. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Failed to execute '%s'", querystr.c);
  6262. }
  6263. PQclear(pg_result);
  6264. cleanup:
  6265. if (ids_converted) {
  6266. zval_dtor(ids_converted);
  6267. FREE_ZVAL(ids_converted);
  6268. }
  6269. if (ret == SUCCESS && (opt & PGSQL_DML_STRING)) {
  6270. *sql = querystr.c;
  6271. }
  6272. else {
  6273. smart_str_free(&querystr);
  6274. }
  6275. return ret;
  6276. }
  6277. /* }}} */
  6278. /* {{{ proto mixed pg_select(resource db, string table, array ids[, int options])
  6279. Select records that has ids (id=>value) */
  6280. PHP_FUNCTION(pg_select)
  6281. {
  6282. zval *pgsql_link, *ids;
  6283. char *table, *sql = NULL;
  6284. int table_len;
  6285. ulong option = PGSQL_DML_EXEC;
  6286. PGconn *pg_link;
  6287. int id = -1, argc = ZEND_NUM_ARGS();
  6288. if (zend_parse_parameters(argc TSRMLS_CC, "rsa|l",
  6289. &pgsql_link, &table, &table_len, &ids, &option) == FAILURE) {
  6290. return;
  6291. }
  6292. if (option & ~(PGSQL_CONV_FORCE_NULL|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_ASYNC|PGSQL_DML_STRING|PGSQL_DML_ESCAPE)) {
  6293. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid option is specified");
  6294. RETURN_FALSE;
  6295. }
  6296. ZEND_FETCH_RESOURCE2(pg_link, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
  6297. if (php_pgsql_flush_query(pg_link TSRMLS_CC)) {
  6298. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected unhandled result(s) in connection");
  6299. }
  6300. array_init(return_value);
  6301. if (php_pgsql_select(pg_link, table, ids, return_value, option, &sql TSRMLS_CC) == FAILURE) {
  6302. zval_dtor(return_value);
  6303. RETURN_FALSE;
  6304. }
  6305. if (option & PGSQL_DML_STRING) {
  6306. zval_dtor(return_value);
  6307. RETURN_STRING(sql, 0);
  6308. }
  6309. return;
  6310. }
  6311. /* }}} */
  6312. #endif
  6313. /*
  6314. * Local variables:
  6315. * tab-width: 4
  6316. * c-basic-offset: 4
  6317. * End:
  6318. * vim600: sw=4 ts=4 fdm=marker
  6319. * vim<600: sw=4 ts=4
  6320. */