1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929 |
- /*
- +----------------------------------------------------------------------+
- | Copyright (c) The PHP Group |
- +----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | https://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
- +----------------------------------------------------------------------+
- | Authors: Zeev Suraski <zeev@php.net> |
- | Jouni Ahto <jouni.ahto@exdec.fi> |
- | Yasuo Ohgaki <yohgaki@php.net> |
- | Youichi Iwakiri <yiwakiri@st.rim.or.jp> (pg_copy_*) |
- | Chris Kings-Lynne <chriskl@php.net> (v3 protocol) |
- +----------------------------------------------------------------------+
- */
- #include <stdlib.h>
- #define PHP_PGSQL_PRIVATE 1
- #ifdef HAVE_CONFIG_H
- #include "config.h"
- #endif
- #define SMART_STR_PREALLOC 512
- #include "php.h"
- #include "php_ini.h"
- #include "ext/standard/php_standard.h"
- #include "zend_smart_str.h"
- #include "ext/pcre/php_pcre.h"
- #ifdef PHP_WIN32
- # include "win32/time.h"
- #endif
- #include "php_pgsql.h"
- #include "php_globals.h"
- #include "zend_exceptions.h"
- #include "pgsql_arginfo.h"
- #ifdef HAVE_PGSQL
- #ifndef InvalidOid
- #define InvalidOid ((Oid) 0)
- #endif
- #define PGSQL_ASSOC 1<<0
- #define PGSQL_NUM 1<<1
- #define PGSQL_BOTH (PGSQL_ASSOC|PGSQL_NUM)
- #define PGSQL_NOTICE_LAST 1 /* Get the last notice */
- #define PGSQL_NOTICE_ALL 2 /* Get all notices */
- #define PGSQL_NOTICE_CLEAR 3 /* Remove notices */
- #define PGSQL_STATUS_LONG 1
- #define PGSQL_STATUS_STRING 2
- #define PGSQL_MAX_LENGTH_OF_LONG 30
- #define PGSQL_MAX_LENGTH_OF_DOUBLE 60
- #if ZEND_LONG_MAX < UINT_MAX
- #define PGSQL_RETURN_OID(oid) do { \
- if (oid > ZEND_LONG_MAX) { \
- RETURN_STR(zend_ulong_to_str(oid)); \
- } \
- RETURN_LONG((zend_long)oid); \
- } while(0)
- #else
- #define PGSQL_RETURN_OID(oid) RETURN_LONG((zend_long)oid)
- #endif
- #define CHECK_DEFAULT_LINK(x) \
- if ((x) == NULL) { \
- zend_throw_error(NULL, "No PostgreSQL connection opened yet"); \
- RETURN_THROWS(); \
- }
- /* This is a bit hacky as the macro usage is "link = FETCH_DEFAULT_LINK();" */
- #define FETCH_DEFAULT_LINK() \
- (PGG(default_link) ? pgsql_link_from_obj(PGG(default_link)) : NULL); \
- php_error_docref(NULL, E_DEPRECATED, "Automatic fetching of PostgreSQL connection is deprecated")
- /* Used only when creating a connection */
- #define FETCH_DEFAULT_LINK_NO_WARNING() \
- (PGG(default_link) ? pgsql_link_from_obj(PGG(default_link)) : NULL)
- #define CHECK_PGSQL_LINK(link_handle) \
- if (link_handle->conn == NULL) { \
- zend_throw_error(NULL, "PostgreSQL connection has already been closed"); \
- RETURN_THROWS(); \
- }
- #define CHECK_PGSQL_RESULT(result_handle) \
- if (result_handle->result == NULL) { \
- zend_throw_error(NULL, "PostgreSQL result has already been closed"); \
- RETURN_THROWS(); \
- }
- #define CHECK_PGSQL_LOB(lob) \
- if (lob->conn == NULL) { \
- zend_throw_error(NULL, "PostgreSQL large object has already been closed"); \
- RETURN_THROWS(); \
- }
- #ifndef HAVE_PQFREEMEM
- #define PQfreemem free
- #endif
- ZEND_DECLARE_MODULE_GLOBALS(pgsql)
- static PHP_GINIT_FUNCTION(pgsql);
- /* {{{ pgsql_module_entry */
- zend_module_entry pgsql_module_entry = {
- STANDARD_MODULE_HEADER,
- "pgsql",
- ext_functions,
- PHP_MINIT(pgsql),
- PHP_MSHUTDOWN(pgsql),
- PHP_RINIT(pgsql),
- PHP_RSHUTDOWN(pgsql),
- PHP_MINFO(pgsql),
- PHP_PGSQL_VERSION,
- PHP_MODULE_GLOBALS(pgsql),
- PHP_GINIT(pgsql),
- NULL,
- NULL,
- STANDARD_MODULE_PROPERTIES_EX
- };
- /* }}} */
- #ifdef COMPILE_DL_PGSQL
- #ifdef ZTS
- ZEND_TSRMLS_CACHE_DEFINE()
- #endif
- ZEND_GET_MODULE(pgsql)
- #endif
- static int le_plink;
- static zend_class_entry *pgsql_link_ce, *pgsql_result_ce, *pgsql_lob_ce;
- static zend_object_handlers pgsql_link_object_handlers, pgsql_result_object_handlers, pgsql_lob_object_handlers;
- static inline pgsql_link_handle *pgsql_link_from_obj(zend_object *obj) {
- return (pgsql_link_handle *)((char *)(obj) - XtOffsetOf(pgsql_link_handle, std));
- }
- #define Z_PGSQL_LINK_P(zv) pgsql_link_from_obj(Z_OBJ_P(zv))
- static zend_object *pgsql_link_create_object(zend_class_entry *class_type) {
- pgsql_link_handle *intern = zend_object_alloc(sizeof(pgsql_link_handle), class_type);
- zend_object_std_init(&intern->std, class_type);
- object_properties_init(&intern->std, class_type);
- intern->std.handlers = &pgsql_link_object_handlers;
- return &intern->std;
- }
- static zend_function *pgsql_link_get_constructor(zend_object *object) {
- zend_throw_error(NULL, "Cannot directly construct PgSql\\Connection, use pg_connect() or pg_pconnect() instead");
- return NULL;
- }
- static void pgsql_link_free(pgsql_link_handle *link)
- {
- PGresult *res;
- while ((res = PQgetResult(link->conn))) {
- PQclear(res);
- }
- if (!link->persistent) {
- PQfinish(link->conn);
- }
- PGG(num_links)--;
- zend_hash_del(&PGG(connections), link->hash);
- link->conn = NULL;
- zend_string_release(link->hash);
- if (link->notices) {
- zend_hash_destroy(link->notices);
- FREE_HASHTABLE(link->notices);
- link->notices = NULL;
- }
- }
- static void pgsql_link_free_obj(zend_object *obj)
- {
- pgsql_link_handle *link = pgsql_link_from_obj(obj);
- if (link->conn) {
- pgsql_link_free(link);
- }
- zend_object_std_dtor(&link->std);
- }
- static inline pgsql_result_handle *pgsql_result_from_obj(zend_object *obj) {
- return (pgsql_result_handle *)((char *)(obj) - XtOffsetOf(pgsql_result_handle, std));
- }
- #define Z_PGSQL_RESULT_P(zv) pgsql_result_from_obj(Z_OBJ_P(zv))
- static zend_object *pgsql_result_create_object(zend_class_entry *class_type) {
- pgsql_result_handle *intern = zend_object_alloc(sizeof(pgsql_result_handle), class_type);
- zend_object_std_init(&intern->std, class_type);
- object_properties_init(&intern->std, class_type);
- intern->std.handlers = &pgsql_result_object_handlers;
- return &intern->std;
- }
- static zend_function *pgsql_result_get_constructor(zend_object *object) {
- zend_throw_error(NULL, "Cannot directly construct PgSql\\Result, use a dedicated function instead");
- return NULL;
- }
- static void pgsql_result_free(pgsql_result_handle *pg_result)
- {
- PQclear(pg_result->result);
- pg_result->result = NULL;
- }
- static void pgsql_result_free_obj(zend_object *obj)
- {
- pgsql_result_handle *pg_result = pgsql_result_from_obj(obj);
- if (pg_result->result) {
- pgsql_result_free(pg_result);
- }
- zend_object_std_dtor(&pg_result->std);
- }
- static inline pgLofp *pgsql_lob_from_obj(zend_object *obj) {
- return (pgLofp *)((char *)(obj) - XtOffsetOf(pgLofp, std));
- }
- #define Z_PGSQL_LOB_P(zv) pgsql_lob_from_obj(Z_OBJ_P(zv))
- static zend_object *pgsql_lob_create_object(zend_class_entry *class_type) {
- pgLofp *intern = zend_object_alloc(sizeof(pgLofp), class_type);
- zend_object_std_init(&intern->std, class_type);
- object_properties_init(&intern->std, class_type);
- intern->std.handlers = &pgsql_lob_object_handlers;
- return &intern->std;
- }
- static zend_function *pgsql_lob_get_constructor(zend_object *object) {
- zend_throw_error(NULL, "Cannot directly construct PgSql\\Lob, use pg_lo_open() instead");
- return NULL;
- }
- static void pgsql_lob_free_obj(zend_object *obj)
- {
- pgLofp *lofp = pgsql_lob_from_obj(obj);
- zend_object_std_dtor(&lofp->std);
- }
- /* Compatibility definitions */
- #ifndef HAVE_PGSQL_WITH_MULTIBYTE_SUPPORT
- #define pg_encoding_to_char(x) "SQL_ASCII"
- #endif
- static zend_string *_php_pgsql_trim_message(const char *message)
- {
- size_t i = strlen(message);
- if (i>2 && (message[i-2] == '\r' || message[i-2] == '\n') && message[i-1] == '.') {
- --i;
- }
- while (i>1 && (message[i-1] == '\r' || message[i-1] == '\n')) {
- --i;
- }
- return zend_string_init(message, i, 0);
- }
- #define PHP_PQ_ERROR(text, pgsql) { \
- zend_string *msgbuf = _php_pgsql_trim_message(PQerrorMessage(pgsql)); \
- php_error_docref(NULL, E_WARNING, text, ZSTR_VAL(msgbuf)); \
- zend_string_release(msgbuf); \
- } \
- static void php_pgsql_set_default_link(zend_object *obj)
- {
- GC_ADDREF(obj);
- if (PGG(default_link) != NULL) {
- zend_object_release(PGG(default_link));
- }
- PGG(default_link) = obj;
- }
- static void _close_pgsql_plink(zend_resource *rsrc)
- {
- PGconn *link = (PGconn *)rsrc->ptr;
- PGresult *res;
- while ((res = PQgetResult(link))) {
- PQclear(res);
- }
- PQfinish(link);
- PGG(num_persistent)--;
- PGG(num_links)--;
- rsrc->ptr = NULL;
- }
- static void _php_pgsql_notice_handler(void *l, const char *message)
- {
- if (PGG(ignore_notices)) {
- return;
- }
- zval tmp;
- pgsql_link_handle *link = (pgsql_link_handle *) l;
- if (!link->notices) {
- link->notices = zend_new_array(1);
- }
- zend_string *trimmed_message = _php_pgsql_trim_message(message);
- if (PGG(log_notices)) {
- php_error_docref(NULL, E_NOTICE, "%s", ZSTR_VAL(trimmed_message));
- }
- ZVAL_STR(&tmp, trimmed_message);
- zend_hash_next_index_insert(link->notices, &tmp);
- }
- static int _rollback_transactions(zval *el)
- {
- PGconn *link;
- PGresult *res;
- zend_resource *rsrc = Z_RES_P(el);
- if (rsrc->type != le_plink) {
- return ZEND_HASH_APPLY_KEEP;
- }
- link = (PGconn *) rsrc->ptr;
- if (PQsetnonblocking(link, 0)) {
- php_error_docref("ref.pgsql", E_NOTICE, "Cannot set connection to blocking mode");
- return -1;
- }
- while ((res = PQgetResult(link))) {
- PQclear(res);
- }
- if ((PQprotocolVersion(link) >= 3 && PQtransactionStatus(link) != PQTRANS_IDLE) || PQprotocolVersion(link) < 3) {
- int orig = PGG(ignore_notices);
- PGG(ignore_notices) = 1;
- res = PQexec(link,"ROLLBACK;");
- PQclear(res);
- PGG(ignore_notices) = orig;
- }
- return ZEND_HASH_APPLY_KEEP;
- }
- static void release_string(zval *zv)
- {
- zend_string_release((zend_string *) Z_PTR_P(zv));
- }
- static bool _php_pgsql_identifier_is_escaped(const char *identifier, size_t len) /* {{{ */
- {
- /* Handle edge case. Cannot be a escaped string */
- if (len <= 2) {
- return false;
- }
- /* Detect double quotes */
- if (identifier[0] == '"' && identifier[len-1] == '"') {
- size_t i;
- /* Detect wrong format of " inside of escaped string */
- for (i = 1; i < len-1; i++) {
- if (identifier[i] == '"' && (identifier[++i] != '"' || i == len-1)) {
- return false;
- }
- }
- } else {
- return false;
- }
- /* Escaped properly */
- return true;
- }
- /* {{{ PHP_INI */
- PHP_INI_BEGIN()
- STD_PHP_INI_BOOLEAN( "pgsql.allow_persistent", "1", PHP_INI_SYSTEM, OnUpdateBool, allow_persistent, zend_pgsql_globals, pgsql_globals)
- STD_PHP_INI_ENTRY_EX("pgsql.max_persistent", "-1", PHP_INI_SYSTEM, OnUpdateLong, max_persistent, zend_pgsql_globals, pgsql_globals, display_link_numbers)
- STD_PHP_INI_ENTRY_EX("pgsql.max_links", "-1", PHP_INI_SYSTEM, OnUpdateLong, max_links, zend_pgsql_globals, pgsql_globals, display_link_numbers)
- STD_PHP_INI_BOOLEAN( "pgsql.auto_reset_persistent", "0", PHP_INI_SYSTEM, OnUpdateBool, auto_reset_persistent, zend_pgsql_globals, pgsql_globals)
- STD_PHP_INI_BOOLEAN( "pgsql.ignore_notice", "0", PHP_INI_ALL, OnUpdateBool, ignore_notices, zend_pgsql_globals, pgsql_globals)
- STD_PHP_INI_BOOLEAN( "pgsql.log_notice", "0", PHP_INI_ALL, OnUpdateBool, log_notices, zend_pgsql_globals, pgsql_globals)
- PHP_INI_END()
- static PHP_GINIT_FUNCTION(pgsql)
- {
- #if defined(COMPILE_DL_PGSQL) && defined(ZTS)
- ZEND_TSRMLS_CACHE_UPDATE();
- #endif
- memset(pgsql_globals, 0, sizeof(zend_pgsql_globals));
- zend_hash_init(&pgsql_globals->connections, 0, NULL, NULL, 1);
- }
- static void php_libpq_version(char *buf, size_t len)
- {
- int version = PQlibVersion();
- int major = version / 10000;
- if (major >= 10) {
- int minor = version % 10000;
- snprintf(buf, len, "%d.%d", major, minor);
- } else {
- int minor = version / 100 % 100;
- int revision = version % 100;
- snprintf(buf, len, "%d.%d.%d", major, minor, revision);
- }
- }
- PHP_MINIT_FUNCTION(pgsql)
- {
- char buf[16];
- REGISTER_INI_ENTRIES();
- le_plink = zend_register_list_destructors_ex(NULL, _close_pgsql_plink, "pgsql link persistent", module_number);
- pgsql_link_ce = register_class_PgSql_Connection();
- pgsql_link_ce->create_object = pgsql_link_create_object;
- memcpy(&pgsql_link_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
- pgsql_link_object_handlers.offset = XtOffsetOf(pgsql_link_handle, std);
- pgsql_link_object_handlers.free_obj = pgsql_link_free_obj;
- pgsql_link_object_handlers.get_constructor = pgsql_link_get_constructor;
- pgsql_link_object_handlers.clone_obj = NULL;
- pgsql_link_object_handlers.compare = zend_objects_not_comparable;
- pgsql_result_ce = register_class_PgSql_Result();
- pgsql_result_ce->create_object = pgsql_result_create_object;
- memcpy(&pgsql_result_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
- pgsql_result_object_handlers.offset = XtOffsetOf(pgsql_result_handle, std);
- pgsql_result_object_handlers.free_obj = pgsql_result_free_obj;
- pgsql_result_object_handlers.get_constructor = pgsql_result_get_constructor;
- pgsql_result_object_handlers.clone_obj = NULL;
- pgsql_result_object_handlers.compare = zend_objects_not_comparable;
- pgsql_lob_ce = register_class_PgSql_Lob();
- pgsql_lob_ce->create_object = pgsql_lob_create_object;
- memcpy(&pgsql_lob_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
- pgsql_lob_object_handlers.offset = XtOffsetOf(pgLofp, std);
- pgsql_lob_object_handlers.free_obj = pgsql_lob_free_obj;
- pgsql_lob_object_handlers.get_constructor = pgsql_lob_get_constructor;
- pgsql_lob_object_handlers.clone_obj = NULL;
- pgsql_lob_object_handlers.compare = zend_objects_not_comparable;
- /* libpq version */
- php_libpq_version(buf, sizeof(buf));
- REGISTER_STRING_CONSTANT("PGSQL_LIBPQ_VERSION", buf, CONST_CS | CONST_PERSISTENT);
- REGISTER_STRING_CONSTANT("PGSQL_LIBPQ_VERSION_STR", buf, CONST_CS | CONST_PERSISTENT | CONST_DEPRECATED);
- /* For connection option */
- REGISTER_LONG_CONSTANT("PGSQL_CONNECT_FORCE_NEW", PGSQL_CONNECT_FORCE_NEW, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PGSQL_CONNECT_ASYNC", PGSQL_CONNECT_ASYNC, CONST_CS | CONST_PERSISTENT);
- /* For pg_fetch_array() */
- REGISTER_LONG_CONSTANT("PGSQL_ASSOC", PGSQL_ASSOC, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PGSQL_NUM", PGSQL_NUM, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PGSQL_BOTH", PGSQL_BOTH, CONST_CS | CONST_PERSISTENT);
- /* For pg_last_notice() */
- REGISTER_LONG_CONSTANT("PGSQL_NOTICE_LAST", PGSQL_NOTICE_LAST, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PGSQL_NOTICE_ALL", PGSQL_NOTICE_ALL, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PGSQL_NOTICE_CLEAR", PGSQL_NOTICE_CLEAR, CONST_CS | CONST_PERSISTENT);
- /* For pg_connection_status() */
- REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_BAD", CONNECTION_BAD, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_OK", CONNECTION_OK, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_STARTED", CONNECTION_STARTED, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_MADE", CONNECTION_MADE, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_AWAITING_RESPONSE", CONNECTION_AWAITING_RESPONSE, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_AUTH_OK", CONNECTION_AUTH_OK, CONST_CS | CONST_PERSISTENT);
- #ifdef CONNECTION_SSL_STARTUP
- REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_SSL_STARTUP", CONNECTION_SSL_STARTUP, CONST_CS | CONST_PERSISTENT);
- #endif
- REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_SETENV", CONNECTION_SETENV, CONST_CS | CONST_PERSISTENT);
- /* For pg_connect_poll() */
- REGISTER_LONG_CONSTANT("PGSQL_POLLING_FAILED", PGRES_POLLING_FAILED, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PGSQL_POLLING_READING", PGRES_POLLING_READING, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PGSQL_POLLING_WRITING", PGRES_POLLING_WRITING, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PGSQL_POLLING_OK", PGRES_POLLING_OK, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PGSQL_POLLING_ACTIVE", PGRES_POLLING_ACTIVE, CONST_CS | CONST_PERSISTENT);
- /* For pg_transaction_status() */
- REGISTER_LONG_CONSTANT("PGSQL_TRANSACTION_IDLE", PQTRANS_IDLE, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PGSQL_TRANSACTION_ACTIVE", PQTRANS_ACTIVE, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PGSQL_TRANSACTION_INTRANS", PQTRANS_INTRANS, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PGSQL_TRANSACTION_INERROR", PQTRANS_INERROR, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PGSQL_TRANSACTION_UNKNOWN", PQTRANS_UNKNOWN, CONST_CS | CONST_PERSISTENT);
- /* For pg_set_error_verbosity() */
- REGISTER_LONG_CONSTANT("PGSQL_ERRORS_TERSE", PQERRORS_TERSE, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PGSQL_ERRORS_DEFAULT", PQERRORS_DEFAULT, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PGSQL_ERRORS_VERBOSE", PQERRORS_VERBOSE, CONST_CS | CONST_PERSISTENT);
- /* For lo_seek() */
- REGISTER_LONG_CONSTANT("PGSQL_SEEK_SET", SEEK_SET, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PGSQL_SEEK_CUR", SEEK_CUR, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PGSQL_SEEK_END", SEEK_END, CONST_CS | CONST_PERSISTENT);
- /* For pg_result_status() return value type */
- REGISTER_LONG_CONSTANT("PGSQL_STATUS_LONG", PGSQL_STATUS_LONG, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PGSQL_STATUS_STRING", PGSQL_STATUS_STRING, CONST_CS | CONST_PERSISTENT);
- /* For pg_result_status() return value */
- REGISTER_LONG_CONSTANT("PGSQL_EMPTY_QUERY", PGRES_EMPTY_QUERY, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PGSQL_COMMAND_OK", PGRES_COMMAND_OK, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PGSQL_TUPLES_OK", PGRES_TUPLES_OK, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PGSQL_COPY_OUT", PGRES_COPY_OUT, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PGSQL_COPY_IN", PGRES_COPY_IN, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PGSQL_BAD_RESPONSE", PGRES_BAD_RESPONSE, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PGSQL_NONFATAL_ERROR", PGRES_NONFATAL_ERROR, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PGSQL_FATAL_ERROR", PGRES_FATAL_ERROR, CONST_CS | CONST_PERSISTENT);
- /* For pg_result_error_field() field codes */
- REGISTER_LONG_CONSTANT("PGSQL_DIAG_SEVERITY", PG_DIAG_SEVERITY, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PGSQL_DIAG_SQLSTATE", PG_DIAG_SQLSTATE, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PGSQL_DIAG_MESSAGE_PRIMARY", PG_DIAG_MESSAGE_PRIMARY, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PGSQL_DIAG_MESSAGE_DETAIL", PG_DIAG_MESSAGE_DETAIL, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PGSQL_DIAG_MESSAGE_HINT", PG_DIAG_MESSAGE_HINT, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PGSQL_DIAG_STATEMENT_POSITION", PG_DIAG_STATEMENT_POSITION, CONST_CS | CONST_PERSISTENT);
- #ifdef PG_DIAG_INTERNAL_POSITION
- REGISTER_LONG_CONSTANT("PGSQL_DIAG_INTERNAL_POSITION", PG_DIAG_INTERNAL_POSITION, CONST_CS | CONST_PERSISTENT);
- #endif
- #ifdef PG_DIAG_INTERNAL_QUERY
- REGISTER_LONG_CONSTANT("PGSQL_DIAG_INTERNAL_QUERY", PG_DIAG_INTERNAL_QUERY, CONST_CS | CONST_PERSISTENT);
- #endif
- REGISTER_LONG_CONSTANT("PGSQL_DIAG_CONTEXT", PG_DIAG_CONTEXT, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PGSQL_DIAG_SOURCE_FILE", PG_DIAG_SOURCE_FILE, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PGSQL_DIAG_SOURCE_LINE", PG_DIAG_SOURCE_LINE, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PGSQL_DIAG_SOURCE_FUNCTION", PG_DIAG_SOURCE_FUNCTION, CONST_CS | CONST_PERSISTENT);
- #ifdef PG_DIAG_SCHEMA_NAME
- REGISTER_LONG_CONSTANT("PGSQL_DIAG_SCHEMA_NAME", PG_DIAG_SCHEMA_NAME, CONST_CS | CONST_PERSISTENT);
- #endif
- #ifdef PG_DIAG_TABLE_NAME
- REGISTER_LONG_CONSTANT("PGSQL_DIAG_TABLE_NAME", PG_DIAG_TABLE_NAME, CONST_CS | CONST_PERSISTENT);
- #endif
- #ifdef PG_DIAG_COLUMN_NAME
- REGISTER_LONG_CONSTANT("PGSQL_DIAG_COLUMN_NAME", PG_DIAG_COLUMN_NAME, CONST_CS | CONST_PERSISTENT);
- #endif
- #ifdef PG_DIAG_DATATYPE_NAME
- REGISTER_LONG_CONSTANT("PGSQL_DIAG_DATATYPE_NAME", PG_DIAG_DATATYPE_NAME, CONST_CS | CONST_PERSISTENT);
- #endif
- #ifdef PG_DIAG_CONSTRAINT_NAME
- REGISTER_LONG_CONSTANT("PGSQL_DIAG_CONSTRAINT_NAME", PG_DIAG_CONSTRAINT_NAME, CONST_CS | CONST_PERSISTENT);
- #endif
- #ifdef PG_DIAG_SEVERITY_NONLOCALIZED
- REGISTER_LONG_CONSTANT("PGSQL_DIAG_SEVERITY_NONLOCALIZED", PG_DIAG_SEVERITY_NONLOCALIZED, CONST_CS | CONST_PERSISTENT);
- #endif
- /* pg_convert options */
- REGISTER_LONG_CONSTANT("PGSQL_CONV_IGNORE_DEFAULT", PGSQL_CONV_IGNORE_DEFAULT, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PGSQL_CONV_FORCE_NULL", PGSQL_CONV_FORCE_NULL, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PGSQL_CONV_IGNORE_NOT_NULL", PGSQL_CONV_IGNORE_NOT_NULL, CONST_CS | CONST_PERSISTENT);
- /* pg_insert/update/delete/select options */
- REGISTER_LONG_CONSTANT("PGSQL_DML_ESCAPE", PGSQL_DML_ESCAPE, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PGSQL_DML_NO_CONV", PGSQL_DML_NO_CONV, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PGSQL_DML_EXEC", PGSQL_DML_EXEC, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PGSQL_DML_ASYNC", PGSQL_DML_ASYNC, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PGSQL_DML_STRING", PGSQL_DML_STRING, CONST_CS | CONST_PERSISTENT);
- return SUCCESS;
- }
- PHP_MSHUTDOWN_FUNCTION(pgsql)
- {
- UNREGISTER_INI_ENTRIES();
- zend_hash_destroy(&PGG(connections));
- return SUCCESS;
- }
- PHP_RINIT_FUNCTION(pgsql)
- {
- PGG(default_link) = NULL;
- PGG(num_links) = PGG(num_persistent);
- zend_hash_init(&PGG(field_oids), 0, NULL, release_string, 0);
- zend_hash_init(&PGG(table_oids), 0, NULL, release_string, 0);
- return SUCCESS;
- }
- PHP_RSHUTDOWN_FUNCTION(pgsql)
- {
- if (PGG(default_link)) {
- zend_object_release(PGG(default_link));
- PGG(default_link) = NULL;
- }
- zend_hash_destroy(&PGG(field_oids));
- zend_hash_destroy(&PGG(table_oids));
- /* clean up persistent connection */
- zend_hash_apply(&EG(persistent_list), (apply_func_t) _rollback_transactions);
- return SUCCESS;
- }
- PHP_MINFO_FUNCTION(pgsql)
- {
- char buf[256];
- php_info_print_table_start();
- php_info_print_table_header(2, "PostgreSQL Support", "enabled");
- php_libpq_version(buf, sizeof(buf));
- php_info_print_table_row(2, "PostgreSQL (libpq) Version", buf);
- #ifdef HAVE_PGSQL_WITH_MULTIBYTE_SUPPORT
- php_info_print_table_row(2, "Multibyte character support", "enabled");
- #else
- php_info_print_table_row(2, "Multibyte character support", "disabled");
- #endif
- snprintf(buf, sizeof(buf), ZEND_LONG_FMT, PGG(num_persistent));
- php_info_print_table_row(2, "Active Persistent Links", buf);
- snprintf(buf, sizeof(buf), ZEND_LONG_FMT, PGG(num_links));
- php_info_print_table_row(2, "Active Links", buf);
- php_info_print_table_end();
- DISPLAY_INI_ENTRIES();
- }
- static void php_pgsql_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent)
- {
- char *connstring;
- size_t connstring_len;
- pgsql_link_handle *link;
- PGconn *pgsql;
- smart_str str = {0};
- zend_long connect_type = 0;
- PGresult *pg_result;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|l", &connstring, &connstring_len, &connect_type) == FAILURE) {
- RETURN_THROWS();
- }
- smart_str_appends(&str, "pgsql");
- smart_str_appendl(&str, connstring, connstring_len);
- smart_str_appendc(&str, '_');
- /* make sure that the PGSQL_CONNECT_FORCE_NEW bit is not part of the hash so that subsequent
- * connections can re-use this connection. See bug #39979. */
- smart_str_append_long(&str, connect_type & ~PGSQL_CONNECT_FORCE_NEW);
- smart_str_0(&str);
- if (persistent && PGG(allow_persistent)) {
- zend_resource *le;
- /* try to find if we already have this link in our persistent list */
- if ((le = zend_hash_find_ptr(&EG(persistent_list), str.s)) == NULL) { /* we don't */
- if (PGG(max_links) != -1 && PGG(num_links) >= PGG(max_links)) {
- php_error_docref(NULL, E_WARNING,
- "Cannot create new link. Too many open links (" ZEND_LONG_FMT ")", PGG(num_links));
- goto err;
- }
- if (PGG(max_persistent) != -1 && PGG(num_persistent) >= PGG(max_persistent)) {
- php_error_docref(NULL, E_WARNING,
- "Cannot create new link. Too many open persistent links (" ZEND_LONG_FMT ")", PGG(num_persistent));
- goto err;
- }
- /* create the link */
- pgsql = PQconnectdb(connstring);
- if (pgsql == NULL || PQstatus(pgsql) == CONNECTION_BAD) {
- PHP_PQ_ERROR("Unable to connect to PostgreSQL server: %s", pgsql)
- if (pgsql) {
- PQfinish(pgsql);
- }
- goto err;
- }
- /* hash it up */
- if (zend_register_persistent_resource(ZSTR_VAL(str.s), ZSTR_LEN(str.s), pgsql, le_plink) == NULL) {
- goto err;
- }
- PGG(num_links)++;
- PGG(num_persistent)++;
- } else { /* we do */
- if (le->type != le_plink) {
- goto err;
- }
- /* ensure that the link did not die */
- if (PGG(auto_reset_persistent) & 1) {
- /* need to send & get something from backend to
- make sure we catch CONNECTION_BAD every time */
- PGresult *pg_result;
- pg_result = PQexec(le->ptr, "select 1");
- PQclear(pg_result);
- }
- if (PQstatus(le->ptr) == CONNECTION_BAD) { /* the link died */
- if (le->ptr == NULL) {
- le->ptr = PQconnectdb(connstring);
- }
- else {
- PQreset(le->ptr);
- }
- if (le->ptr == NULL || PQstatus(le->ptr) == CONNECTION_BAD) {
- php_error_docref(NULL, E_WARNING,"PostgreSQL connection lost, unable to reconnect");
- zend_hash_del(&EG(persistent_list), str.s);
- goto err;
- }
- }
- pgsql = (PGconn *) le->ptr;
- /* consider to use php_version_compare() here */
- if (PQprotocolVersion(pgsql) >= 3 && zend_strtod(PQparameterStatus(pgsql, "server_version"), NULL) >= 7.2) {
- pg_result = PQexec(pgsql, "RESET ALL;");
- PQclear(pg_result);
- }
- }
- object_init_ex(return_value, pgsql_link_ce);
- link = Z_PGSQL_LINK_P(return_value);
- link->conn = pgsql;
- link->hash = zend_string_copy(str.s);
- link->notices = NULL;
- link->persistent = 1;
- } else { /* Non persistent connection */
- zval *index_ptr;
- /* first we check the hash for the hashed_details key. If it exists,
- * it should point us to the right offset where the actual pgsql link sits.
- * if it doesn't, open a new pgsql link, add it to the resource list,
- * and add a pointer to it with hashed_details as the key.
- */
- if (!(connect_type & PGSQL_CONNECT_FORCE_NEW)
- && (index_ptr = zend_hash_find(&PGG(connections), str.s)) != NULL) {
- php_pgsql_set_default_link(Z_OBJ_P(index_ptr));
- ZVAL_COPY(return_value, index_ptr);
- goto cleanup;
- }
- if (PGG(max_links) != -1 && PGG(num_links) >= PGG(max_links)) {
- php_error_docref(NULL, E_WARNING, "Cannot create new link. Too many open links (" ZEND_LONG_FMT ")", PGG(num_links));
- goto err;
- }
- /* Non-blocking connect */
- if (connect_type & PGSQL_CONNECT_ASYNC) {
- pgsql = PQconnectStart(connstring);
- if (pgsql==NULL || PQstatus(pgsql)==CONNECTION_BAD) {
- PHP_PQ_ERROR("Unable to connect to PostgreSQL server: %s", pgsql);
- if (pgsql) {
- PQfinish(pgsql);
- }
- goto err;
- }
- } else {
- pgsql = PQconnectdb(connstring);
- if (pgsql==NULL || PQstatus(pgsql)==CONNECTION_BAD) {
- PHP_PQ_ERROR("Unable to connect to PostgreSQL server: %s", pgsql);
- if (pgsql) {
- PQfinish(pgsql);
- }
- goto err;
- }
- }
- object_init_ex(return_value, pgsql_link_ce);
- link = Z_PGSQL_LINK_P(return_value);
- link->conn = pgsql;
- link->hash = zend_string_copy(str.s);
- link->notices = NULL;
- link->persistent = 0;
- /* add it to the hash */
- zend_hash_update(&PGG(connections), str.s, return_value);
- /* Keep track of link => hash mapping, so we can remove the hash entry from connections
- * when the connection is closed. This uses the address of the connection rather than the
- * zend_resource, because the resource destructor is passed a stack copy of the resource
- * structure. */
- PGG(num_links)++;
- }
- /* set notice processor */
- if (! PGG(ignore_notices) && Z_TYPE_P(return_value) == IS_OBJECT) {
- PQsetNoticeProcessor(pgsql, _php_pgsql_notice_handler, link);
- }
- php_pgsql_set_default_link(Z_OBJ_P(return_value));
- cleanup:
- smart_str_free(&str);
- return;
- err:
- smart_str_free(&str);
- RETURN_FALSE;
- }
- /* }}} */
- /* {{{ Open a PostgreSQL connection */
- PHP_FUNCTION(pg_connect)
- {
- php_pgsql_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU,0);
- }
- /* }}} */
- /* {{{ Poll the status of an in-progress async PostgreSQL connection attempt*/
- PHP_FUNCTION(pg_connect_poll)
- {
- zval *pgsql_link;
- pgsql_link_handle *pgsql_handle;
- PGconn *pgsql;
- int ret;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &pgsql_link, pgsql_link_ce) == FAILURE) {
- RETURN_THROWS();
- }
- pgsql_handle = Z_PGSQL_LINK_P(pgsql_link);
- CHECK_PGSQL_LINK(pgsql_handle);
- pgsql = pgsql_handle->conn;
- ret = PQconnectPoll(pgsql);
- RETURN_LONG(ret);
- }
- /* }}} */
- /* {{{ Open a persistent PostgreSQL connection */
- PHP_FUNCTION(pg_pconnect)
- {
- php_pgsql_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU,1);
- }
- /* }}} */
- /* {{{ Close a PostgreSQL connection */
- PHP_FUNCTION(pg_close)
- {
- zval *pgsql_link = NULL;
- pgsql_link_handle *link;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "|O!", &pgsql_link, pgsql_link_ce) == FAILURE) {
- RETURN_THROWS();
- }
- if (!pgsql_link) {
- link = FETCH_DEFAULT_LINK();
- CHECK_DEFAULT_LINK(link);
- zend_object_release(PGG(default_link));
- PGG(default_link) = NULL;
- RETURN_TRUE;
- }
- link = Z_PGSQL_LINK_P(pgsql_link);
- CHECK_PGSQL_LINK(link);
- if (link == FETCH_DEFAULT_LINK_NO_WARNING()) {
- GC_DELREF(PGG(default_link));
- PGG(default_link) = NULL;
- }
- pgsql_link_free(link);
- RETURN_TRUE;
- }
- /* }}} */
- #define PHP_PG_DBNAME 1
- #define PHP_PG_ERROR_MESSAGE 2
- #define PHP_PG_OPTIONS 3
- #define PHP_PG_PORT 4
- #define PHP_PG_TTY 5
- #define PHP_PG_HOST 6
- #define PHP_PG_VERSION 7
- /* php_pgsql_get_link_info */
- static void php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type)
- {
- pgsql_link_handle *link;
- zval *pgsql_link = NULL;
- PGconn *pgsql;
- char *result;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "|O!", &pgsql_link, pgsql_link_ce) == FAILURE) {
- RETURN_THROWS();
- }
- if (!pgsql_link) {
- link = FETCH_DEFAULT_LINK();
- CHECK_DEFAULT_LINK(link);
- } else {
- link = Z_PGSQL_LINK_P(pgsql_link);
- CHECK_PGSQL_LINK(link);
- }
- pgsql = link->conn;
- switch(entry_type) {
- case PHP_PG_DBNAME:
- result = PQdb(pgsql);
- break;
- case PHP_PG_ERROR_MESSAGE:
- RETURN_STR(_php_pgsql_trim_message(PQerrorMessage(pgsql)));
- case PHP_PG_OPTIONS:
- result = PQoptions(pgsql);
- break;
- case PHP_PG_PORT:
- result = PQport(pgsql);
- break;
- case PHP_PG_TTY:
- result = PQtty(pgsql);
- break;
- case PHP_PG_HOST:
- result = PQhost(pgsql);
- break;
- case PHP_PG_VERSION:
- array_init(return_value);
- char buf[16];
- php_libpq_version(buf, sizeof(buf));
- add_assoc_string(return_value, "client", buf);
- add_assoc_long(return_value, "protocol", PQprotocolVersion(pgsql));
- if (PQprotocolVersion(pgsql) >= 3) {
- /* 8.0 or grater supports protorol version 3 */
- char *tmp;
- add_assoc_string(return_value, "server", (char*)PQparameterStatus(pgsql, "server_version"));
- #define PHP_PQ_COPY_PARAM(_x) tmp = (char*)PQparameterStatus(pgsql, _x); \
- if(tmp) add_assoc_string(return_value, _x, tmp); \
- else add_assoc_null(return_value, _x);
- PHP_PQ_COPY_PARAM("server_encoding");
- PHP_PQ_COPY_PARAM("client_encoding");
- PHP_PQ_COPY_PARAM("is_superuser");
- PHP_PQ_COPY_PARAM("session_authorization");
- PHP_PQ_COPY_PARAM("DateStyle");
- PHP_PQ_COPY_PARAM("IntervalStyle");
- PHP_PQ_COPY_PARAM("TimeZone");
- PHP_PQ_COPY_PARAM("integer_datetimes");
- PHP_PQ_COPY_PARAM("standard_conforming_strings");
- PHP_PQ_COPY_PARAM("application_name");
- }
- return;
- EMPTY_SWITCH_DEFAULT_CASE()
- }
- if (result) {
- RETURN_STRING(result);
- } else {
- RETURN_EMPTY_STRING();
- }
- }
- /* Get the database name */
- PHP_FUNCTION(pg_dbname)
- {
- php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_DBNAME);
- }
- /* Get the error message string */
- PHP_FUNCTION(pg_last_error)
- {
- php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_ERROR_MESSAGE);
- }
- /* Get the options associated with the connection */
- PHP_FUNCTION(pg_options)
- {
- php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_OPTIONS);
- }
- /* Return the port number associated with the connection */
- PHP_FUNCTION(pg_port)
- {
- php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_PORT);
- }
- /* Return the tty name associated with the connection */
- PHP_FUNCTION(pg_tty)
- {
- php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_TTY);
- }
- /* Returns the host name associated with the connection */
- PHP_FUNCTION(pg_host)
- {
- php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_HOST);
- }
- /* Returns an array with client, protocol and server version (when available) */
- PHP_FUNCTION(pg_version)
- {
- php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_VERSION);
- }
- /* Returns the value of a server parameter */
- PHP_FUNCTION(pg_parameter_status)
- {
- zval *pgsql_link = NULL;
- pgsql_link_handle *link;
- PGconn *pgsql;
- char *param;
- size_t len;
- if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "Os", &pgsql_link, pgsql_link_ce, ¶m, &len) == FAILURE) {
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", ¶m, &len) == FAILURE) {
- RETURN_THROWS();
- }
- link = FETCH_DEFAULT_LINK();
- CHECK_DEFAULT_LINK(link);
- } else {
- link = Z_PGSQL_LINK_P(pgsql_link);
- CHECK_PGSQL_LINK(link);
- }
- pgsql = link->conn;
- param = (char*)PQparameterStatus(pgsql, param);
- if (param) {
- RETURN_STRING(param);
- } else {
- RETURN_FALSE;
- }
- }
- /* Ping database. If connection is bad, try to reconnect. */
- PHP_FUNCTION(pg_ping)
- {
- zval *pgsql_link = NULL;
- PGconn *pgsql;
- PGresult *res;
- pgsql_link_handle *link;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "|O!", &pgsql_link, pgsql_link_ce) == FAILURE) {
- RETURN_THROWS();
- }
- if (pgsql_link == NULL) {
- link = FETCH_DEFAULT_LINK();
- CHECK_DEFAULT_LINK(link);
- } else {
- link = Z_PGSQL_LINK_P(pgsql_link);
- CHECK_PGSQL_LINK(link);
- }
- pgsql = link->conn;
- /* ping connection */
- res = PQexec(pgsql, "SELECT 1;");
- PQclear(res);
- /* check status. */
- if (PQstatus(pgsql) == CONNECTION_OK)
- RETURN_TRUE;
- /* reset connection if it's broken */
- PQreset(pgsql);
- if (PQstatus(pgsql) == CONNECTION_OK) {
- RETURN_TRUE;
- }
- RETURN_FALSE;
- }
- /* Execute a query */
- PHP_FUNCTION(pg_query)
- {
- zval *pgsql_link = NULL;
- char *query;
- size_t query_len;
- int leftover = 0;
- pgsql_link_handle *link;
- PGconn *pgsql;
- PGresult *pgsql_result;
- ExecStatusType status;
- if (ZEND_NUM_ARGS() == 1) {
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &query, &query_len) == FAILURE) {
- RETURN_THROWS();
- }
- link = FETCH_DEFAULT_LINK();
- CHECK_DEFAULT_LINK(link);
- } else {
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "Os", &pgsql_link, pgsql_link_ce, &query, &query_len) == FAILURE) {
- RETURN_THROWS();
- }
- link = Z_PGSQL_LINK_P(pgsql_link);
- CHECK_PGSQL_LINK(link);
- }
- pgsql = link->conn;
- if (PQsetnonblocking(pgsql, 0)) {
- php_error_docref(NULL, E_NOTICE,"Cannot set connection to blocking mode");
- RETURN_FALSE;
- }
- while ((pgsql_result = PQgetResult(pgsql))) {
- PQclear(pgsql_result);
- leftover = 1;
- }
- if (leftover) {
- php_error_docref(NULL, E_NOTICE, "Found results on this connection. Use pg_get_result() to get these results first");
- }
- pgsql_result = PQexec(pgsql, query);
- if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
- PQclear(pgsql_result);
- PQreset(pgsql);
- pgsql_result = PQexec(pgsql, query);
- }
- if (pgsql_result) {
- status = PQresultStatus(pgsql_result);
- } else {
- status = (ExecStatusType) PQstatus(pgsql);
- }
- switch (status) {
- case PGRES_EMPTY_QUERY:
- case PGRES_BAD_RESPONSE:
- case PGRES_NONFATAL_ERROR:
- case PGRES_FATAL_ERROR:
- PHP_PQ_ERROR("Query failed: %s", pgsql);
- PQclear(pgsql_result);
- RETURN_FALSE;
- break;
- case PGRES_COMMAND_OK: /* successful command that did not return rows */
- default:
- if (pgsql_result) {
- object_init_ex(return_value, pgsql_result_ce);
- pgsql_result_handle *pg_result = Z_PGSQL_RESULT_P(return_value);
- pg_result->conn = pgsql;
- pg_result->result = pgsql_result;
- pg_result->row = 0;
- } else {
- PQclear(pgsql_result);
- RETURN_FALSE;
- }
- break;
- }
- }
- static void _php_pgsql_free_params(char **params, int num_params)
- {
- if (num_params > 0) {
- int i;
- for (i = 0; i < num_params; i++) {
- if (params[i]) {
- efree(params[i]);
- }
- }
- efree(params);
- }
- }
- /* Execute a query */
- PHP_FUNCTION(pg_query_params)
- {
- zval *pgsql_link = NULL;
- zval *pv_param_arr, *tmp;
- char *query;
- size_t query_len;
- int leftover = 0;
- int num_params = 0;
- char **params = NULL;
- pgsql_link_handle *link;
- PGconn *pgsql;
- PGresult *pgsql_result;
- ExecStatusType status;
- pgsql_result_handle *pg_result;
- if (ZEND_NUM_ARGS() == 2) {
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "sa", &query, &query_len, &pv_param_arr) == FAILURE) {
- RETURN_THROWS();
- }
- link = FETCH_DEFAULT_LINK();
- CHECK_DEFAULT_LINK(link);
- } else {
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "Osa", &pgsql_link, pgsql_link_ce, &query, &query_len, &pv_param_arr) == FAILURE) {
- RETURN_THROWS();
- }
- link = Z_PGSQL_LINK_P(pgsql_link);
- CHECK_PGSQL_LINK(link);
- }
- pgsql = link->conn;
- if (PQsetnonblocking(pgsql, 0)) {
- php_error_docref(NULL, E_NOTICE,"Cannot set connection to blocking mode");
- RETURN_FALSE;
- }
- while ((pgsql_result = PQgetResult(pgsql))) {
- PQclear(pgsql_result);
- leftover = 1;
- }
- if (leftover) {
- php_error_docref(NULL, E_NOTICE, "Found results on this connection. Use pg_get_result() to get these results first");
- }
- num_params = zend_hash_num_elements(Z_ARRVAL_P(pv_param_arr));
- if (num_params > 0) {
- int i = 0;
- params = (char **)safe_emalloc(sizeof(char *), num_params, 0);
- ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(pv_param_arr), tmp) {
- ZVAL_DEREF(tmp);
- if (Z_TYPE_P(tmp) == IS_NULL) {
- params[i] = NULL;
- } else {
- zend_string *param_str = zval_try_get_string(tmp);
- if (!param_str) {
- _php_pgsql_free_params(params, i);
- RETURN_THROWS();
- }
- params[i] = estrndup(ZSTR_VAL(param_str), ZSTR_LEN(param_str));
- zend_string_release(param_str);
- }
- i++;
- } ZEND_HASH_FOREACH_END();
- }
- pgsql_result = PQexecParams(pgsql, query, num_params,
- NULL, (const char * const *)params, NULL, NULL, 0);
- if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
- PQclear(pgsql_result);
- PQreset(pgsql);
- pgsql_result = PQexecParams(pgsql, query, num_params,
- NULL, (const char * const *)params, NULL, NULL, 0);
- }
- if (pgsql_result) {
- status = PQresultStatus(pgsql_result);
- } else {
- status = (ExecStatusType) PQstatus(pgsql);
- }
- _php_pgsql_free_params(params, num_params);
- switch (status) {
- case PGRES_EMPTY_QUERY:
- case PGRES_BAD_RESPONSE:
- case PGRES_NONFATAL_ERROR:
- case PGRES_FATAL_ERROR:
- PHP_PQ_ERROR("Query failed: %s", pgsql);
- PQclear(pgsql_result);
- RETURN_FALSE;
- break;
- case PGRES_COMMAND_OK: /* successful command that did not return rows */
- default:
- if (pgsql_result) {
- object_init_ex(return_value, pgsql_result_ce);
- pg_result = Z_PGSQL_RESULT_P(return_value);
- pg_result->conn = pgsql;
- pg_result->result = pgsql_result;
- pg_result->row = 0;
- } else {
- PQclear(pgsql_result);
- RETURN_FALSE;
- }
- break;
- }
- }
- /* Prepare a query for future execution */
- PHP_FUNCTION(pg_prepare)
- {
- zval *pgsql_link = NULL;
- char *query, *stmtname;
- size_t query_len, stmtname_len;
- int leftover = 0;
- PGconn *pgsql;
- pgsql_link_handle *link;
- PGresult *pgsql_result;
- ExecStatusType status;
- pgsql_result_handle *pg_result;
- if (ZEND_NUM_ARGS() == 2) {
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss", &stmtname, &stmtname_len, &query, &query_len) == FAILURE) {
- RETURN_THROWS();
- }
- link = FETCH_DEFAULT_LINK();
- CHECK_DEFAULT_LINK(link);
- } else {
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "Oss", &pgsql_link, pgsql_link_ce, &stmtname, &stmtname_len, &query, &query_len) == FAILURE) {
- RETURN_THROWS();
- }
- link = Z_PGSQL_LINK_P(pgsql_link);
- CHECK_PGSQL_LINK(link);
- }
- pgsql = link->conn;
- if (PQsetnonblocking(pgsql, 0)) {
- php_error_docref(NULL, E_NOTICE,"Cannot set connection to blocking mode");
- RETURN_FALSE;
- }
- while ((pgsql_result = PQgetResult(pgsql))) {
- PQclear(pgsql_result);
- leftover = 1;
- }
- if (leftover) {
- php_error_docref(NULL, E_NOTICE, "Found results on this connection. Use pg_get_result() to get these results first");
- }
- pgsql_result = PQprepare(pgsql, stmtname, query, 0, NULL);
- if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
- PQclear(pgsql_result);
- PQreset(pgsql);
- pgsql_result = PQprepare(pgsql, stmtname, query, 0, NULL);
- }
- if (pgsql_result) {
- status = PQresultStatus(pgsql_result);
- } else {
- status = (ExecStatusType) PQstatus(pgsql);
- }
- switch (status) {
- case PGRES_EMPTY_QUERY:
- case PGRES_BAD_RESPONSE:
- case PGRES_NONFATAL_ERROR:
- case PGRES_FATAL_ERROR:
- PHP_PQ_ERROR("Query failed: %s", pgsql);
- PQclear(pgsql_result);
- RETURN_FALSE;
- break;
- case PGRES_COMMAND_OK: /* successful command that did not return rows */
- default:
- if (pgsql_result) {
- object_init_ex(return_value, pgsql_result_ce);
- pg_result = Z_PGSQL_RESULT_P(return_value);
- pg_result->conn = pgsql;
- pg_result->result = pgsql_result;
- pg_result->row = 0;
- } else {
- PQclear(pgsql_result);
- RETURN_FALSE;
- }
- break;
- }
- }
- /* Execute a prepared query */
- PHP_FUNCTION(pg_execute)
- {
- zval *pgsql_link = NULL;
- zval *pv_param_arr, *tmp;
- char *stmtname;
- size_t stmtname_len;
- int leftover = 0;
- int num_params = 0;
- char **params = NULL;
- PGconn *pgsql;
- pgsql_link_handle *link;
- PGresult *pgsql_result;
- ExecStatusType status;
- pgsql_result_handle *pg_result;
- if (ZEND_NUM_ARGS() == 2) {
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "sa", &stmtname, &stmtname_len, &pv_param_arr)==FAILURE) {
- RETURN_THROWS();
- }
- link = FETCH_DEFAULT_LINK();
- CHECK_DEFAULT_LINK(link);
- } else {
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "Osa", &pgsql_link, pgsql_link_ce, &stmtname, &stmtname_len, &pv_param_arr) == FAILURE) {
- RETURN_THROWS();
- }
- link = Z_PGSQL_LINK_P(pgsql_link);
- CHECK_PGSQL_LINK(link);
- }
- pgsql = link->conn;
- if (PQsetnonblocking(pgsql, 0)) {
- php_error_docref(NULL, E_NOTICE,"Cannot set connection to blocking mode");
- RETURN_FALSE;
- }
- while ((pgsql_result = PQgetResult(pgsql))) {
- PQclear(pgsql_result);
- leftover = 1;
- }
- if (leftover) {
- php_error_docref(NULL, E_NOTICE, "Found results on this connection. Use pg_get_result() to get these results first");
- }
- num_params = zend_hash_num_elements(Z_ARRVAL_P(pv_param_arr));
- if (num_params > 0) {
- int i = 0;
- params = (char **)safe_emalloc(sizeof(char *), num_params, 0);
- ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(pv_param_arr), tmp) {
- if (Z_TYPE_P(tmp) == IS_NULL) {
- params[i] = NULL;
- } else {
- zend_string *tmp_str;
- zend_string *str = zval_get_tmp_string(tmp, &tmp_str);
- params[i] = estrndup(ZSTR_VAL(str), ZSTR_LEN(str));
- zend_tmp_string_release(tmp_str);
- }
- i++;
- } ZEND_HASH_FOREACH_END();
- }
- pgsql_result = PQexecPrepared(pgsql, stmtname, num_params,
- (const char * const *)params, NULL, NULL, 0);
- if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
- PQclear(pgsql_result);
- PQreset(pgsql);
- pgsql_result = PQexecPrepared(pgsql, stmtname, num_params,
- (const char * const *)params, NULL, NULL, 0);
- }
- if (pgsql_result) {
- status = PQresultStatus(pgsql_result);
- } else {
- status = (ExecStatusType) PQstatus(pgsql);
- }
- _php_pgsql_free_params(params, num_params);
- switch (status) {
- case PGRES_EMPTY_QUERY:
- case PGRES_BAD_RESPONSE:
- case PGRES_NONFATAL_ERROR:
- case PGRES_FATAL_ERROR:
- PHP_PQ_ERROR("Query failed: %s", pgsql);
- PQclear(pgsql_result);
- RETURN_FALSE;
- break;
- case PGRES_COMMAND_OK: /* successful command that did not return rows */
- default:
- if (pgsql_result) {
- object_init_ex(return_value, pgsql_result_ce);
- pg_result = Z_PGSQL_RESULT_P(return_value);
- pg_result->conn = pgsql;
- pg_result->result = pgsql_result;
- pg_result->row = 0;
- } else {
- PQclear(pgsql_result);
- RETURN_FALSE;
- }
- break;
- }
- }
- #define PHP_PG_NUM_ROWS 1
- #define PHP_PG_NUM_FIELDS 2
- #define PHP_PG_CMD_TUPLES 3
- /* php_pgsql_get_result_info */
- static void php_pgsql_get_result_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type)
- {
- zval *result;
- PGresult *pgsql_result;
- pgsql_result_handle *pg_result;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &result, pgsql_result_ce) == FAILURE) {
- RETURN_THROWS();
- }
- pg_result = Z_PGSQL_RESULT_P(result);
- CHECK_PGSQL_RESULT(pg_result);
- pgsql_result = pg_result->result;
- switch (entry_type) {
- case PHP_PG_NUM_ROWS:
- RETVAL_LONG(PQntuples(pgsql_result));
- break;
- case PHP_PG_NUM_FIELDS:
- RETVAL_LONG(PQnfields(pgsql_result));
- break;
- case PHP_PG_CMD_TUPLES:
- RETVAL_LONG(atoi(PQcmdTuples(pgsql_result)));
- break;
- EMPTY_SWITCH_DEFAULT_CASE()
- }
- }
- /* Return the number of rows in the result */
- PHP_FUNCTION(pg_num_rows)
- {
- php_pgsql_get_result_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_NUM_ROWS);
- }
- /* Return the number of fields in the result */
- PHP_FUNCTION(pg_num_fields)
- {
- php_pgsql_get_result_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_NUM_FIELDS);
- }
- /* Returns the number of affected tuples */
- PHP_FUNCTION(pg_affected_rows)
- {
- php_pgsql_get_result_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_CMD_TUPLES);
- }
- /* Returns the last notice set by the backend */
- PHP_FUNCTION(pg_last_notice)
- {
- zval *pgsql_link = NULL;
- zval *notice;
- HashTable *notices;
- pgsql_link_handle *link;
- zend_long option = PGSQL_NOTICE_LAST;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|l", &pgsql_link, pgsql_link_ce, &option) == FAILURE) {
- RETURN_THROWS();
- }
- link = Z_PGSQL_LINK_P(pgsql_link);
- CHECK_PGSQL_LINK(link);
- notices = link->notices;
- switch (option) {
- case PGSQL_NOTICE_LAST:
- if (notices) {
- zend_hash_internal_pointer_end(notices);
- if ((notice = zend_hash_get_current_data(notices)) == NULL) {
- RETURN_EMPTY_STRING();
- }
- RETURN_COPY(notice);
- } else {
- RETURN_EMPTY_STRING();
- }
- break;
- case PGSQL_NOTICE_ALL:
- if (notices) {
- RETURN_ARR(zend_array_dup(notices));
- } else {
- array_init(return_value);
- return;
- }
- break;
- case PGSQL_NOTICE_CLEAR:
- if (notices) {
- zend_hash_clean(notices);
- }
- RETURN_TRUE;
- break;
- default:
- zend_argument_value_error(2, "must be one of PGSQL_NOTICE_LAST, PGSQL_NOTICE_ALL, or PGSQL_NOTICE_CLEAR");
- RETURN_THROWS();
- }
- RETURN_FALSE;
- }
- static inline bool is_valid_oid_string(zend_string *oid, Oid *return_oid)
- {
- char *end_ptr;
- *return_oid = (Oid) strtoul(ZSTR_VAL(oid), &end_ptr, 10);
- return ZSTR_VAL(oid) + ZSTR_LEN(oid) == end_ptr;
- }
- static zend_string *get_field_name(PGconn *pgsql, Oid oid)
- {
- zend_string *ret = zend_hash_index_find_ptr(&PGG(field_oids), oid);
- if (ret) {
- zend_string_addref(ret);
- return ret;
- }
- PGresult *result = PQexec(pgsql, "select oid,typname from pg_type");
- if (!result || PQresultStatus(result) != PGRES_TUPLES_OK) {
- if (result) {
- PQclear(result);
- }
- return ZSTR_EMPTY_ALLOC();
- }
- int num_rows = PQntuples(result);
- int oid_offset = PQfnumber(result,"oid");
- int name_offset = PQfnumber(result,"typname");
- for (int i = 0; i < num_rows; i++) {
- char *tmp_oid_str = PQgetvalue(result, i, oid_offset);
- if (!tmp_oid_str) {
- continue;
- }
- char *tmp_name = PQgetvalue(result, i, name_offset);
- if (!tmp_name) {
- continue;
- }
- char *end_ptr;
- Oid tmp_oid = strtoul(tmp_oid_str, &end_ptr, 10);
- zend_string *name = zend_string_init(tmp_name, strlen(tmp_name), 0);
- zend_hash_index_update_ptr(&PGG(field_oids), tmp_oid, name);
- if (!ret && tmp_oid == oid) {
- ret = zend_string_copy(name);
- }
- }
- PQclear(result);
- return ret;
- }
- /* Returns the name of the table field belongs to, or table's oid if oid_only is true */
- PHP_FUNCTION(pg_field_table)
- {
- zval *result;
- pgsql_result_handle *pg_result;
- zend_long fnum = -1;
- bool return_oid = 0;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ol|b", &result, pgsql_result_ce, &fnum, &return_oid) == FAILURE) {
- RETURN_THROWS();
- }
- pg_result = Z_PGSQL_RESULT_P(result);
- CHECK_PGSQL_RESULT(pg_result);
- if (fnum < 0) {
- zend_argument_value_error(2, "must be greater than or equal to 0");
- RETURN_THROWS();
- }
- if (fnum >= PQnfields(pg_result->result)) {
- zend_argument_value_error(2, "must be less than the number of fields for this result set");
- RETURN_THROWS();
- }
- Oid oid = PQftable(pg_result->result, (int)fnum);
- if (InvalidOid == oid) {
- RETURN_FALSE;
- }
- if (return_oid) {
- PGSQL_RETURN_OID(oid);
- }
- zend_string *field_table = zend_hash_index_find_ptr(&PGG(table_oids), oid);
- if (field_table) {
- RETURN_STR_COPY(field_table);
- }
- /* Not found, lookup by querying PostgreSQL system tables */
- smart_str querystr = {0};
- smart_str_appends(&querystr, "select relname from pg_class where oid=");
- smart_str_append_unsigned(&querystr, oid);
- smart_str_0(&querystr);
- PGresult *tmp_res = PQexec(pg_result->conn, ZSTR_VAL(querystr.s));
- smart_str_free(&querystr);
- if (!tmp_res || PQresultStatus(tmp_res) != PGRES_TUPLES_OK) {
- if (tmp_res) {
- PQclear(tmp_res);
- }
- RETURN_FALSE;
- }
- char *table_name = PQgetvalue(tmp_res, 0, 0);
- if (!table_name) {
- PQclear(tmp_res);
- RETURN_FALSE;
- }
- field_table = zend_string_init(table_name, strlen(table_name), 0);
- zend_hash_index_update_ptr(&PGG(table_oids), oid, field_table);
- PQclear(tmp_res);
- RETURN_STR_COPY(field_table);
- }
- /* }}} */
- #define PHP_PG_FIELD_NAME 1
- #define PHP_PG_FIELD_SIZE 2
- #define PHP_PG_FIELD_TYPE 3
- #define PHP_PG_FIELD_TYPE_OID 4
- /* {{{ php_pgsql_get_field_info */
- static void php_pgsql_get_field_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type)
- {
- zval *result;
- zend_long field;
- PGresult *pgsql_result;
- pgsql_result_handle *pg_result;
- Oid oid;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ol", &result, pgsql_result_ce, &field) == FAILURE) {
- RETURN_THROWS();
- }
- pg_result = Z_PGSQL_RESULT_P(result);
- CHECK_PGSQL_RESULT(pg_result);
- if (field < 0) {
- zend_argument_value_error(2, "must be greater than or equal to 0");
- RETURN_THROWS();
- }
- pgsql_result = pg_result->result;
- if (field >= PQnfields(pgsql_result)) {
- zend_argument_value_error(2, "must be less than the number of fields for this result set");
- RETURN_THROWS();
- }
- switch (entry_type) {
- case PHP_PG_FIELD_NAME:
- RETURN_STRING(PQfname(pgsql_result, (int)field));
- break;
- case PHP_PG_FIELD_SIZE:
- RETURN_LONG(PQfsize(pgsql_result, (int)field));
- break;
- case PHP_PG_FIELD_TYPE:
- RETURN_STR(get_field_name(pg_result->conn, PQftype(pgsql_result, (int)field)));
- break;
- case PHP_PG_FIELD_TYPE_OID:
- oid = PQftype(pgsql_result, (int)field);
- PGSQL_RETURN_OID(oid);
- break;
- EMPTY_SWITCH_DEFAULT_CASE()
- }
- }
- /* }}} */
- /* {{{ Returns the name of the field */
- PHP_FUNCTION(pg_field_name)
- {
- php_pgsql_get_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_FIELD_NAME);
- }
- /* }}} */
- /* {{{ Returns the internal size of the field */
- PHP_FUNCTION(pg_field_size)
- {
- php_pgsql_get_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_FIELD_SIZE);
- }
- /* }}} */
- /* {{{ Returns the type name for the given field */
- PHP_FUNCTION(pg_field_type)
- {
- php_pgsql_get_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_FIELD_TYPE);
- }
- /* }}} */
- /* {{{ Returns the type oid for the given field */
- PHP_FUNCTION(pg_field_type_oid)
- {
- php_pgsql_get_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_FIELD_TYPE_OID);
- }
- /* }}} */
- /* {{{ Returns the field number of the named field */
- PHP_FUNCTION(pg_field_num)
- {
- zval *result;
- char *field;
- size_t field_len;
- PGresult *pgsql_result;
- pgsql_result_handle *pg_result;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "Os", &result, pgsql_result_ce, &field, &field_len) == FAILURE) {
- RETURN_THROWS();
- }
- pg_result = Z_PGSQL_RESULT_P(result);
- CHECK_PGSQL_RESULT(pg_result);
- pgsql_result = pg_result->result;
- RETURN_LONG(PQfnumber(pgsql_result, field));
- }
- /* }}} */
- static zend_long field_arg_to_offset(
- PGresult *result, zend_string *field_name, zend_long field_offset, int arg_num) {
- if (field_name) {
- field_offset = PQfnumber(result, ZSTR_VAL(field_name));
- if (field_offset < 0) {
- /* Avoid displaying the argument name, as the signature is overloaded and the name
- * might not line up. */
- zend_value_error("Argument #%d must be a field name from this result set", arg_num);
- return -1;
- }
- } else {
- if (field_offset < 0) {
- zend_value_error("Argument #%d must be greater than or equal to 0", arg_num);
- return -1;
- }
- if (field_offset >= PQnfields(result)) {
- zend_value_error("Argument #%d must be less than the number of fields for this result set", arg_num);
- return -1;
- }
- }
- return field_offset;
- }
- /* {{{ Returns values from a result identifier */
- PHP_FUNCTION(pg_fetch_result)
- {
- zval *result;
- zend_string *field_name;
- zend_long row, field_offset;
- PGresult *pgsql_result;
- pgsql_result_handle *pg_result;
- int pgsql_row;
- if (ZEND_NUM_ARGS() == 2) {
- ZEND_PARSE_PARAMETERS_START(2, 2)
- Z_PARAM_OBJECT_OF_CLASS(result, pgsql_result_ce)
- Z_PARAM_STR_OR_LONG(field_name, field_offset)
- ZEND_PARSE_PARAMETERS_END();
- } else {
- ZEND_PARSE_PARAMETERS_START(3, 3)
- Z_PARAM_OBJECT_OF_CLASS(result, pgsql_result_ce)
- Z_PARAM_LONG(row)
- Z_PARAM_STR_OR_LONG(field_name, field_offset)
- ZEND_PARSE_PARAMETERS_END();
- }
- pg_result = Z_PGSQL_RESULT_P(result);
- CHECK_PGSQL_RESULT(pg_result);
- pgsql_result = pg_result->result;
- if (ZEND_NUM_ARGS() == 2) {
- if (pg_result->row < 0) {
- pg_result->row = 0;
- }
- pgsql_row = pg_result->row;
- if (pgsql_row >= PQntuples(pgsql_result)) {
- RETURN_FALSE;
- }
- pg_result->row++;
- } else {
- if (row < 0) {
- zend_argument_value_error(2, "must be greater than or equal to 0");
- RETURN_THROWS();
- }
- if (row >= PQntuples(pgsql_result)) {
- php_error_docref(NULL, E_WARNING, "Unable to jump to row " ZEND_LONG_FMT " on PostgreSQL result index " ZEND_LONG_FMT,
- row, Z_LVAL_P(result));
- RETURN_FALSE;
- }
- pgsql_row = (int)row;
- }
- field_offset = field_arg_to_offset(pgsql_result, field_name, field_offset, ZEND_NUM_ARGS());
- if (field_offset < 0) {
- RETURN_THROWS();
- }
- if (PQgetisnull(pgsql_result, pgsql_row, field_offset)) {
- RETVAL_NULL();
- } else {
- RETVAL_STRINGL(PQgetvalue(pgsql_result, pgsql_row, field_offset),
- PQgetlength(pgsql_result, pgsql_row, field_offset));
- }
- }
- /* }}} */
- /* {{{ void php_pgsql_fetch_hash */
- static void php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, zend_long result_type, int into_object)
- {
- zval *result;
- PGresult *pgsql_result;
- pgsql_result_handle *pg_result;
- int i, num_fields, pgsql_row;
- zend_long row;
- bool row_is_null = 1;
- char *field_name;
- zval *ctor_params = NULL;
- zend_class_entry *ce = NULL;
- if (into_object) {
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|l!Ca", &result, pgsql_result_ce, &row, &row_is_null, &ce, &ctor_params) == FAILURE) {
- RETURN_THROWS();
- }
- if (!ce) {
- ce = zend_standard_class_def;
- }
- result_type = PGSQL_ASSOC;
- } else {
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|l!l", &result, pgsql_result_ce, &row, &row_is_null, &result_type) == FAILURE) {
- RETURN_THROWS();
- }
- }
- if (!row_is_null && row < 0) {
- zend_argument_value_error(2, "must be greater than or equal to 0");
- RETURN_THROWS();
- }
- if (!(result_type & PGSQL_BOTH)) {
- zend_argument_value_error(3, "must be one of PGSQL_ASSOC, PGSQL_NUM, or PGSQL_BOTH");
- RETURN_THROWS();
- }
- pg_result = Z_PGSQL_RESULT_P(result);
- CHECK_PGSQL_RESULT(pg_result);
- pgsql_result = pg_result->result;
- if (!row_is_null) {
- if (row >= PQntuples(pgsql_result)) {
- php_error_docref(NULL, E_WARNING, "Unable to jump to row " ZEND_LONG_FMT " on PostgreSQL result index " ZEND_LONG_FMT,
- row, Z_LVAL_P(result));
- RETURN_FALSE;
- }
- pgsql_row = (int)row;
- pg_result->row = pgsql_row;
- } else {
- /* If 2nd param is NULL, use internal row counter to access next row */
- pgsql_row = pg_result->row;
- if (pgsql_row < 0 || pgsql_row >= PQntuples(pgsql_result)) {
- RETURN_FALSE;
- }
- pg_result->row++;
- }
- array_init(return_value);
- for (i = 0, num_fields = PQnfields(pgsql_result); i < num_fields; i++) {
- if (PQgetisnull(pgsql_result, pgsql_row, i)) {
- if (result_type & PGSQL_NUM) {
- add_index_null(return_value, i);
- }
- if (result_type & PGSQL_ASSOC) {
- field_name = PQfname(pgsql_result, i);
- add_assoc_null(return_value, field_name);
- }
- } else {
- char *element = PQgetvalue(pgsql_result, pgsql_row, i);
- if (element) {
- const size_t element_len = strlen(element);
- if (result_type & PGSQL_NUM) {
- add_index_stringl(return_value, i, element, element_len);
- }
- if (result_type & PGSQL_ASSOC) {
- field_name = PQfname(pgsql_result, i);
- add_assoc_stringl(return_value, field_name, element, element_len);
- }
- }
- }
- }
- if (into_object) {
- zval dataset;
- zend_fcall_info fci;
- zend_fcall_info_cache fcc;
- zval retval;
- ZVAL_COPY_VALUE(&dataset, return_value);
- object_init_ex(return_value, ce);
- if (!ce->default_properties_count && !ce->__set) {
- Z_OBJ_P(return_value)->properties = Z_ARR(dataset);
- } else {
- zend_merge_properties(return_value, Z_ARRVAL(dataset));
- zval_ptr_dtor(&dataset);
- }
- if (ce->constructor) {
- fci.size = sizeof(fci);
- ZVAL_UNDEF(&fci.function_name);
- fci.object = Z_OBJ_P(return_value);
- fci.retval = &retval;
- fci.params = NULL;
- fci.param_count = 0;
- fci.named_params = NULL;
- if (ctor_params) {
- if (zend_fcall_info_args(&fci, ctor_params) == FAILURE) {
- ZEND_UNREACHABLE();
- }
- }
- fcc.function_handler = ce->constructor;
- fcc.called_scope = Z_OBJCE_P(return_value);
- fcc.object = Z_OBJ_P(return_value);
- if (zend_call_function(&fci, &fcc) == FAILURE) {
- zend_throw_exception_ex(zend_ce_exception, 0, "Could not execute %s::%s()", ZSTR_VAL(ce->name), ZSTR_VAL(ce->constructor->common.function_name));
- } else {
- zval_ptr_dtor(&retval);
- }
- if (fci.params) {
- efree(fci.params);
- }
- } else if (ctor_params && zend_hash_num_elements(Z_ARRVAL_P(ctor_params)) > 0) {
- zend_argument_error(zend_ce_exception, 3,
- "must be empty when the specified class (%s) does not have a constructor",
- ZSTR_VAL(ce->name)
- );
- }
- }
- }
- /* }}} */
- /* {{{ Get a row as an enumerated array */
- PHP_FUNCTION(pg_fetch_row)
- {
- php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, PGSQL_NUM, 0);
- }
- /* }}} */
- /* {{{ Fetch a row as an assoc array */
- PHP_FUNCTION(pg_fetch_assoc)
- {
- /* pg_fetch_assoc() is added from PHP 4.3.0. It should raise error, when
- there is 3rd parameter */
- if (ZEND_NUM_ARGS() > 2)
- WRONG_PARAM_COUNT;
- php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, PGSQL_ASSOC, 0);
- }
- /* }}} */
- /* {{{ Fetch a row as an array */
- PHP_FUNCTION(pg_fetch_array)
- {
- php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, PGSQL_BOTH, 0);
- }
- /* }}} */
- /* {{{ Fetch a row as an object */
- PHP_FUNCTION(pg_fetch_object)
- {
- /* pg_fetch_object() allowed result_type used to be. 3rd parameter
- must be allowed for compatibility */
- php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, PGSQL_ASSOC, 1);
- }
- /* }}} */
- /* {{{ Fetch all rows into array */
- PHP_FUNCTION(pg_fetch_all)
- {
- zval *result;
- zend_long result_type = PGSQL_ASSOC;
- PGresult *pgsql_result;
- pgsql_result_handle *pg_result;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|l", &result, pgsql_result_ce, &result_type) == FAILURE) {
- RETURN_THROWS();
- }
- if (!(result_type & PGSQL_BOTH)) {
- zend_argument_value_error(2, "must be one of PGSQL_ASSOC, PGSQL_NUM, or PGSQL_BOTH");
- RETURN_THROWS();
- }
- pg_result = Z_PGSQL_RESULT_P(result);
- CHECK_PGSQL_RESULT(pg_result);
- pgsql_result = pg_result->result;
- array_init(return_value);
- php_pgsql_result2array(pgsql_result, return_value, result_type);
- }
- /* }}} */
- /* {{{ Fetch all rows into array */
- PHP_FUNCTION(pg_fetch_all_columns)
- {
- zval *result;
- PGresult *pgsql_result;
- pgsql_result_handle *pg_result;
- zend_long colno=0;
- int pg_numrows, pg_row;
- size_t num_fields;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|l", &result, pgsql_result_ce, &colno) == FAILURE) {
- RETURN_THROWS();
- }
- pg_result = Z_PGSQL_RESULT_P(result);
- CHECK_PGSQL_RESULT(pg_result);
- if (colno < 0) {
- zend_argument_value_error(2, "must be greater than or equal to 0");
- RETURN_THROWS();
- }
- pgsql_result = pg_result->result;
- num_fields = PQnfields(pgsql_result);
- if (colno >= (zend_long)num_fields) {
- zend_argument_value_error(2, "must be less than the number of fields for this result set");
- RETURN_THROWS();
- }
- array_init(return_value);
- if ((pg_numrows = PQntuples(pgsql_result)) <= 0) {
- return;
- }
- for (pg_row = 0; pg_row < pg_numrows; pg_row++) {
- if (PQgetisnull(pgsql_result, pg_row, (int)colno)) {
- add_next_index_null(return_value);
- } else {
- add_next_index_string(return_value, PQgetvalue(pgsql_result, pg_row, (int)colno));
- }
- }
- }
- /* }}} */
- /* {{{ Set internal row offset */
- PHP_FUNCTION(pg_result_seek)
- {
- zval *result;
- zend_long row;
- pgsql_result_handle *pg_result;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ol", &result, pgsql_result_ce, &row) == FAILURE) {
- RETURN_THROWS();
- }
- pg_result = Z_PGSQL_RESULT_P(result);
- CHECK_PGSQL_RESULT(pg_result);
- if (row < 0 || row >= PQntuples(pg_result->result)) {
- RETURN_FALSE;
- }
- /* seek to offset */
- pg_result->row = (int)row;
- RETURN_TRUE;
- }
- /* }}} */
- #define PHP_PG_DATA_LENGTH 1
- #define PHP_PG_DATA_ISNULL 2
- /* {{{ php_pgsql_data_info */
- static void php_pgsql_data_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type)
- {
- zval *result;
- zend_string *field_name;
- zend_long row, field_offset;
- PGresult *pgsql_result;
- pgsql_result_handle *pg_result;
- int pgsql_row;
- if (ZEND_NUM_ARGS() == 2) {
- ZEND_PARSE_PARAMETERS_START(2, 2)
- Z_PARAM_OBJECT_OF_CLASS(result, pgsql_result_ce)
- Z_PARAM_STR_OR_LONG(field_name, field_offset)
- ZEND_PARSE_PARAMETERS_END();
- } else {
- ZEND_PARSE_PARAMETERS_START(3, 3)
- Z_PARAM_OBJECT_OF_CLASS(result, pgsql_result_ce)
- Z_PARAM_LONG(row)
- Z_PARAM_STR_OR_LONG(field_name, field_offset)
- ZEND_PARSE_PARAMETERS_END();
- }
- pg_result = Z_PGSQL_RESULT_P(result);
- CHECK_PGSQL_RESULT(pg_result);
- pgsql_result = pg_result->result;
- if (ZEND_NUM_ARGS() == 2) {
- if (pg_result->row < 0) {
- pg_result->row = 0;
- }
- pgsql_row = pg_result->row;
- if (pgsql_row < 0 || pgsql_row >= PQntuples(pgsql_result)) {
- RETURN_FALSE;
- }
- } else {
- if (row < 0) {
- zend_argument_value_error(2, "must be greater than or equal to 0");
- RETURN_THROWS();
- }
- if (row >= PQntuples(pgsql_result)) {
- php_error_docref(NULL, E_WARNING, "Unable to jump to row " ZEND_LONG_FMT " on PostgreSQL result index " ZEND_LONG_FMT,
- row, Z_LVAL_P(result));
- RETURN_FALSE;
- }
- pgsql_row = (int)row;
- }
- field_offset = field_arg_to_offset(pgsql_result, field_name, field_offset, ZEND_NUM_ARGS());
- if (field_offset < 0) {
- RETURN_THROWS();
- }
- switch (entry_type) {
- case PHP_PG_DATA_LENGTH:
- RETVAL_LONG(PQgetlength(pgsql_result, pgsql_row, field_offset));
- break;
- case PHP_PG_DATA_ISNULL:
- RETVAL_LONG(PQgetisnull(pgsql_result, pgsql_row, field_offset));
- break;
- EMPTY_SWITCH_DEFAULT_CASE()
- }
- }
- /* }}} */
- /* {{{ Returns the printed length */
- PHP_FUNCTION(pg_field_prtlen)
- {
- php_pgsql_data_info(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_PG_DATA_LENGTH);
- }
- /* }}} */
- /* {{{ Test if a field is NULL */
- PHP_FUNCTION(pg_field_is_null)
- {
- php_pgsql_data_info(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_PG_DATA_ISNULL);
- }
- /* }}} */
- /* {{{ Free result memory */
- PHP_FUNCTION(pg_free_result)
- {
- zval *result;
- pgsql_result_handle *pg_result;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &result, pgsql_result_ce) == FAILURE) {
- RETURN_THROWS();
- }
- pg_result = Z_PGSQL_RESULT_P(result);
- CHECK_PGSQL_RESULT(pg_result);
- pgsql_result_free(pg_result);
- RETURN_TRUE;
- }
- /* }}} */
- /* {{{ Returns the last object identifier */
- PHP_FUNCTION(pg_last_oid)
- {
- zval *result;
- PGresult *pgsql_result;
- pgsql_result_handle *pg_result;
- Oid oid;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &result, pgsql_result_ce) == FAILURE) {
- RETURN_THROWS();
- }
- pg_result = Z_PGSQL_RESULT_P(result);
- CHECK_PGSQL_RESULT(pg_result);
- pgsql_result = pg_result->result;
- oid = PQoidValue(pgsql_result);
- if (oid == InvalidOid) {
- RETURN_FALSE;
- }
- PGSQL_RETURN_OID(oid);
- }
- /* }}} */
- /* {{{ Enable tracing a PostgreSQL connection */
- PHP_FUNCTION(pg_trace)
- {
- char *z_filename, *mode = "w";
- size_t z_filename_len, mode_len;
- zval *pgsql_link = NULL;
- PGconn *pgsql;
- FILE *fp = NULL;
- php_stream *stream;
- pgsql_link_handle *link;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "p|sO!", &z_filename, &z_filename_len, &mode, &mode_len, &pgsql_link, pgsql_link_ce) == FAILURE) {
- RETURN_THROWS();
- }
- if (!pgsql_link) {
- link = FETCH_DEFAULT_LINK();
- CHECK_DEFAULT_LINK(link);
- } else {
- link = Z_PGSQL_LINK_P(pgsql_link);
- CHECK_PGSQL_LINK(link);
- }
- pgsql = link->conn;
- stream = php_stream_open_wrapper(z_filename, mode, REPORT_ERRORS, NULL);
- if (!stream) {
- RETURN_FALSE;
- }
- if (FAILURE == php_stream_cast(stream, PHP_STREAM_AS_STDIO, (void**)&fp, REPORT_ERRORS)) {
- php_stream_close(stream);
- RETURN_FALSE;
- }
- php_stream_auto_cleanup(stream);
- PQtrace(pgsql, fp);
- RETURN_TRUE;
- }
- /* }}} */
- /* {{{ Disable tracing of a PostgreSQL connection */
- PHP_FUNCTION(pg_untrace)
- {
- zval *pgsql_link = NULL;
- PGconn *pgsql;
- pgsql_link_handle *link;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "|r!", &pgsql_link) == FAILURE) {
- RETURN_THROWS();
- }
- if (pgsql_link == NULL) {
- link = FETCH_DEFAULT_LINK();
- CHECK_DEFAULT_LINK(link);
- } else {
- link = Z_PGSQL_LINK_P(pgsql_link);
- CHECK_PGSQL_LINK(link);
- }
- pgsql = link->conn;
- PQuntrace(pgsql);
- RETURN_TRUE;
- }
- /* }}} */
- /* {{{ Create a large object */
- PHP_FUNCTION(pg_lo_create)
- {
- zval *pgsql_link = NULL, *oid = NULL;
- PGconn *pgsql;
- Oid pgsql_oid, wanted_oid = InvalidOid;
- pgsql_link_handle *link;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "|zz", &pgsql_link, &oid) == FAILURE) {
- RETURN_THROWS();
- }
- /* Overloaded method uses default link if arg 1 is not an object, set oid pointer */
- if ((ZEND_NUM_ARGS() == 1) && (Z_TYPE_P(pgsql_link) != IS_OBJECT)) {
- oid = pgsql_link;
- pgsql_link = NULL;
- }
- if (pgsql_link == NULL) {
- link = FETCH_DEFAULT_LINK();
- CHECK_DEFAULT_LINK(link);
- } else if ((Z_TYPE_P(pgsql_link) == IS_OBJECT && instanceof_function(Z_OBJCE_P(pgsql_link), pgsql_link_ce))) {
- link = Z_PGSQL_LINK_P(pgsql_link);
- CHECK_PGSQL_LINK(link);
- } else {
- zend_argument_type_error(1, "must be of type PgSql\\Connection when the connection is provided");
- RETURN_THROWS();
- }
- pgsql = link->conn;
- if (oid) {
- switch (Z_TYPE_P(oid)) {
- case IS_STRING:
- {
- if (!is_valid_oid_string(Z_STR_P(oid), &wanted_oid)) {
- /* wrong integer format */
- zend_value_error("Invalid OID value passed");
- RETURN_THROWS();
- }
- }
- break;
- case IS_LONG:
- if (Z_LVAL_P(oid) < (zend_long)InvalidOid) {
- zend_value_error("Invalid OID value passed");
- RETURN_THROWS();
- }
- wanted_oid = (Oid)Z_LVAL_P(oid);
- break;
- default:
- zend_type_error("OID value must be of type string|int, %s given", zend_zval_type_name(oid));
- RETURN_THROWS();
- }
- if ((pgsql_oid = lo_create(pgsql, wanted_oid)) == InvalidOid) {
- php_error_docref(NULL, E_WARNING, "Unable to create PostgreSQL large object");
- RETURN_FALSE;
- }
- PGSQL_RETURN_OID(pgsql_oid);
- }
- if ((pgsql_oid = lo_creat(pgsql, INV_READ|INV_WRITE)) == InvalidOid) {
- php_error_docref(NULL, E_WARNING, "Unable to create PostgreSQL large object");
- RETURN_FALSE;
- }
- PGSQL_RETURN_OID(pgsql_oid);
- }
- /* }}} */
- /* {{{ Delete a large object */
- PHP_FUNCTION(pg_lo_unlink)
- {
- zval *pgsql_link = NULL;
- zend_long oid_long;
- zend_string *oid_string;
- PGconn *pgsql;
- Oid oid;
- pgsql_link_handle *link;
- /* accept string type since Oid type is unsigned int */
- if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "OS", &pgsql_link, pgsql_link_ce, &oid_string) == SUCCESS) {
- if (!is_valid_oid_string(oid_string, &oid)) {
- /* wrong integer format */
- zend_value_error("Invalid OID value passed");
- RETURN_THROWS();
- }
- link = Z_PGSQL_LINK_P(pgsql_link);
- CHECK_PGSQL_LINK(link);
- }
- else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(),
- "Ol", &pgsql_link, pgsql_link_ce, &oid_long) == SUCCESS) {
- if (oid_long <= (zend_long)InvalidOid) {
- zend_value_error("Invalid OID value passed");
- RETURN_THROWS();
- }
- oid = (Oid)oid_long;
- link = Z_PGSQL_LINK_P(pgsql_link);
- CHECK_PGSQL_LINK(link);
- }
- else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "S", &oid_string) == SUCCESS) {
- if (!is_valid_oid_string(oid_string, &oid)) {
- /* wrong integer format */
- zend_value_error("Invalid OID value passed");
- RETURN_THROWS();
- }
- link = FETCH_DEFAULT_LINK();
- CHECK_DEFAULT_LINK(link);
- }
- else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(),
- "l", &oid_long) == SUCCESS) {
- if (oid_long <= (zend_long)InvalidOid) {
- zend_value_error("Invalid OID value passed");
- RETURN_THROWS();
- }
- oid = (Oid)oid_long;
- link = FETCH_DEFAULT_LINK();
- CHECK_DEFAULT_LINK(link);
- }
- else {
- zend_argument_count_error("Requires 1 or 2 arguments, %d given", ZEND_NUM_ARGS());
- RETURN_THROWS();
- }
- pgsql = link->conn;
- if (lo_unlink(pgsql, oid) == -1) {
- php_error_docref(NULL, E_WARNING, "Unable to delete PostgreSQL large object %u", oid);
- RETURN_FALSE;
- }
- RETURN_TRUE;
- }
- /* }}} */
- /* {{{ Open a large object and return fd */
- PHP_FUNCTION(pg_lo_open)
- {
- zval *pgsql_link = NULL;
- zend_long oid_long;
- zend_string *oid_string;
- zend_string *mode;
- PGconn *pgsql;
- Oid oid;
- int pgsql_mode=0, pgsql_lofd;
- bool create = false;
- pgLofp *pgsql_lofp;
- pgsql_link_handle *link;
- /* accept string type since Oid is unsigned int */
- if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(),
- "OSS", &pgsql_link, pgsql_link_ce, &oid_string, &mode) == SUCCESS) {
- if (!is_valid_oid_string(oid_string, &oid)) {
- /* wrong integer format */
- zend_value_error("Invalid OID value passed");
- RETURN_THROWS();
- }
- link = Z_PGSQL_LINK_P(pgsql_link);
- CHECK_PGSQL_LINK(link);
- }
- else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(),
- "Ols", &pgsql_link, pgsql_link_ce, &oid_long, &mode) == SUCCESS) {
- if (oid_long <= (zend_long)InvalidOid) {
- zend_value_error("Invalid OID value passed");
- RETURN_THROWS();
- }
- oid = (Oid)oid_long;
- link = Z_PGSQL_LINK_P(pgsql_link);
- CHECK_PGSQL_LINK(link);
- }
- else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(),
- "SS", &oid_string, &mode) == SUCCESS) {
- if (!is_valid_oid_string(oid_string, &oid)) {
- /* wrong integer format */
- zend_value_error("Invalid OID value passed");
- RETURN_THROWS();
- }
- link = FETCH_DEFAULT_LINK();
- CHECK_DEFAULT_LINK(link);
- }
- else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(),
- "lS", &oid_long, &mode) == SUCCESS) {
- if (oid_long <= (zend_long)InvalidOid) {
- zend_value_error("Invalid OID value passed");
- RETURN_THROWS();
- }
- oid = (Oid)oid_long;
- link = FETCH_DEFAULT_LINK();
- CHECK_DEFAULT_LINK(link);
- }
- else {
- zend_argument_count_error("Requires 1 or 2 arguments, %d given", ZEND_NUM_ARGS());
- RETURN_THROWS();
- }
- pgsql = link->conn;
- /* r/w/+ is little bit more PHP-like than INV_READ/INV_WRITE and a lot of
- faster to type. Unfortunately, doesn't behave the same way as fopen()...
- (Jouni)
- */
- if (zend_string_equals_literal(mode, "r")) {
- pgsql_mode |= INV_READ;
- } else if (zend_string_equals_literal(mode, "w")) {
- pgsql_mode |= INV_WRITE;
- create = true;
- } else if (zend_string_equals_literal(mode, "r+")) {
- pgsql_mode |= INV_READ;
- pgsql_mode |= INV_WRITE;
- } else if (zend_string_equals_literal(mode, "w+")) {
- pgsql_mode |= INV_READ;
- pgsql_mode |= INV_WRITE;
- create = true;
- } else {
- zend_value_error("Mode must be one of 'r', 'r+', 'w', or 'w+'");
- RETURN_THROWS();
- }
- if ((pgsql_lofd = lo_open(pgsql, oid, pgsql_mode)) == -1) {
- if (create) {
- if ((oid = lo_creat(pgsql, INV_READ|INV_WRITE)) == 0) {
- php_error_docref(NULL, E_WARNING, "Unable to create PostgreSQL large object");
- RETURN_FALSE;
- } else {
- if ((pgsql_lofd = lo_open(pgsql, oid, pgsql_mode)) == -1) {
- if (lo_unlink(pgsql, oid) == -1) {
- php_error_docref(NULL, E_WARNING, "Something is really messed up! Your database is badly corrupted in a way NOT related to PHP");
- } else {
- php_error_docref(NULL, E_WARNING, "Unable to open PostgreSQL large object");
- }
- RETURN_FALSE;
- }
- }
- } else {
- php_error_docref(NULL, E_WARNING, "Unable to open PostgreSQL large object");
- RETURN_FALSE;
- }
- }
- object_init_ex(return_value, pgsql_lob_ce);
- pgsql_lofp = Z_PGSQL_LOB_P(return_value);
- pgsql_lofp->conn = pgsql;
- pgsql_lofp->lofd = pgsql_lofd;
- }
- /* }}} */
- /* {{{ Close a large object */
- PHP_FUNCTION(pg_lo_close)
- {
- zval *pgsql_lofp;
- pgLofp *pgsql;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &pgsql_lofp, pgsql_lob_ce) == FAILURE) {
- RETURN_THROWS();
- }
- pgsql = Z_PGSQL_LOB_P(pgsql_lofp);
- CHECK_PGSQL_LOB(pgsql);
- if (lo_close((PGconn *)pgsql->conn, pgsql->lofd) < 0) {
- php_error_docref(NULL, E_WARNING, "Unable to close PostgreSQL large object descriptor %d", pgsql->lofd);
- RETVAL_FALSE;
- } else {
- RETVAL_TRUE;
- }
- return;
- }
- /* }}} */
- #define PGSQL_LO_READ_BUF_SIZE 8192
- /* {{{ Read a large object */
- PHP_FUNCTION(pg_lo_read)
- {
- zval *pgsql_id;
- zend_long buffer_length = PGSQL_LO_READ_BUF_SIZE;
- int nbytes;
- zend_string *buf;
- pgLofp *pgsql;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|l", &pgsql_id, pgsql_lob_ce, &buffer_length) == FAILURE) {
- RETURN_THROWS();
- }
- pgsql = Z_PGSQL_LOB_P(pgsql_id);
- CHECK_PGSQL_LOB(pgsql);
- if (buffer_length < 0) {
- zend_argument_value_error(2, "must be greater or equal than 0");
- RETURN_THROWS();
- }
- buf = zend_string_alloc(buffer_length, 0);
- if ((nbytes = lo_read((PGconn *)pgsql->conn, pgsql->lofd, ZSTR_VAL(buf), ZSTR_LEN(buf)))<0) {
- zend_string_efree(buf);
- RETURN_FALSE;
- }
- /* TODO Use truncate API? */
- ZSTR_LEN(buf) = nbytes;
- ZSTR_VAL(buf)[ZSTR_LEN(buf)] = '\0';
- RETURN_NEW_STR(buf);
- }
- /* }}} */
- /* {{{ Write a large object */
- PHP_FUNCTION(pg_lo_write)
- {
- zval *pgsql_id;
- zend_string *str;
- zend_long z_len;
- bool z_len_is_null = 1;
- size_t nbytes;
- size_t len;
- pgLofp *pgsql;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "OS|l!", &pgsql_id, pgsql_lob_ce, &str, &z_len, &z_len_is_null) == FAILURE) {
- RETURN_THROWS();
- }
- if (!z_len_is_null) {
- if (z_len < 0) {
- zend_argument_value_error(3, "must be greater than or equal to 0");
- RETURN_THROWS();
- }
- if (z_len > (zend_long)ZSTR_LEN(str)) {
- zend_argument_value_error(3, "must be less than or equal to the length of argument #2 ($buf)");
- RETURN_THROWS();
- }
- len = z_len;
- }
- else {
- len = ZSTR_LEN(str);
- }
- pgsql = Z_PGSQL_LOB_P(pgsql_id);
- CHECK_PGSQL_LOB(pgsql);
- if ((nbytes = lo_write((PGconn *)pgsql->conn, pgsql->lofd, ZSTR_VAL(str), len)) == (size_t)-1) {
- RETURN_FALSE;
- }
- RETURN_LONG(nbytes);
- }
- /* }}} */
- /* {{{ Read a large object and send straight to browser */
- PHP_FUNCTION(pg_lo_read_all)
- {
- zval *pgsql_id;
- int tbytes;
- volatile int nbytes;
- char buf[PGSQL_LO_READ_BUF_SIZE];
- pgLofp *pgsql;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &pgsql_id, pgsql_lob_ce) == FAILURE) {
- RETURN_THROWS();
- }
- pgsql = Z_PGSQL_LOB_P(pgsql_id);
- CHECK_PGSQL_LOB(pgsql);
- tbytes = 0;
- while ((nbytes = lo_read((PGconn *)pgsql->conn, pgsql->lofd, buf, PGSQL_LO_READ_BUF_SIZE))>0) {
- PHPWRITE(buf, nbytes);
- tbytes += nbytes;
- }
- RETURN_LONG(tbytes);
- }
- /* }}} */
- /* {{{ Import large object direct from filesystem */
- PHP_FUNCTION(pg_lo_import)
- {
- zval *pgsql_link = NULL, *oid = NULL;
- zend_string *file_in;
- PGconn *pgsql;
- Oid returned_oid;
- pgsql_link_handle *link;
- if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(),
- "OP|z", &pgsql_link, pgsql_link_ce, &file_in, &oid) == SUCCESS) {
- link = Z_PGSQL_LINK_P(pgsql_link);
- CHECK_PGSQL_LINK(link);
- }
- else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(),
- "P|z", &file_in, &oid) == SUCCESS) {
- link = FETCH_DEFAULT_LINK();
- CHECK_DEFAULT_LINK(link);
- }
- else {
- WRONG_PARAM_COUNT;
- }
- if (php_check_open_basedir(ZSTR_VAL(file_in))) {
- RETURN_FALSE;
- }
- pgsql = link->conn;
- if (oid) {
- Oid wanted_oid;
- switch (Z_TYPE_P(oid)) {
- case IS_STRING:
- {
- if (!is_valid_oid_string(Z_STR_P(oid), &wanted_oid)) {
- /* wrong integer format */
- zend_value_error("Invalid OID value passed");
- RETURN_THROWS();
- }
- }
- break;
- case IS_LONG:
- if (Z_LVAL_P(oid) < (zend_long)InvalidOid) {
- zend_value_error("Invalid OID value passed");
- RETURN_THROWS();
- }
- wanted_oid = (Oid)Z_LVAL_P(oid);
- break;
- default:
- zend_type_error("OID value must be of type string|int, %s given", zend_zval_type_name(oid));
- RETURN_THROWS();
- }
- returned_oid = lo_import_with_oid(pgsql, ZSTR_VAL(file_in), wanted_oid);
- if (returned_oid == InvalidOid) {
- RETURN_FALSE;
- }
- PGSQL_RETURN_OID(returned_oid);
- }
- returned_oid = lo_import(pgsql, ZSTR_VAL(file_in));
- if (returned_oid == InvalidOid) {
- RETURN_FALSE;
- }
- PGSQL_RETURN_OID(returned_oid);
- }
- /* }}} */
- /* {{{ Export large object direct to filesystem */
- PHP_FUNCTION(pg_lo_export)
- {
- zval *pgsql_link = NULL;
- zend_string *oid_string;
- zend_string *file_out;
- zend_long oid_long;
- Oid oid;
- PGconn *pgsql;
- pgsql_link_handle *link;
- /* allow string to handle large OID value correctly */
- if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(),
- "rlP", &pgsql_link, pgsql_link_ce, &oid_long, &file_out) == SUCCESS) {
- if (oid_long <= (zend_long)InvalidOid) {
- zend_value_error("Invalid OID value passed");
- RETURN_THROWS();
- }
- oid = (Oid)oid_long;
- link = Z_PGSQL_LINK_P(pgsql_link);
- CHECK_PGSQL_LINK(link);
- }
- else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(),
- "OSP", &pgsql_link, pgsql_link_ce, &oid_string, &file_out) == SUCCESS) {
- if (!is_valid_oid_string(oid_string, &oid)) {
- /* wrong integer format */
- zend_value_error("Invalid OID value passed");
- RETURN_THROWS();
- }
- link = Z_PGSQL_LINK_P(pgsql_link);
- CHECK_PGSQL_LINK(link);
- }
- else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(),
- "lP", &oid_long, &file_out) == SUCCESS) {
- if (oid_long <= (zend_long)InvalidOid) {
- zend_value_error("Invalid OID value passed");
- RETURN_THROWS();
- }
- oid = (Oid)oid_long;
- link = FETCH_DEFAULT_LINK();
- CHECK_DEFAULT_LINK(link);
- }
- else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(),
- "SP", &oid_string, &file_out) == SUCCESS) {
- if (!is_valid_oid_string(oid_string, &oid)) {
- /* wrong integer format */
- zend_value_error("Invalid OID value passed");
- RETURN_THROWS();
- }
- link = FETCH_DEFAULT_LINK();
- CHECK_DEFAULT_LINK(link);
- }
- else {
- zend_argument_count_error("Requires 2 or 3 arguments, %d given", ZEND_NUM_ARGS());
- RETURN_THROWS();
- }
- if (php_check_open_basedir(ZSTR_VAL(file_out))) {
- RETURN_FALSE;
- }
- pgsql = link->conn;
- if (lo_export(pgsql, oid, ZSTR_VAL(file_out)) == -1) {
- RETURN_FALSE;
- }
- RETURN_TRUE;
- }
- /* }}} */
- /* {{{ Seeks position of large object */
- PHP_FUNCTION(pg_lo_seek)
- {
- zval *pgsql_id = NULL;
- zend_long result, offset = 0, whence = SEEK_CUR;
- pgLofp *pgsql;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ol|l", &pgsql_id, pgsql_lob_ce, &offset, &whence) == FAILURE) {
- RETURN_THROWS();
- }
- if (whence != SEEK_SET && whence != SEEK_CUR && whence != SEEK_END) {
- zend_argument_value_error(3, "must be one of PGSQL_SEEK_SET, PGSQL_SEEK_CUR, or PGSQL_SEEK_END");
- RETURN_THROWS();
- }
- pgsql = Z_PGSQL_LOB_P(pgsql_id);
- CHECK_PGSQL_LOB(pgsql);
- #ifdef HAVE_PG_LO64
- if (PQserverVersion((PGconn *)pgsql->conn) >= 90300) {
- result = lo_lseek64((PGconn *)pgsql->conn, pgsql->lofd, offset, (int)whence);
- } else {
- result = lo_lseek((PGconn *)pgsql->conn, pgsql->lofd, (int)offset, (int)whence);
- }
- #else
- result = lo_lseek((PGconn *)pgsql->conn, pgsql->lofd, offset, whence);
- #endif
- if (result > -1) {
- RETURN_TRUE;
- } else {
- RETURN_FALSE;
- }
- }
- /* }}} */
- /* {{{ Returns current position of large object */
- PHP_FUNCTION(pg_lo_tell)
- {
- zval *pgsql_id = NULL;
- zend_long offset = 0;
- pgLofp *pgsql;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &pgsql_id, pgsql_lob_ce) == FAILURE) {
- RETURN_THROWS();
- }
- pgsql = Z_PGSQL_LOB_P(pgsql_id);
- CHECK_PGSQL_LOB(pgsql);
- #ifdef VE_PG_LO64
- if (PQserverVersion((PGconn *)pgsql->conn) >= 90300) {
- offset = lo_tell64((PGconn *)pgsql->conn, pgsql->lofd);
- } else {
- offset = lo_tell((PGconn *)pgsql->conn, pgsql->lofd);
- }
- #else
- offset = lo_tell((PGconn *)pgsql->conn, pgsql->lofd);
- #endif
- RETURN_LONG(offset);
- }
- /* }}} */
- /* {{{ Truncate large object to size */
- PHP_FUNCTION(pg_lo_truncate)
- {
- zval *pgsql_id = NULL;
- size_t size;
- pgLofp *pgsql;
- int result;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ol", &pgsql_id, pgsql_lob_ce, &size) == FAILURE) {
- RETURN_THROWS();
- }
- pgsql = Z_PGSQL_LOB_P(pgsql_id);
- CHECK_PGSQL_LOB(pgsql);
- #ifdef VE_PG_LO64
- if (PQserverVersion((PGconn *)pgsql->conn) >= 90300) {
- result = lo_truncate64((PGconn *)pgsql->conn, pgsql->lofd, size);
- } else {
- result = lo_truncate((PGconn *)pgsql->conn, pgsql->lofd, size);
- }
- #else
- result = lo_truncate((PGconn *)pgsql->conn, pgsql->lofd, size);
- #endif
- if (!result) {
- RETURN_TRUE;
- } else {
- RETURN_FALSE;
- }
- }
- /* }}} */
- /* {{{ Set error verbosity */
- PHP_FUNCTION(pg_set_error_verbosity)
- {
- zval *pgsql_link = NULL;
- zend_long verbosity;
- PGconn *pgsql;
- pgsql_link_handle *link;
- if (ZEND_NUM_ARGS() == 1) {
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &verbosity) == FAILURE) {
- RETURN_THROWS();
- }
- link = FETCH_DEFAULT_LINK();
- CHECK_DEFAULT_LINK(link);
- } else {
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ol", &pgsql_link, pgsql_link_ce, &verbosity) == FAILURE) {
- RETURN_THROWS();
- }
- link = Z_PGSQL_LINK_P(pgsql_link);
- CHECK_PGSQL_LINK(link);
- }
- pgsql = link->conn;
- if (verbosity & (PQERRORS_TERSE|PQERRORS_DEFAULT|PQERRORS_VERBOSE)) {
- RETURN_LONG(PQsetErrorVerbosity(pgsql, verbosity));
- } else {
- RETURN_FALSE;
- }
- }
- /* }}} */
- /* {{{ Set client encoding */
- PHP_FUNCTION(pg_set_client_encoding)
- {
- char *encoding;
- size_t encoding_len;
- zval *pgsql_link = NULL;
- PGconn *pgsql;
- pgsql_link_handle *link;
- if (ZEND_NUM_ARGS() == 1) {
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &encoding, &encoding_len) == FAILURE) {
- RETURN_THROWS();
- }
- link = FETCH_DEFAULT_LINK();
- CHECK_DEFAULT_LINK(link);
- } else {
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "Os", &pgsql_link, pgsql_link_ce, &encoding, &encoding_len) == FAILURE) {
- RETURN_THROWS();
- }
- link = Z_PGSQL_LINK_P(pgsql_link);
- CHECK_PGSQL_LINK(link);
- }
- pgsql = link->conn;
- RETURN_LONG(PQsetClientEncoding(pgsql, encoding));
- }
- /* }}} */
- /* {{{ Get the current client encoding */
- PHP_FUNCTION(pg_client_encoding)
- {
- zval *pgsql_link = NULL;
- PGconn *pgsql;
- pgsql_link_handle *link;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "|O!", &pgsql_link, pgsql_link_ce) == FAILURE) {
- RETURN_THROWS();
- }
- if (pgsql_link == NULL) {
- link = FETCH_DEFAULT_LINK();
- CHECK_DEFAULT_LINK(link);
- } else {
- link = Z_PGSQL_LINK_P(pgsql_link);
- CHECK_PGSQL_LINK(link);
- }
- pgsql = link->conn;
- /* Just do the same as found in PostgreSQL sources... */
- RETURN_STRING((char *) pg_encoding_to_char(PQclientEncoding(pgsql)));
- }
- /* }}} */
- /* {{{ Sync with backend. Completes the Copy command */
- PHP_FUNCTION(pg_end_copy)
- {
- zval *pgsql_link = NULL;
- PGconn *pgsql;
- int result = 0;
- pgsql_link_handle *link;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "|O!", &pgsql_link, pgsql_link_ce) == FAILURE) {
- RETURN_THROWS();
- }
- if (pgsql_link == NULL) {
- link = FETCH_DEFAULT_LINK();
- CHECK_DEFAULT_LINK(link);
- } else {
- link = Z_PGSQL_LINK_P(pgsql_link);
- CHECK_PGSQL_LINK(link);
- }
- pgsql = link->conn;
- result = PQendcopy(pgsql);
- if (result!=0) {
- PHP_PQ_ERROR("Query failed: %s", pgsql);
- RETURN_FALSE;
- }
- RETURN_TRUE;
- }
- /* }}} */
- /* {{{ Send null-terminated string to backend server*/
- PHP_FUNCTION(pg_put_line)
- {
- char *query;
- size_t query_len;
- zval *pgsql_link = NULL;
- PGconn *pgsql;
- pgsql_link_handle *link;
- int result = 0;
- if (ZEND_NUM_ARGS() == 1) {
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &query, &query_len) == FAILURE) {
- RETURN_THROWS();
- }
- link = FETCH_DEFAULT_LINK();
- CHECK_DEFAULT_LINK(link);
- } else {
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "Os", &pgsql_link, pgsql_link_ce, &query, &query_len) == FAILURE) {
- RETURN_THROWS();
- }
- link = Z_PGSQL_LINK_P(pgsql_link);
- CHECK_PGSQL_LINK(link);
- }
- pgsql = link->conn;
- result = PQputline(pgsql, query);
- if (result==EOF) {
- PHP_PQ_ERROR("Query failed: %s", pgsql);
- RETURN_FALSE;
- }
- RETURN_TRUE;
- }
- /* }}} */
- /* {{{ Copy table to array */
- PHP_FUNCTION(pg_copy_to)
- {
- zval *pgsql_link;
- pgsql_link_handle *link;
- zend_string *table_name;
- zend_string *pg_delimiter = NULL;
- char *pg_null_as = NULL;
- size_t pg_null_as_len = 0;
- bool free_pg_null = false;
- char *query;
- PGconn *pgsql;
- PGresult *pgsql_result;
- ExecStatusType status;
- char *csv = (char *)NULL;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "OP|Ss", &pgsql_link, pgsql_link_ce,
- &table_name, &pg_delimiter, &pg_null_as, &pg_null_as_len) == FAILURE
- ) {
- RETURN_THROWS();
- }
- link = Z_PGSQL_LINK_P(pgsql_link);
- CHECK_PGSQL_LINK(link);
- pgsql = link->conn;
- if (!pg_delimiter) {
- pg_delimiter = ZSTR_CHAR('\t');
- } else if (ZSTR_LEN(pg_delimiter) != 1) {
- zend_argument_value_error(3, "must be one character");
- RETURN_THROWS();
- }
- if (!pg_null_as) {
- pg_null_as = estrdup("\\\\N");
- free_pg_null = true;
- }
- spprintf(&query, 0, "COPY %s TO STDOUT DELIMITER E'%c' NULL AS E'%s'", ZSTR_VAL(table_name), *ZSTR_VAL(pg_delimiter), pg_null_as);
- while ((pgsql_result = PQgetResult(pgsql))) {
- PQclear(pgsql_result);
- }
- pgsql_result = PQexec(pgsql, query);
- if (free_pg_null) {
- efree(pg_null_as);
- }
- efree(query);
- if (pgsql_result) {
- status = PQresultStatus(pgsql_result);
- } else {
- status = (ExecStatusType) PQstatus(pgsql);
- }
- switch (status) {
- case PGRES_COPY_OUT:
- if (pgsql_result) {
- int copydone = 0;
- PQclear(pgsql_result);
- array_init(return_value);
- while (!copydone)
- {
- int ret = PQgetCopyData(pgsql, &csv, 0);
- switch (ret) {
- case -1:
- copydone = 1;
- break;
- case 0:
- case -2:
- PHP_PQ_ERROR("getline failed: %s", pgsql);
- RETURN_FALSE;
- break;
- default:
- add_next_index_string(return_value, csv);
- PQfreemem(csv);
- break;
- }
- }
- while ((pgsql_result = PQgetResult(pgsql))) {
- PQclear(pgsql_result);
- }
- } else {
- PQclear(pgsql_result);
- RETURN_FALSE;
- }
- break;
- default:
- PQclear(pgsql_result);
- PHP_PQ_ERROR("Copy command failed: %s", pgsql);
- RETURN_FALSE;
- break;
- }
- }
- /* }}} */
- /* {{{ Copy table from array */
- PHP_FUNCTION(pg_copy_from)
- {
- zval *pgsql_link = NULL, *pg_rows;
- pgsql_link_handle *link;
- zval *value;
- zend_string *table_name;
- zend_string *pg_delimiter = NULL;
- char *pg_null_as = NULL;
- size_t pg_null_as_len;
- bool pg_null_as_free = false;
- char *query;
- PGconn *pgsql;
- PGresult *pgsql_result;
- ExecStatusType status;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "OPa|Ss", &pgsql_link, pgsql_link_ce,
- &table_name, &pg_rows, &pg_delimiter, &pg_null_as, &pg_null_as_len) == FAILURE
- ) {
- RETURN_THROWS();
- }
- link = Z_PGSQL_LINK_P(pgsql_link);
- CHECK_PGSQL_LINK(link);
- pgsql = link->conn;
- if (!pg_delimiter) {
- pg_delimiter = ZSTR_CHAR('\t');
- } else if (ZSTR_LEN(pg_delimiter) != 1) {
- zend_argument_value_error(4, "must be one character");
- RETURN_THROWS();
- }
- if (!pg_null_as) {
- pg_null_as = estrdup("\\\\N");
- pg_null_as_free = true;
- }
- spprintf(&query, 0, "COPY %s FROM STDIN DELIMITER E'%c' NULL AS E'%s'", ZSTR_VAL(table_name), *ZSTR_VAL(pg_delimiter), pg_null_as);
- while ((pgsql_result = PQgetResult(pgsql))) {
- PQclear(pgsql_result);
- }
- pgsql_result = PQexec(pgsql, query);
- if (pg_null_as_free) {
- efree(pg_null_as);
- }
- efree(query);
- if (pgsql_result) {
- status = PQresultStatus(pgsql_result);
- } else {
- status = (ExecStatusType) PQstatus(pgsql);
- }
- switch (status) {
- case PGRES_COPY_IN:
- if (pgsql_result) {
- int command_failed = 0;
- PQclear(pgsql_result);
- ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(pg_rows), value) {
- zend_string *tmp = zval_try_get_string(value);
- if (UNEXPECTED(!tmp)) {
- return;
- }
- query = (char *)emalloc(ZSTR_LEN(tmp) + 2);
- strlcpy(query, ZSTR_VAL(tmp), ZSTR_LEN(tmp) + 2);
- if (ZSTR_LEN(tmp) > 0 && *(query + ZSTR_LEN(tmp) - 1) != '\n') {
- strlcat(query, "\n", ZSTR_LEN(tmp) + 2);
- }
- if (PQputCopyData(pgsql, query, (int)strlen(query)) != 1) {
- efree(query);
- zend_string_release(tmp);
- PHP_PQ_ERROR("copy failed: %s", pgsql);
- RETURN_FALSE;
- }
- efree(query);
- zend_string_release(tmp);
- } ZEND_HASH_FOREACH_END();
- if (PQputCopyEnd(pgsql, NULL) != 1) {
- PHP_PQ_ERROR("putcopyend failed: %s", pgsql);
- RETURN_FALSE;
- }
- while ((pgsql_result = PQgetResult(pgsql))) {
- if (PGRES_COMMAND_OK != PQresultStatus(pgsql_result)) {
- PHP_PQ_ERROR("Copy command failed: %s", pgsql);
- command_failed = 1;
- }
- PQclear(pgsql_result);
- }
- if (command_failed) {
- RETURN_FALSE;
- }
- } else {
- PQclear(pgsql_result);
- RETURN_FALSE;
- }
- RETURN_TRUE;
- break;
- default:
- PQclear(pgsql_result);
- PHP_PQ_ERROR("Copy command failed: %s", pgsql);
- RETURN_FALSE;
- break;
- }
- }
- /* }}} */
- /* {{{ Escape string for text/char type */
- PHP_FUNCTION(pg_escape_string)
- {
- zend_string *from = NULL, *to = NULL;
- zval *pgsql_link;
- pgsql_link_handle *link;
- PGconn *pgsql;
- switch (ZEND_NUM_ARGS()) {
- case 1:
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &from) == FAILURE) {
- RETURN_THROWS();
- }
- link = FETCH_DEFAULT_LINK();
- break;
- default:
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "OS", &pgsql_link, pgsql_link_ce, &from) == FAILURE) {
- RETURN_THROWS();
- }
- link = Z_PGSQL_LINK_P(pgsql_link);
- CHECK_PGSQL_LINK(link);
- break;
- }
- to = zend_string_safe_alloc(ZSTR_LEN(from), 2, 0, 0);
- if (link) {
- pgsql = link->conn;
- ZSTR_LEN(to) = PQescapeStringConn(pgsql, ZSTR_VAL(to), ZSTR_VAL(from), ZSTR_LEN(from), NULL);
- } else
- {
- ZSTR_LEN(to) = PQescapeString(ZSTR_VAL(to), ZSTR_VAL(from), ZSTR_LEN(from));
- }
- to = zend_string_truncate(to, ZSTR_LEN(to), 0);
- RETURN_NEW_STR(to);
- }
- /* }}} */
- /* {{{ Escape binary for bytea type */
- PHP_FUNCTION(pg_escape_bytea)
- {
- zend_string *from;
- char *to = NULL;
- size_t to_len;
- PGconn *pgsql;
- zval *pgsql_link;
- pgsql_link_handle *link;
- switch (ZEND_NUM_ARGS()) {
- case 1:
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &from) == FAILURE) {
- RETURN_THROWS();
- }
- link = FETCH_DEFAULT_LINK();
- break;
- default:
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "OS", &pgsql_link, pgsql_link_ce, &from) == FAILURE) {
- RETURN_THROWS();
- }
- link = Z_PGSQL_LINK_P(pgsql_link);
- CHECK_PGSQL_LINK(link);
- break;
- }
- if (link) {
- pgsql = link->conn;
- to = (char *)PQescapeByteaConn(pgsql, (unsigned char *)ZSTR_VAL(from), ZSTR_LEN(from), &to_len);
- } else {
- to = (char *)PQescapeBytea((unsigned char *)ZSTR_VAL(from), ZSTR_LEN(from), &to_len);
- }
- RETVAL_STRINGL(to, to_len-1); /* to_len includes additional '\0' */
- PQfreemem(to);
- }
- /* }}} */
- /* {{{ Unescape binary for bytea type */
- PHP_FUNCTION(pg_unescape_bytea)
- {
- char *from, *tmp;
- size_t to_len;
- size_t from_len;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &from, &from_len) == FAILURE) {
- RETURN_THROWS();
- }
- tmp = (char *)PQunescapeBytea((unsigned char*)from, &to_len);
- if (!tmp) {
- zend_error(E_ERROR, "Out of memory");
- return;
- }
- RETVAL_STRINGL(tmp, to_len);
- PQfreemem(tmp);
- }
- /* }}} */
- static void php_pgsql_escape_internal(INTERNAL_FUNCTION_PARAMETERS, int escape_literal) /* {{{ */ {
- zend_string *from = NULL;
- zval *pgsql_link = NULL;
- PGconn *pgsql;
- char *tmp;
- pgsql_link_handle *link;
- switch (ZEND_NUM_ARGS()) {
- case 1:
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &from) == FAILURE) {
- RETURN_THROWS();
- }
- link = FETCH_DEFAULT_LINK();
- CHECK_DEFAULT_LINK(link);
- break;
- default:
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "OS", &pgsql_link, pgsql_link_ce, &from) == FAILURE) {
- RETURN_THROWS();
- }
- link = Z_PGSQL_LINK_P(pgsql_link);
- CHECK_PGSQL_LINK(link);
- break;
- }
- pgsql = link->conn;
- if (escape_literal) {
- tmp = PQescapeLiteral(pgsql, ZSTR_VAL(from), ZSTR_LEN(from));
- } else {
- tmp = PQescapeIdentifier(pgsql, ZSTR_VAL(from), ZSTR_LEN(from));
- }
- if (!tmp) {
- php_error_docref(NULL, E_WARNING,"Failed to escape");
- RETURN_FALSE;
- }
- RETVAL_STRING(tmp);
- PQfreemem(tmp);
- }
- /* }}} */
- /* {{{ Escape parameter as string literal (i.e. parameter) */
- PHP_FUNCTION(pg_escape_literal)
- {
- php_pgsql_escape_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
- }
- /* }}} */
- /* {{{ Escape identifier (i.e. table name, field name) */
- PHP_FUNCTION(pg_escape_identifier)
- {
- php_pgsql_escape_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
- }
- /* }}} */
- /* {{{ Get error message associated with result */
- PHP_FUNCTION(pg_result_error)
- {
- zval *result;
- PGresult *pgsql_result;
- pgsql_result_handle *pg_result;
- char *err = NULL;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &result, pgsql_result_ce) == FAILURE) {
- RETURN_THROWS();
- }
- pg_result = Z_PGSQL_RESULT_P(result);
- pgsql_result = pg_result->result;
- if (!pgsql_result) {
- RETURN_FALSE;
- }
- err = (char *)PQresultErrorMessage(pgsql_result);
- RETURN_STRING(err);
- }
- /* }}} */
- /* {{{ Get error message field associated with result */
- PHP_FUNCTION(pg_result_error_field)
- {
- zval *result;
- zend_long fieldcode;
- PGresult *pgsql_result;
- pgsql_result_handle *pg_result;
- char *field = NULL;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ol", &result, pgsql_result_ce, &fieldcode) == FAILURE) {
- RETURN_THROWS();
- }
- pg_result = Z_PGSQL_RESULT_P(result);
- pgsql_result = pg_result->result;
- if (!pgsql_result) {
- RETURN_FALSE;
- }
- if (fieldcode & (PG_DIAG_SEVERITY|PG_DIAG_SQLSTATE|PG_DIAG_MESSAGE_PRIMARY|PG_DIAG_MESSAGE_DETAIL
- |PG_DIAG_MESSAGE_HINT|PG_DIAG_STATEMENT_POSITION
- #ifdef PG_DIAG_INTERNAL_POSITION
- |PG_DIAG_INTERNAL_POSITION
- #endif
- #ifdef PG_DIAG_INTERNAL_QUERY
- |PG_DIAG_INTERNAL_QUERY
- #endif
- |PG_DIAG_CONTEXT|PG_DIAG_SOURCE_FILE|PG_DIAG_SOURCE_LINE
- |PG_DIAG_SOURCE_FUNCTION)) {
- field = (char *)PQresultErrorField(pgsql_result, (int)fieldcode);
- if (field == NULL) {
- RETURN_NULL();
- } else {
- RETURN_STRING(field);
- }
- } else {
- RETURN_FALSE;
- }
- }
- /* }}} */
- /* {{{ Get connection status */
- PHP_FUNCTION(pg_connection_status)
- {
- zval *pgsql_link = NULL;
- pgsql_link_handle *link;
- PGconn *pgsql;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &pgsql_link, pgsql_link_ce) == FAILURE) {
- RETURN_THROWS();
- }
- link = Z_PGSQL_LINK_P(pgsql_link);
- CHECK_PGSQL_LINK(link);
- pgsql = link->conn;
- RETURN_LONG(PQstatus(pgsql));
- }
- /* }}} */
- /* {{{ Get transaction status */
- PHP_FUNCTION(pg_transaction_status)
- {
- zval *pgsql_link = NULL;
- pgsql_link_handle *link;
- PGconn *pgsql;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &pgsql_link, pgsql_link_ce) == FAILURE) {
- RETURN_THROWS();
- }
- link = Z_PGSQL_LINK_P(pgsql_link);
- CHECK_PGSQL_LINK(link);
- pgsql = link->conn;
- RETURN_LONG(PQtransactionStatus(pgsql));
- }
- /* }}} */
- /* {{{ Reset connection (reconnect) */
- PHP_FUNCTION(pg_connection_reset)
- {
- zval *pgsql_link;
- pgsql_link_handle *link;
- PGconn *pgsql;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &pgsql_link, pgsql_link_ce) == FAILURE) {
- RETURN_THROWS();
- }
- link = Z_PGSQL_LINK_P(pgsql_link);
- CHECK_PGSQL_LINK(link);
- pgsql = link->conn;
- PQreset(pgsql);
- if (PQstatus(pgsql) == CONNECTION_BAD) {
- RETURN_FALSE;
- }
- RETURN_TRUE;
- }
- /* }}} */
- #define PHP_PG_ASYNC_IS_BUSY 1
- #define PHP_PG_ASYNC_REQUEST_CANCEL 2
- /* {{{ php_pgsql_flush_query */
- static int php_pgsql_flush_query(PGconn *pgsql)
- {
- PGresult *res;
- int leftover = 0;
- if (PQsetnonblocking(pgsql, 1)) {
- php_error_docref(NULL, E_NOTICE,"Cannot set connection to nonblocking mode");
- return -1;
- }
- while ((res = PQgetResult(pgsql))) {
- PQclear(res);
- leftover++;
- }
- PQsetnonblocking(pgsql, 0);
- return leftover;
- }
- /* }}} */
- /* {{{ php_pgsql_do_async */
- static void php_pgsql_do_async(INTERNAL_FUNCTION_PARAMETERS, int entry_type)
- {
- zval *pgsql_link;
- pgsql_link_handle *link;
- PGconn *pgsql;
- PGresult *pgsql_result;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &pgsql_link, pgsql_link_ce) == FAILURE) {
- RETURN_THROWS();
- }
- link = Z_PGSQL_LINK_P(pgsql_link);
- CHECK_PGSQL_LINK(link);
- pgsql = link->conn;
- if (PQsetnonblocking(pgsql, 1)) {
- php_error_docref(NULL, E_NOTICE, "Cannot set connection to nonblocking mode");
- RETURN_FALSE;
- }
- switch(entry_type) {
- case PHP_PG_ASYNC_IS_BUSY:
- PQconsumeInput(pgsql);
- RETVAL_LONG(PQisBusy(pgsql));
- break;
- case PHP_PG_ASYNC_REQUEST_CANCEL:
- RETVAL_LONG(PQrequestCancel(pgsql));
- while ((pgsql_result = PQgetResult(pgsql))) {
- PQclear(pgsql_result);
- }
- break;
- EMPTY_SWITCH_DEFAULT_CASE()
- }
- if (PQsetnonblocking(pgsql, 0)) {
- php_error_docref(NULL, E_NOTICE, "Cannot set connection to blocking mode");
- }
- convert_to_boolean(return_value);
- }
- /* }}} */
- /* {{{ Cancel request */
- PHP_FUNCTION(pg_cancel_query)
- {
- php_pgsql_do_async(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_PG_ASYNC_REQUEST_CANCEL);
- }
- /* }}} */
- /* {{{ Get connection is busy or not */
- PHP_FUNCTION(pg_connection_busy)
- {
- php_pgsql_do_async(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_PG_ASYNC_IS_BUSY);
- }
- /* }}} */
- static bool _php_pgsql_link_has_results(PGconn *pgsql) /* {{{ */
- {
- PGresult *result;
- while ((result = PQgetResult(pgsql))) {
- PQclear(result);
- return true;
- }
- return false;
- }
- /* }}} */
- /* {{{ Send asynchronous query */
- PHP_FUNCTION(pg_send_query)
- {
- zval *pgsql_link;
- pgsql_link_handle *link;
- char *query;
- size_t len;
- PGconn *pgsql;
- int is_non_blocking;
- int ret;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "Os", &pgsql_link, pgsql_link_ce, &query, &len) == FAILURE) {
- RETURN_THROWS();
- }
- link = Z_PGSQL_LINK_P(pgsql_link);
- CHECK_PGSQL_LINK(link);
- pgsql = link->conn;
- is_non_blocking = PQisnonblocking(pgsql);
- if (is_non_blocking == 0 && PQsetnonblocking(pgsql, 1) == -1) {
- php_error_docref(NULL, E_NOTICE, "Cannot set connection to nonblocking mode");
- RETURN_FALSE;
- }
- if (_php_pgsql_link_has_results(pgsql)) {
- php_error_docref(NULL, E_NOTICE,
- "There are results on this connection. Call pg_get_result() until it returns FALSE");
- }
- if (is_non_blocking) {
- if (!PQsendQuery(pgsql, query)) {
- RETURN_FALSE;
- }
- ret = PQflush(pgsql);
- } else {
- if (!PQsendQuery(pgsql, query)) {
- if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
- PQreset(pgsql);
- }
- if (!PQsendQuery(pgsql, query)) {
- RETURN_FALSE;
- }
- }
- /* Wait to finish sending buffer */
- while ((ret = PQflush(pgsql))) {
- if (ret == -1) {
- php_error_docref(NULL, E_NOTICE, "Could not empty PostgreSQL send buffer");
- break;
- }
- usleep(10000);
- }
- if (PQsetnonblocking(pgsql, 0)) {
- php_error_docref(NULL, E_NOTICE, "Cannot set connection to blocking mode");
- }
- }
- if (ret == 0) {
- RETURN_TRUE;
- } else if (ret == -1) {
- RETURN_FALSE;
- } else {
- RETURN_LONG(0);
- }
- }
- /* }}} */
- /* {{{ Send asynchronous parameterized query */
- PHP_FUNCTION(pg_send_query_params)
- {
- zval *pgsql_link, *pv_param_arr, *tmp;
- pgsql_link_handle *link;
- int num_params = 0;
- char **params = NULL;
- char *query;
- size_t query_len;
- PGconn *pgsql;
- int is_non_blocking;
- int ret;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "Osa", &pgsql_link, pgsql_link_ce, &query, &query_len, &pv_param_arr) == FAILURE) {
- RETURN_THROWS();
- }
- link = Z_PGSQL_LINK_P(pgsql_link);
- CHECK_PGSQL_LINK(link);
- pgsql = link->conn;
- is_non_blocking = PQisnonblocking(pgsql);
- if (is_non_blocking == 0 && PQsetnonblocking(pgsql, 1) == -1) {
- php_error_docref(NULL, E_NOTICE, "Cannot set connection to nonblocking mode");
- RETURN_FALSE;
- }
- if (_php_pgsql_link_has_results(pgsql)) {
- php_error_docref(NULL, E_NOTICE,
- "There are results on this connection. Call pg_get_result() until it returns FALSE");
- }
- num_params = zend_hash_num_elements(Z_ARRVAL_P(pv_param_arr));
- if (num_params > 0) {
- int i = 0;
- params = (char **)safe_emalloc(sizeof(char *), num_params, 0);
- ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(pv_param_arr), tmp) {
- if (Z_TYPE_P(tmp) == IS_NULL) {
- params[i] = NULL;
- } else {
- zend_string *tmp_str;
- zend_string *str = zval_get_tmp_string(tmp, &tmp_str);
- params[i] = estrndup(ZSTR_VAL(str), ZSTR_LEN(str));
- zend_tmp_string_release(tmp_str);
- }
- i++;
- } ZEND_HASH_FOREACH_END();
- }
- if (PQsendQueryParams(pgsql, query, num_params, NULL, (const char * const *)params, NULL, NULL, 0)) {
- _php_pgsql_free_params(params, num_params);
- } else if (is_non_blocking) {
- _php_pgsql_free_params(params, num_params);
- RETURN_FALSE;
- } else {
- if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
- PQreset(pgsql);
- }
- if (!PQsendQueryParams(pgsql, query, num_params, NULL, (const char * const *)params, NULL, NULL, 0)) {
- _php_pgsql_free_params(params, num_params);
- RETURN_FALSE;
- }
- }
- if (is_non_blocking) {
- ret = PQflush(pgsql);
- } else {
- /* Wait to finish sending buffer */
- while ((ret = PQflush(pgsql))) {
- if (ret == -1) {
- php_error_docref(NULL, E_NOTICE, "Could not empty PostgreSQL send buffer");
- break;
- }
- usleep(10000);
- }
- if (PQsetnonblocking(pgsql, 0) != 0) {
- php_error_docref(NULL, E_NOTICE, "Cannot set connection to blocking mode");
- }
- }
- if (ret == 0) {
- RETURN_TRUE;
- } else if (ret == -1) {
- RETURN_FALSE;
- } else {
- RETURN_LONG(0);
- }
- }
- /* }}} */
- /* {{{ Asynchronously prepare a query for future execution */
- PHP_FUNCTION(pg_send_prepare)
- {
- zval *pgsql_link;
- pgsql_link_handle *link;
- char *query, *stmtname;
- size_t stmtname_len, query_len;
- PGconn *pgsql;
- int is_non_blocking;
- int ret;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "Oss", &pgsql_link, pgsql_link_ce, &stmtname, &stmtname_len, &query, &query_len) == FAILURE) {
- RETURN_THROWS();
- }
- link = Z_PGSQL_LINK_P(pgsql_link);
- CHECK_PGSQL_LINK(link);
- pgsql = link->conn;
- is_non_blocking = PQisnonblocking(pgsql);
- if (is_non_blocking == 0 && PQsetnonblocking(pgsql, 1) == -1) {
- php_error_docref(NULL, E_NOTICE, "Cannot set connection to nonblocking mode");
- RETURN_FALSE;
- }
- if (_php_pgsql_link_has_results(pgsql)) {
- php_error_docref(NULL, E_NOTICE,
- "There are results on this connection. Call pg_get_result() until it returns FALSE");
- }
- if (!PQsendPrepare(pgsql, stmtname, query, 0, NULL)) {
- if (is_non_blocking) {
- RETURN_FALSE;
- } else {
- if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
- PQreset(pgsql);
- }
- if (!PQsendPrepare(pgsql, stmtname, query, 0, NULL)) {
- RETURN_FALSE;
- }
- }
- }
- if (is_non_blocking) {
- ret = PQflush(pgsql);
- } else {
- /* Wait to finish sending buffer */
- while ((ret = PQflush(pgsql))) {
- if (ret == -1) {
- php_error_docref(NULL, E_NOTICE, "Could not empty PostgreSQL send buffer");
- break;
- }
- usleep(10000);
- }
- if (PQsetnonblocking(pgsql, 0) != 0) {
- php_error_docref(NULL, E_NOTICE, "Cannot set connection to blocking mode");
- }
- }
- if (ret == 0) {
- RETURN_TRUE;
- } else if (ret == -1) {
- RETURN_FALSE;
- } else {
- RETURN_LONG(0);
- }
- }
- /* }}} */
- /* {{{ Executes prevriously prepared stmtname asynchronously */
- PHP_FUNCTION(pg_send_execute)
- {
- zval *pgsql_link;
- pgsql_link_handle *link;
- zval *pv_param_arr, *tmp;
- int num_params = 0;
- char **params = NULL;
- char *stmtname;
- size_t stmtname_len;
- PGconn *pgsql;
- int is_non_blocking;
- int ret;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "Osa", &pgsql_link, pgsql_link_ce, &stmtname, &stmtname_len, &pv_param_arr) == FAILURE) {
- RETURN_THROWS();
- }
- link = Z_PGSQL_LINK_P(pgsql_link);
- CHECK_PGSQL_LINK(link);
- pgsql = link->conn;
- is_non_blocking = PQisnonblocking(pgsql);
- if (is_non_blocking == 0 && PQsetnonblocking(pgsql, 1) == -1) {
- php_error_docref(NULL, E_NOTICE, "Cannot set connection to nonblocking mode");
- RETURN_FALSE;
- }
- if (_php_pgsql_link_has_results(pgsql)) {
- php_error_docref(NULL, E_NOTICE,
- "There are results on this connection. Call pg_get_result() until it returns FALSE");
- }
- num_params = zend_hash_num_elements(Z_ARRVAL_P(pv_param_arr));
- if (num_params > 0) {
- int i = 0;
- params = (char **)safe_emalloc(sizeof(char *), num_params, 0);
- ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(pv_param_arr), tmp) {
- if (Z_TYPE_P(tmp) == IS_NULL) {
- params[i] = NULL;
- } else {
- zend_string *tmp_str = zval_try_get_string(tmp);
- if (UNEXPECTED(!tmp_str)) {
- _php_pgsql_free_params(params, i);
- return;
- }
- params[i] = estrndup(ZSTR_VAL(tmp_str), ZSTR_LEN(tmp_str));
- zend_string_release(tmp_str);
- }
- i++;
- } ZEND_HASH_FOREACH_END();
- }
- if (PQsendQueryPrepared(pgsql, stmtname, num_params, (const char * const *)params, NULL, NULL, 0)) {
- _php_pgsql_free_params(params, num_params);
- } else if (is_non_blocking) {
- _php_pgsql_free_params(params, num_params);
- RETURN_FALSE;
- } else {
- if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
- PQreset(pgsql);
- }
- if (!PQsendQueryPrepared(pgsql, stmtname, num_params, (const char * const *)params, NULL, NULL, 0)) {
- _php_pgsql_free_params(params, num_params);
- RETURN_FALSE;
- }
- }
- if (is_non_blocking) {
- ret = PQflush(pgsql);
- } else {
- /* Wait to finish sending buffer */
- while ((ret = PQflush(pgsql))) {
- if (ret == -1) {
- php_error_docref(NULL, E_NOTICE, "Could not empty PostgreSQL send buffer");
- break;
- }
- usleep(10000);
- }
- if (PQsetnonblocking(pgsql, 0) != 0) {
- php_error_docref(NULL, E_NOTICE, "Cannot set connection to blocking mode");
- }
- }
- if (ret == 0) {
- RETURN_TRUE;
- } else if (ret == -1) {
- RETURN_FALSE;
- } else {
- RETURN_LONG(0);
- }
- }
- /* }}} */
- /* {{{ Get asynchronous query result */
- PHP_FUNCTION(pg_get_result)
- {
- zval *pgsql_link;
- pgsql_link_handle *link;
- PGconn *pgsql;
- PGresult *pgsql_result;
- pgsql_result_handle *pg_result;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &pgsql_link, pgsql_link_ce) == FAILURE) {
- RETURN_THROWS();
- }
- link = Z_PGSQL_LINK_P(pgsql_link);
- CHECK_PGSQL_LINK(link);
- pgsql = link->conn;
- pgsql_result = PQgetResult(pgsql);
- if (!pgsql_result) {
- /* no result */
- RETURN_FALSE;
- }
- object_init_ex(return_value, pgsql_result_ce);
- pg_result = Z_PGSQL_RESULT_P(return_value);
- pg_result->conn = pgsql;
- pg_result->result = pgsql_result;
- pg_result->row = 0;
- }
- /* }}} */
- /* {{{ Get status of query result */
- PHP_FUNCTION(pg_result_status)
- {
- zval *result;
- zend_long result_type = PGSQL_STATUS_LONG;
- ExecStatusType status;
- PGresult *pgsql_result;
- pgsql_result_handle *pg_result;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|l", &result, pgsql_result_ce, &result_type) == FAILURE) {
- RETURN_THROWS();
- }
- pg_result = Z_PGSQL_RESULT_P(result);
- CHECK_PGSQL_RESULT(pg_result);
- pgsql_result = pg_result->result;
- if (result_type == PGSQL_STATUS_LONG) {
- status = PQresultStatus(pgsql_result);
- RETURN_LONG((int)status);
- }
- else if (result_type == PGSQL_STATUS_STRING) {
- RETURN_STRING(PQcmdStatus(pgsql_result));
- } else {
- zend_argument_value_error(2, "must be either PGSQL_STATUS_LONG or PGSQL_STATUS_STRING");
- RETURN_THROWS();
- }
- }
- /* }}} */
- /* {{{ Get asynchronous notification */
- PHP_FUNCTION(pg_get_notify)
- {
- zval *pgsql_link;
- pgsql_link_handle *link;
- zend_long result_type = PGSQL_ASSOC;
- PGconn *pgsql;
- PGnotify *pgsql_notify;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|l", &pgsql_link, pgsql_link_ce, &result_type) == FAILURE) {
- RETURN_THROWS();
- }
- link = Z_PGSQL_LINK_P(pgsql_link);
- CHECK_PGSQL_LINK(link);
- pgsql = link->conn;
- if (!(result_type & PGSQL_BOTH)) {
- zend_argument_value_error(2, "must be one of PGSQL_ASSOC, PGSQL_NUM, or PGSQL_BOTH");
- RETURN_THROWS();
- }
- PQconsumeInput(pgsql);
- pgsql_notify = PQnotifies(pgsql);
- if (!pgsql_notify) {
- /* no notify message */
- RETURN_FALSE;
- }
- array_init(return_value);
- if (result_type & PGSQL_NUM) {
- add_index_string(return_value, 0, pgsql_notify->relname);
- add_index_long(return_value, 1, pgsql_notify->be_pid);
- /* consider to use php_version_compare() here */
- if (PQprotocolVersion(pgsql) >= 3 && zend_strtod(PQparameterStatus(pgsql, "server_version"), NULL) >= 9.0) {
- add_index_string(return_value, 2, pgsql_notify->extra);
- }
- }
- if (result_type & PGSQL_ASSOC) {
- add_assoc_string(return_value, "message", pgsql_notify->relname);
- add_assoc_long(return_value, "pid", pgsql_notify->be_pid);
- /* consider to use php_version_compare() here */
- if (PQprotocolVersion(pgsql) >= 3 && zend_strtod(PQparameterStatus(pgsql, "server_version"), NULL) >= 9.0) {
- add_assoc_string(return_value, "payload", pgsql_notify->extra);
- }
- }
- PQfreemem(pgsql_notify);
- }
- /* }}} */
- /* {{{ Get backend(server) pid */
- PHP_FUNCTION(pg_get_pid)
- {
- zval *pgsql_link;
- pgsql_link_handle *link;
- PGconn *pgsql;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &pgsql_link, pgsql_link_ce) == FAILURE) {
- RETURN_THROWS();
- }
- link = Z_PGSQL_LINK_P(pgsql_link);
- CHECK_PGSQL_LINK(link);
- pgsql = link->conn;
- RETURN_LONG(PQbackendPID(pgsql));
- }
- /* }}} */
- static ssize_t php_pgsql_fd_write(php_stream *stream, const char *buf, size_t count) /* {{{ */
- {
- return -1;
- }
- /* }}} */
- static ssize_t php_pgsql_fd_read(php_stream *stream, char *buf, size_t count) /* {{{ */
- {
- return -1;
- }
- /* }}} */
- static int php_pgsql_fd_close(php_stream *stream, int close_handle) /* {{{ */
- {
- return EOF;
- }
- /* }}} */
- static int php_pgsql_fd_flush(php_stream *stream) /* {{{ */
- {
- return FAILURE;
- }
- /* }}} */
- static int php_pgsql_fd_set_option(php_stream *stream, int option, int value, void *ptrparam) /* {{{ */
- {
- PGconn *pgsql = (PGconn *) stream->abstract;
- switch (option) {
- case PHP_STREAM_OPTION_BLOCKING:
- return PQsetnonblocking(pgsql, value);
- default:
- return FAILURE;
- }
- }
- /* }}} */
- static int php_pgsql_fd_cast(php_stream *stream, int cast_as, void **ret) /* {{{ */
- {
- PGconn *pgsql = (PGconn *) stream->abstract;
- switch (cast_as) {
- case PHP_STREAM_AS_FD_FOR_SELECT:
- case PHP_STREAM_AS_FD:
- case PHP_STREAM_AS_SOCKETD: {
- int fd_number = PQsocket(pgsql);
- if (fd_number == -1) {
- return FAILURE;
- }
- if (ret) {
- *(php_socket_t *)ret = fd_number;
- }
- }
- return SUCCESS;
- ZEND_FALLTHROUGH;
- default:
- return FAILURE;
- }
- }
- /* }}} */
- /* {{{ Get a read-only handle to the socket underlying the pgsql connection */
- PHP_FUNCTION(pg_socket)
- {
- zval *pgsql_link;
- pgsql_link_handle *link;
- php_stream *stream;
- PGconn *pgsql;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &pgsql_link, pgsql_link_ce) == FAILURE) {
- RETURN_THROWS();
- }
- link = Z_PGSQL_LINK_P(pgsql_link);
- CHECK_PGSQL_LINK(link);
- pgsql = link->conn;
- stream = php_stream_alloc(&php_stream_pgsql_fd_ops, pgsql, NULL, "r");
- if (stream) {
- php_stream_to_zval(stream, return_value);
- return;
- }
- RETURN_FALSE;
- }
- /* }}} */
- /* {{{ Reads input on the connection */
- PHP_FUNCTION(pg_consume_input)
- {
- zval *pgsql_link;
- pgsql_link_handle *link;
- PGconn *pgsql;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &pgsql_link, pgsql_link_ce) == FAILURE) {
- RETURN_THROWS();
- }
- link = Z_PGSQL_LINK_P(pgsql_link);
- CHECK_PGSQL_LINK(link);
- pgsql = link->conn;
- RETURN_BOOL(PQconsumeInput(pgsql));
- }
- /* }}} */
- /* {{{ Flush outbound query data on the connection */
- PHP_FUNCTION(pg_flush)
- {
- zval *pgsql_link;
- pgsql_link_handle *link;
- PGconn *pgsql;
- int ret;
- int is_non_blocking;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &pgsql_link, pgsql_link_ce) == FAILURE) {
- RETURN_THROWS();
- }
- link = Z_PGSQL_LINK_P(pgsql_link);
- CHECK_PGSQL_LINK(link);
- pgsql = link->conn;
- is_non_blocking = PQisnonblocking(pgsql);
- if (is_non_blocking == 0 && PQsetnonblocking(pgsql, 1) == -1) {
- php_error_docref(NULL, E_NOTICE, "Cannot set connection to nonblocking mode");
- RETURN_FALSE;
- }
- ret = PQflush(pgsql);
- if (is_non_blocking == 0 && PQsetnonblocking(pgsql, 0) == -1) {
- php_error_docref(NULL, E_NOTICE, "Failed resetting connection to blocking mode");
- }
- switch (ret) {
- case 0: RETURN_TRUE; break;
- case 1: RETURN_LONG(0); break;
- default: RETURN_FALSE;
- }
- }
- /* }}} */
- /* {{{ php_pgsql_meta_data
- * table_name must not be empty
- * TODO: Add meta_data cache for better performance
- */
- PHP_PGSQL_API zend_result php_pgsql_meta_data(PGconn *pg_link, const zend_string *table_name, zval *meta, bool extended)
- {
- PGresult *pg_result;
- char *src, *tmp_name, *tmp_name2 = NULL;
- char *escaped;
- smart_str querystr = {0};
- size_t new_len;
- int i, num_rows;
- zval elem;
- ZEND_ASSERT(ZSTR_LEN(table_name) != 0);
- src = estrdup(ZSTR_VAL(table_name));
- tmp_name = php_strtok_r(src, ".", &tmp_name2);
- if (!tmp_name) {
- // TODO ValueError (empty table name)?
- efree(src);
- php_error_docref(NULL, E_WARNING, "The table name must be specified");
- return FAILURE;
- }
- if (!tmp_name2 || !*tmp_name2) {
- /* Default schema */
- tmp_name2 = tmp_name;
- tmp_name = "public";
- }
- if (extended) {
- smart_str_appends(&querystr,
- "SELECT a.attname, a.attnum, t.typname, a.attlen, a.attnotNULL, a.atthasdef, a.attndims, t.typtype, "
- "d.description "
- "FROM pg_class as c "
- " JOIN pg_attribute a ON (a.attrelid = c.oid) "
- " JOIN pg_type t ON (a.atttypid = t.oid) "
- " JOIN pg_namespace n ON (c.relnamespace = n.oid) "
- " LEFT JOIN pg_description d ON (d.objoid=a.attrelid AND d.objsubid=a.attnum AND c.oid=d.objoid) "
- "WHERE a.attnum > 0 AND c.relname = '");
- } else {
- smart_str_appends(&querystr,
- "SELECT a.attname, a.attnum, t.typname, a.attlen, a.attnotnull, a.atthasdef, a.attndims, t.typtype "
- "FROM pg_class as c "
- " JOIN pg_attribute a ON (a.attrelid = c.oid) "
- " JOIN pg_type t ON (a.atttypid = t.oid) "
- " JOIN pg_namespace n ON (c.relnamespace = n.oid) "
- "WHERE a.attnum > 0 AND c.relname = '");
- }
- escaped = (char *)safe_emalloc(strlen(tmp_name2), 2, 1);
- new_len = PQescapeStringConn(pg_link, escaped, tmp_name2, strlen(tmp_name2), NULL);
- if (new_len) {
- smart_str_appendl(&querystr, escaped, new_len);
- }
- efree(escaped);
- smart_str_appends(&querystr, "' AND n.nspname = '");
- escaped = (char *)safe_emalloc(strlen(tmp_name), 2, 1);
- new_len = PQescapeStringConn(pg_link, escaped, tmp_name, strlen(tmp_name), NULL);
- if (new_len) {
- smart_str_appendl(&querystr, escaped, new_len);
- }
- efree(escaped);
- smart_str_appends(&querystr, "' ORDER BY a.attnum;");
- smart_str_0(&querystr);
- efree(src);
- pg_result = PQexec(pg_link, ZSTR_VAL(querystr.s));
- if (PQresultStatus(pg_result) != PGRES_TUPLES_OK || (num_rows = PQntuples(pg_result)) == 0) {
- php_error_docref(NULL, E_WARNING, "Table '%s' doesn't exists", ZSTR_VAL(table_name));
- smart_str_free(&querystr);
- PQclear(pg_result);
- return FAILURE;
- }
- smart_str_free(&querystr);
- for (i = 0; i < num_rows; i++) {
- char *name;
- array_init(&elem);
- /* pg_attribute.attnum */
- add_assoc_long_ex(&elem, "num", sizeof("num") - 1, atoi(PQgetvalue(pg_result, i, 1)));
- /* pg_type.typname */
- add_assoc_string_ex(&elem, "type", sizeof("type") - 1, PQgetvalue(pg_result, i, 2));
- /* pg_attribute.attlen */
- add_assoc_long_ex(&elem, "len", sizeof("len") - 1, atoi(PQgetvalue(pg_result,i,3)));
- /* pg_attribute.attnonull */
- add_assoc_bool_ex(&elem, "not null", sizeof("not null") - 1, !strcmp(PQgetvalue(pg_result, i, 4), "t"));
- /* pg_attribute.atthasdef */
- add_assoc_bool_ex(&elem, "has default", sizeof("has default") - 1, !strcmp(PQgetvalue(pg_result,i,5), "t"));
- /* pg_attribute.attndims */
- add_assoc_long_ex(&elem, "array dims", sizeof("array dims") - 1, atoi(PQgetvalue(pg_result, i, 6)));
- /* pg_type.typtype */
- add_assoc_bool_ex(&elem, "is enum", sizeof("is enum") - 1, !strcmp(PQgetvalue(pg_result, i, 7), "e"));
- if (extended) {
- /* pg_type.typtype */
- add_assoc_bool_ex(&elem, "is base", sizeof("is base") - 1, !strcmp(PQgetvalue(pg_result, i, 7), "b"));
- add_assoc_bool_ex(&elem, "is composite", sizeof("is composite") - 1, !strcmp(PQgetvalue(pg_result, i, 7), "c"));
- add_assoc_bool_ex(&elem, "is pesudo", sizeof("is pesudo") - 1, !strcmp(PQgetvalue(pg_result, i, 7), "p"));
- /* pg_description.description */
- add_assoc_string_ex(&elem, "description", sizeof("description") - 1, PQgetvalue(pg_result, i, 8));
- }
- /* pg_attribute.attname */
- name = PQgetvalue(pg_result,i,0);
- add_assoc_zval(meta, name, &elem);
- }
- PQclear(pg_result);
- return SUCCESS;
- }
- /* }}} */
- /* {{{ Get meta_data */
- PHP_FUNCTION(pg_meta_data)
- {
- zval *pgsql_link;
- pgsql_link_handle *link;
- zend_string *table_name;
- bool extended=0;
- PGconn *pgsql;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "OP|b",
- &pgsql_link, pgsql_link_ce, &table_name, &extended) == FAILURE
- ) {
- RETURN_THROWS();
- }
- link = Z_PGSQL_LINK_P(pgsql_link);
- CHECK_PGSQL_LINK(link);
- pgsql = link->conn;
- /* php_pgsql_meta_data() asserts that table_name is not empty */
- if (ZSTR_LEN(table_name) == 0) {
- zend_argument_value_error(2, "cannot be empty");
- RETURN_THROWS();
- }
- array_init(return_value);
- if (php_pgsql_meta_data(pgsql, table_name, return_value, extended) == FAILURE) {
- zend_array_destroy(Z_ARR_P(return_value)); /* destroy array */
- RETURN_FALSE;
- }
- }
- /* }}} */
- /* {{{ php_pgsql_get_data_type */
- static php_pgsql_data_type php_pgsql_get_data_type(const zend_string *type_name)
- {
- /* This is stupid way to do. I'll fix it when I decide how to support
- user defined types. (Yasuo) */
- /* boolean */
- if (zend_string_equals_literal(type_name, "bool")|| zend_string_equals_literal(type_name, "boolean"))
- return PG_BOOL;
- /* object id */
- if (zend_string_equals_literal(type_name, "oid"))
- return PG_OID;
- /* integer */
- if (zend_string_equals_literal(type_name, "int2") || zend_string_equals_literal(type_name, "smallint"))
- return PG_INT2;
- if (zend_string_equals_literal(type_name, "int4") || zend_string_equals_literal(type_name, "integer"))
- return PG_INT4;
- if (zend_string_equals_literal(type_name, "int8") || zend_string_equals_literal(type_name, "bigint"))
- return PG_INT8;
- /* real and other */
- if (zend_string_equals_literal(type_name, "float4") || zend_string_equals_literal(type_name, "real"))
- return PG_FLOAT4;
- if (zend_string_equals_literal(type_name, "float8") || zend_string_equals_literal(type_name, "double precision"))
- return PG_FLOAT8;
- if (zend_string_equals_literal(type_name, "numeric"))
- return PG_NUMERIC;
- if (zend_string_equals_literal(type_name, "money"))
- return PG_MONEY;
- /* character */
- if (zend_string_equals_literal(type_name, "text"))
- return PG_TEXT;
- if (zend_string_equals_literal(type_name, "bpchar") || zend_string_equals_literal(type_name, "character"))
- return PG_CHAR;
- if (zend_string_equals_literal(type_name, "varchar") || zend_string_equals_literal(type_name, "character varying"))
- return PG_VARCHAR;
- /* time and interval */
- if (zend_string_equals_literal(type_name, "abstime"))
- return PG_UNIX_TIME;
- if (zend_string_equals_literal(type_name, "reltime"))
- return PG_UNIX_TIME_INTERVAL;
- if (zend_string_equals_literal(type_name, "tinterval"))
- return PG_UNIX_TIME_INTERVAL;
- if (zend_string_equals_literal(type_name, "date"))
- return PG_DATE;
- if (zend_string_equals_literal(type_name, "time"))
- return PG_TIME;
- if (zend_string_equals_literal(type_name, "time with time zone") || zend_string_equals_literal(type_name, "timetz"))
- return PG_TIME_WITH_TIMEZONE;
- if (zend_string_equals_literal(type_name, "timestamp without time zone") || zend_string_equals_literal(type_name, "timestamp"))
- return PG_TIMESTAMP;
- if (zend_string_equals_literal(type_name, "timestamp with time zone") || zend_string_equals_literal(type_name, "timestamptz"))
- return PG_TIMESTAMP_WITH_TIMEZONE;
- if (zend_string_equals_literal(type_name, "interval"))
- return PG_INTERVAL;
- /* binary */
- if (zend_string_equals_literal(type_name, "bytea"))
- return PG_BYTEA;
- /* network */
- if (zend_string_equals_literal(type_name, "cidr"))
- return PG_CIDR;
- if (zend_string_equals_literal(type_name, "inet"))
- return PG_INET;
- if (zend_string_equals_literal(type_name, "macaddr"))
- return PG_MACADDR;
- /* bit */
- if (zend_string_equals_literal(type_name, "bit"))
- return PG_BIT;
- if (zend_string_equals_literal(type_name, "bit varying"))
- return PG_VARBIT;
- /* geometric */
- if (zend_string_equals_literal(type_name, "line"))
- return PG_LINE;
- if (zend_string_equals_literal(type_name, "lseg"))
- return PG_LSEG;
- if (zend_string_equals_literal(type_name, "box"))
- return PG_BOX;
- if (zend_string_equals_literal(type_name, "path"))
- return PG_PATH;
- if (zend_string_equals_literal(type_name, "point"))
- return PG_POINT;
- if (zend_string_equals_literal(type_name, "polygon"))
- return PG_POLYGON;
- if (zend_string_equals_literal(type_name, "circle"))
- return PG_CIRCLE;
- return PG_UNKNOWN;
- }
- /* }}} */
- /* {{{ php_pgsql_convert_match
- * test field value with regular expression specified.
- */
- static int php_pgsql_convert_match(const zend_string *str, const char *regex , size_t regex_len, int icase)
- {
- pcre2_code *re;
- PCRE2_SIZE err_offset;
- int res, errnumber;
- uint32_t options = PCRE2_NO_AUTO_CAPTURE;
- size_t i;
- pcre2_match_data *match_data;
- /* Check invalid chars for POSIX regex */
- for (i = 0; i < ZSTR_LEN(str); i++) {
- if (ZSTR_VAL(str)[i] == '\n' ||
- ZSTR_VAL(str)[i] == '\r' ||
- ZSTR_VAL(str)[i] == '\0' ) {
- return FAILURE;
- }
- }
- if (icase) {
- options |= PCRE2_CASELESS;
- }
- re = pcre2_compile((PCRE2_SPTR)regex, regex_len, options, &errnumber, &err_offset, php_pcre_cctx());
- if (NULL == re) {
- PCRE2_UCHAR err_msg[128];
- pcre2_get_error_message(errnumber, err_msg, sizeof(err_msg));
- php_error_docref(NULL, E_WARNING, "Cannot compile regex: '%s'", err_msg);
- return FAILURE;
- }
- match_data = php_pcre_create_match_data(0, re);
- if (NULL == match_data) {
- pcre2_code_free(re);
- php_error_docref(NULL, E_WARNING, "Cannot allocate match data");
- return FAILURE;
- }
- res = pcre2_match(re, (PCRE2_SPTR)ZSTR_VAL(str), ZSTR_LEN(str), 0, 0, match_data, php_pcre_mctx());
- php_pcre_free_match_data(match_data);
- pcre2_code_free(re);
- if (res == PCRE2_ERROR_NOMATCH) {
- return FAILURE;
- } else if (res < 0) {
- php_error_docref(NULL, E_WARNING, "Cannot exec regex");
- return FAILURE;
- }
- return SUCCESS;
- }
- /* }}} */
- /* {{{ php_pgsql_add_quote
- * add quotes around string.
- */
- static zend_string *php_pgsql_add_quotes(zend_string *src)
- {
- return zend_string_concat3("E'", strlen("E'"), ZSTR_VAL(src), ZSTR_LEN(src), "'", strlen("'"));
- }
- /* }}} */
- /* Raise E_NOTICE to E_WARNING or Error? */
- #define PGSQL_CONV_CHECK_IGNORE() \
- if (!err && Z_TYPE(new_val) == IS_STRING && zend_string_equals_literal(Z_STR(new_val), "NULL")) { \
- /* if new_value is string "NULL" and field has default value, remove element to use default value */ \
- if (!(opt & PGSQL_CONV_IGNORE_DEFAULT) && Z_TYPE_P(has_default) == IS_TRUE) { \
- zval_ptr_dtor(&new_val); \
- skip_field = 1; \
- } \
- /* raise error if it's not null and cannot be ignored */ \
- else if (!(opt & PGSQL_CONV_IGNORE_NOT_NULL) && Z_TYPE_P(not_null) == IS_TRUE) { \
- php_error_docref(NULL, E_NOTICE, "Detected NULL for 'NOT NULL' field '%s'", ZSTR_VAL(field)); \
- err = 1; \
- } \
- }
- /* {{{ php_pgsql_convert
- * check and convert array values (fieldname=>value pair) for sql
- */
- PHP_PGSQL_API zend_result php_pgsql_convert(PGconn *pg_link, const zend_string *table_name, const zval *values, zval *result, zend_ulong opt)
- {
- zend_string *field = NULL;
- zval meta, *def, *type, *not_null, *has_default, *is_enum, *val, new_val;
- int err = 0, skip_field;
- php_pgsql_data_type data_type;
- ZEND_ASSERT(pg_link != NULL);
- ZEND_ASSERT(Z_TYPE_P(values) == IS_ARRAY);
- ZEND_ASSERT(Z_TYPE_P(result) == IS_ARRAY);
- ZEND_ASSERT(!(opt & ~PGSQL_CONV_OPTS));
- ZEND_ASSERT(table_name);
- /* Table name cannot be empty for php_pgsql_meta_data() */
- ZEND_ASSERT(ZSTR_LEN(table_name) != 0);
- array_init(&meta);
- /* table_name is escaped by php_pgsql_meta_data */
- if (php_pgsql_meta_data(pg_link, table_name, &meta, 0) == FAILURE) {
- zval_ptr_dtor(&meta);
- return FAILURE;
- }
- ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(values), field, val) {
- skip_field = 0;
- ZVAL_DEREF(val);
- ZVAL_NULL(&new_val);
- /* TODO: Check when meta data can be broken and see if can use assertions instead */
- if (!err && field == NULL) {
- zend_value_error("Array of values must be an associative array with string keys");
- err = 1;
- }
- if (!err && (def = zend_hash_find(Z_ARRVAL(meta), field)) == NULL) {
- php_error_docref(NULL, E_NOTICE, "Invalid field name (%s) in values", ZSTR_VAL(field));
- err = 1;
- }
- if (!err && (type = zend_hash_str_find(Z_ARRVAL_P(def), "type", sizeof("type") - 1)) == NULL) {
- php_error_docref(NULL, E_NOTICE, "Detected broken meta data. Missing 'type'");
- err = 1;
- }
- if (!err && (not_null = zend_hash_str_find(Z_ARRVAL_P(def), "not null", sizeof("not null") - 1)) == NULL) {
- php_error_docref(NULL, E_NOTICE, "Detected broken meta data. Missing 'not null'");
- err = 1;
- }
- if (!err && (has_default = zend_hash_str_find(Z_ARRVAL_P(def), "has default", sizeof("has default") - 1)) == NULL) {
- php_error_docref(NULL, E_NOTICE, "Detected broken meta data. Missing 'has default'");
- err = 1;
- }
- if (!err && (is_enum = zend_hash_str_find(Z_ARRVAL_P(def), "is enum", sizeof("is enum") - 1)) == NULL) {
- php_error_docref(NULL, E_NOTICE, "Detected broken meta data. Missing 'is enum'");
- err = 1;
- }
- if (!err && (Z_TYPE_P(val) == IS_ARRAY || Z_TYPE_P(val) == IS_OBJECT || Z_TYPE_P(val) == IS_RESOURCE)) {
- zend_type_error("Values must be of type string|int|float|bool|null, %s given", zend_zval_type_name(val));
- err = 1;
- }
- if (err) {
- break; /* break out for() */
- }
- convert_to_boolean(is_enum);
- if (Z_TYPE_P(is_enum) == IS_TRUE) {
- /* enums need to be treated like strings */
- data_type = PG_TEXT;
- } else {
- data_type = php_pgsql_get_data_type(Z_STR_P(type));
- }
- /* TODO: Should E_NOTICE be converted to type error if PHP type cannot be converted to field type? */
- switch(data_type)
- {
- case PG_BOOL:
- switch (Z_TYPE_P(val)) {
- case IS_STRING:
- if (Z_STRLEN_P(val) == 0) {
- ZVAL_STR(&new_val, ZSTR_KNOWN(ZEND_STR_NULL));
- }
- else {
- if (zend_string_equals_literal(Z_STR_P(val), "t") || zend_string_equals_literal(Z_STR_P(val), "T") ||
- zend_string_equals_literal(Z_STR_P(val), "y") || zend_string_equals_literal(Z_STR_P(val), "Y") ||
- zend_string_equals_literal(Z_STR_P(val), "true") || zend_string_equals_literal(Z_STR_P(val), "True") ||
- zend_string_equals_literal(Z_STR_P(val), "yes") || zend_string_equals_literal(Z_STR_P(val), "Yes") ||
- zend_string_equals_literal(Z_STR_P(val), "1")) {
- ZVAL_STRINGL(&new_val, "'t'", sizeof("'t'")-1);
- }
- else if (zend_string_equals_literal(Z_STR_P(val), "f") || zend_string_equals_literal(Z_STR_P(val), "F") ||
- zend_string_equals_literal(Z_STR_P(val), "n") || zend_string_equals_literal(Z_STR_P(val), "N") ||
- zend_string_equals_literal(Z_STR_P(val), "false") || zend_string_equals_literal(Z_STR_P(val), "False") ||
- zend_string_equals_literal(Z_STR_P(val), "no") || zend_string_equals_literal(Z_STR_P(val), "No") ||
- zend_string_equals_literal(Z_STR_P(val), "0")) {
- ZVAL_STRINGL(&new_val, "'f'", sizeof("'f'")-1);
- }
- else {
- php_error_docref(NULL, E_NOTICE, "Detected invalid value (%s) for PostgreSQL %s field (%s)", Z_STRVAL_P(val), Z_STRVAL_P(type), ZSTR_VAL(field));
- err = 1;
- }
- }
- break;
- case IS_LONG:
- if (Z_LVAL_P(val)) {
- ZVAL_STRINGL(&new_val, "'t'", sizeof("'t'")-1);
- }
- else {
- ZVAL_STRINGL(&new_val, "'f'", sizeof("'f'")-1);
- }
- break;
- case IS_TRUE:
- ZVAL_STRINGL(&new_val, "'t'", sizeof("'t'")-1);
- break;
- case IS_FALSE:
- ZVAL_STRINGL(&new_val, "'f'", sizeof("'f'")-1);
- break;
- case IS_NULL:
- ZVAL_STR(&new_val, ZSTR_KNOWN(ZEND_STR_NULL));
- break;
- default:
- err = 1;
- }
- PGSQL_CONV_CHECK_IGNORE();
- if (err) {
- php_error_docref(NULL, E_NOTICE, "Expects string, null, long or boolelan value for PostgreSQL '%s' (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
- }
- break;
- case PG_OID:
- case PG_INT2:
- case PG_INT4:
- case PG_INT8:
- switch (Z_TYPE_P(val)) {
- case IS_STRING:
- if (Z_STRLEN_P(val) == 0) {
- ZVAL_STR(&new_val, ZSTR_KNOWN(ZEND_STR_NULL));
- }
- else {
- /* FIXME: better regex must be used */
- #define REGEX0 "^([+-]{0,1}[0-9]+)$"
- if (php_pgsql_convert_match(Z_STR_P(val), REGEX0, sizeof(REGEX0)-1, 0) == FAILURE) {
- err = 1;
- }
- else {
- ZVAL_STRINGL(&new_val, Z_STRVAL_P(val), Z_STRLEN_P(val));
- }
- #undef REGEX0
- }
- break;
- case IS_DOUBLE:
- ZVAL_DOUBLE(&new_val, Z_DVAL_P(val));
- convert_to_long(&new_val);
- break;
- case IS_LONG:
- ZVAL_LONG(&new_val, Z_LVAL_P(val));
- break;
- case IS_NULL:
- ZVAL_STR(&new_val, ZSTR_KNOWN(ZEND_STR_NULL));
- break;
- default:
- err = 1;
- }
- PGSQL_CONV_CHECK_IGNORE();
- if (err) {
- php_error_docref(NULL, E_NOTICE, "Expects NULL, string, long or double value for pgsql '%s' (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
- }
- break;
- case PG_NUMERIC:
- case PG_MONEY:
- case PG_FLOAT4:
- case PG_FLOAT8:
- switch (Z_TYPE_P(val)) {
- case IS_STRING:
- if (Z_STRLEN_P(val) == 0) {
- ZVAL_STR(&new_val, ZSTR_KNOWN(ZEND_STR_NULL));
- }
- else {
- #define REGEX0 "^[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?$"
- #define REGEX1 "^[+-]{0,1}(inf)(inity){0,1}$"
- /* better regex? */
- if (php_pgsql_convert_match(Z_STR_P(val), REGEX0, sizeof(REGEX0)-1, 0) == FAILURE) {
- if (php_pgsql_convert_match(Z_STR_P(val), REGEX1, sizeof(REGEX1)-1, 1) == FAILURE) {
- err = 1;
- } else {
- ZVAL_STR(&new_val, php_pgsql_add_quotes(Z_STR_P(val)));
- }
- }
- else {
- ZVAL_STRING(&new_val, Z_STRVAL_P(val));
- }
- #undef REGEX0
- #undef REGEX1
- }
- break;
- case IS_LONG:
- ZVAL_LONG(&new_val, Z_LVAL_P(val));
- break;
- case IS_DOUBLE:
- ZVAL_DOUBLE(&new_val, Z_DVAL_P(val));
- break;
- case IS_NULL:
- ZVAL_STR(&new_val, ZSTR_KNOWN(ZEND_STR_NULL));
- break;
- default:
- err = 1;
- }
- PGSQL_CONV_CHECK_IGNORE();
- if (err) {
- php_error_docref(NULL, E_NOTICE, "Expects NULL, string, long or double value for PostgreSQL '%s' (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
- }
- break;
- /* Exotic types are handled as string also.
- Please feel free to add more valitions. Invalid query fails
- at execution anyway. */
- case PG_TEXT:
- case PG_CHAR:
- case PG_VARCHAR:
- /* bit */
- case PG_BIT:
- case PG_VARBIT:
- /* geometric */
- case PG_LINE:
- case PG_LSEG:
- case PG_POINT:
- case PG_BOX:
- case PG_PATH:
- case PG_POLYGON:
- case PG_CIRCLE:
- /* unknown. JSON, Array etc */
- case PG_UNKNOWN:
- switch (Z_TYPE_P(val)) {
- case IS_STRING:
- if (Z_STRLEN_P(val) == 0) {
- if (opt & PGSQL_CONV_FORCE_NULL) {
- ZVAL_STR(&new_val, ZSTR_KNOWN(ZEND_STR_NULL));
- } else {
- ZVAL_STRINGL(&new_val, "''", sizeof("''")-1);
- }
- }
- else {
- zend_string *str;
- /* PostgreSQL ignores \0 */
- str = zend_string_alloc(Z_STRLEN_P(val) * 2, 0);
- /* better to use PGSQLescapeLiteral since PGescapeStringConn does not handle special \ */
- ZSTR_LEN(str) = PQescapeStringConn(pg_link, ZSTR_VAL(str), Z_STRVAL_P(val), Z_STRLEN_P(val), NULL);
- ZVAL_STR(&new_val, php_pgsql_add_quotes(str));
- zend_string_release_ex(str, false);
- }
- break;
- case IS_LONG:
- ZVAL_STR(&new_val, zend_long_to_str(Z_LVAL_P(val)));
- break;
- case IS_DOUBLE:
- ZVAL_DOUBLE(&new_val, Z_DVAL_P(val));
- convert_to_string(&new_val);
- break;
- case IS_NULL:
- ZVAL_STR(&new_val, ZSTR_KNOWN(ZEND_STR_NULL));
- break;
- default:
- err = 1;
- }
- PGSQL_CONV_CHECK_IGNORE();
- if (err) {
- php_error_docref(NULL, E_NOTICE, "Expects NULL, string, long or double value for PostgreSQL '%s' (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
- }
- break;
- case PG_UNIX_TIME:
- case PG_UNIX_TIME_INTERVAL:
- /* these are the actallay a integer */
- switch (Z_TYPE_P(val)) {
- case IS_STRING:
- if (Z_STRLEN_P(val) == 0) {
- ZVAL_STR(&new_val, ZSTR_KNOWN(ZEND_STR_NULL));
- }
- else {
- /* better regex? */
- if (php_pgsql_convert_match(Z_STR_P(val), "^[0-9]+$", sizeof("^[0-9]+$")-1, 0) == FAILURE) {
- err = 1;
- }
- else {
- ZVAL_STRINGL(&new_val, Z_STRVAL_P(val), Z_STRLEN_P(val));
- convert_to_long(&new_val);
- }
- }
- break;
- case IS_DOUBLE:
- ZVAL_DOUBLE(&new_val, Z_DVAL_P(val));
- convert_to_long(&new_val);
- break;
- case IS_LONG:
- ZVAL_LONG(&new_val, Z_LVAL_P(val));
- break;
- case IS_NULL:
- ZVAL_STR(&new_val, ZSTR_KNOWN(ZEND_STR_NULL));
- break;
- default:
- err = 1;
- }
- PGSQL_CONV_CHECK_IGNORE();
- if (err) {
- php_error_docref(NULL, E_NOTICE, "Expects NULL, string, long or double value for '%s' (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
- }
- break;
- case PG_CIDR:
- case PG_INET:
- switch (Z_TYPE_P(val)) {
- case IS_STRING:
- if (Z_STRLEN_P(val) == 0) {
- ZVAL_STR(&new_val, ZSTR_KNOWN(ZEND_STR_NULL));
- }
- else {
- #define REGEX0 "^((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-9]{1,3})?$"
- #define REGEX1 "^(([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-9]{1,3})?$"
- /* The inet type holds an IPv4 or IPv6 host address, and optionally its subnet, all in one field. See more in the doc.
- The regex might still be not perfect, but catches the most of IP variants. We might decide to remove the regex
- at all though and let the server side to handle it.*/
- if (php_pgsql_convert_match(Z_STR_P(val), REGEX0, sizeof(REGEX0)-1, 0) == FAILURE
- && php_pgsql_convert_match(Z_STR_P(val), REGEX1, sizeof(REGEX1)-1, 0) == FAILURE) {
- err = 1;
- }
- else {
- ZVAL_STR(&new_val, php_pgsql_add_quotes(Z_STR_P(val)));
- }
- #undef REGEX0
- #undef REGEX1
- }
- break;
- case IS_NULL:
- ZVAL_STR(&new_val, ZSTR_KNOWN(ZEND_STR_NULL));
- break;
- default:
- err = 1;
- }
- PGSQL_CONV_CHECK_IGNORE();
- if (err) {
- php_error_docref(NULL, E_NOTICE, "Expects NULL or IPv4 or IPv6 address string for '%s' (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
- }
- break;
- case PG_TIME_WITH_TIMEZONE:
- case PG_TIMESTAMP:
- case PG_TIMESTAMP_WITH_TIMEZONE:
- switch(Z_TYPE_P(val)) {
- case IS_STRING:
- if (Z_STRLEN_P(val) == 0) {
- ZVAL_STR(&new_val, ZSTR_KNOWN(ZEND_STR_NULL));
- } else if (zend_string_equals_literal_ci(Z_STR_P(val), "now()")) {
- ZVAL_STRINGL(&new_val, "NOW()", sizeof("NOW()")-1);
- } else {
- #define REGEX0 "^([0-9]{4}[/-][0-9]{1,2}[/-][0-9]{1,2})(([ \\t]+|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}$"
- /* better regex? */
- if (php_pgsql_convert_match(Z_STR_P(val), REGEX0, sizeof(REGEX0)-1, 1) == FAILURE) {
- err = 1;
- } else {
- ZVAL_STR(&new_val, php_pgsql_add_quotes(Z_STR_P(val)));
- }
- #undef REGEX0
- }
- break;
- case IS_NULL:
- ZVAL_STR(&new_val, ZSTR_KNOWN(ZEND_STR_NULL));
- break;
- default:
- err = 1;
- }
- PGSQL_CONV_CHECK_IGNORE();
- if (err) {
- php_error_docref(NULL, E_NOTICE, "Expects NULL or string for PostgreSQL %s field (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
- }
- break;
- case PG_DATE:
- switch(Z_TYPE_P(val)) {
- case IS_STRING:
- if (Z_STRLEN_P(val) == 0) {
- ZVAL_STR(&new_val, ZSTR_KNOWN(ZEND_STR_NULL));
- }
- else {
- #define REGEX0 "^([0-9]{4}[/-][0-9]{1,2}[/-][0-9]{1,2})$"
- /* FIXME: better regex must be used */
- if (php_pgsql_convert_match(Z_STR_P(val), REGEX0, sizeof(REGEX0)-1, 1) == FAILURE) {
- err = 1;
- }
- else {
- ZVAL_STR(&new_val, php_pgsql_add_quotes(Z_STR_P(val)));
- }
- #undef REGEX0
- }
- break;
- case IS_NULL:
- ZVAL_STR(&new_val, ZSTR_KNOWN(ZEND_STR_NULL));
- break;
- default:
- err = 1;
- }
- PGSQL_CONV_CHECK_IGNORE();
- if (err) {
- php_error_docref(NULL, E_NOTICE, "Expects NULL or string for PostgreSQL %s field (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
- }
- break;
- case PG_TIME:
- switch(Z_TYPE_P(val)) {
- case IS_STRING:
- if (Z_STRLEN_P(val) == 0) {
- ZVAL_STR(&new_val, ZSTR_KNOWN(ZEND_STR_NULL));
- }
- else {
- #define REGEX0 "^(([0-9]{1,2}:[0-9]{1,2}){1}(:[0-9]{1,2}){0,1}){0,1}$"
- /* FIXME: better regex must be used */
- if (php_pgsql_convert_match(Z_STR_P(val), REGEX0, sizeof(REGEX0)-1, 1) == FAILURE) {
- err = 1;
- }
- else {
- ZVAL_STR(&new_val, php_pgsql_add_quotes(Z_STR_P(val)));
- }
- #undef REGEX0
- }
- break;
- case IS_NULL:
- ZVAL_STR(&new_val, ZSTR_KNOWN(ZEND_STR_NULL));
- break;
- default:
- err = 1;
- }
- PGSQL_CONV_CHECK_IGNORE();
- if (err) {
- php_error_docref(NULL, E_NOTICE, "Expects NULL or string for PostgreSQL %s field (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
- }
- break;
- case PG_INTERVAL:
- switch(Z_TYPE_P(val)) {
- case IS_STRING:
- if (Z_STRLEN_P(val) == 0) {
- ZVAL_STR(&new_val, ZSTR_KNOWN(ZEND_STR_NULL));
- }
- else {
- /* From the Postgres docs:
- interval values can be written with the following syntax:
- [@] quantity unit [quantity unit...] [direction]
- Where: quantity is a number (possibly signed); unit is second, minute, hour,
- day, week, month, year, decade, century, millennium, or abbreviations or
- plurals of these units [note not *all* abbreviations] ; direction can be
- ago or empty. The at sign (@) is optional noise.
- ...
- Quantities of days, hours, minutes, and seconds can be specified without explicit
- unit markings. For example, '1 12:59:10' is read the same as '1 day 12 hours 59 min 10
- sec'.
- */
- #define REGEX0 \
- "^(@?[ \\t]+)?(" \
- /* Textual time units and their abbreviations: */ \
- "(([-+]?[ \\t]+)?" \
- "[0-9]+(\\.[0-9]*)?[ \\t]*" \
- "(millenniums|millennia|millennium|mil|mils|" \
- "centuries|century|cent|c|" \
- "decades|decade|dec|decs|" \
- "years|year|y|" \
- "months|month|mon|" \
- "weeks|week|w|" \
- "days|day|d|" \
- "hours|hour|hr|hrs|h|" \
- "minutes|minute|mins|min|m|" \
- "seconds|second|secs|sec|s))+|" \
- /* Textual time units plus (dd)* hh[:mm[:ss]] */ \
- "((([-+]?[ \\t]+)?" \
- "[0-9]+(\\.[0-9]*)?[ \\t]*" \
- "(millenniums|millennia|millennium|mil|mils|" \
- "centuries|century|cent|c|" \
- "decades|decade|dec|decs|" \
- "years|year|y|" \
- "months|month|mon|" \
- "weeks|week|w|" \
- "days|day|d))+" \
- "([-+]?[ \\t]+" \
- "([0-9]+[ \\t]+)+" /* dd */ \
- "(([0-9]{1,2}:){0,2}[0-9]{0,2})" /* hh:[mm:[ss]] */ \
- ")?))" \
- "([ \\t]+ago)?$"
- if (php_pgsql_convert_match(Z_STR_P(val), REGEX0, sizeof(REGEX0)-1, 1) == FAILURE) {
- err = 1;
- }
- else {
- ZVAL_STR(&new_val, php_pgsql_add_quotes(Z_STR_P(val)));
- }
- #undef REGEX0
- }
- break;
- case IS_NULL:
- ZVAL_STR(&new_val, ZSTR_KNOWN(ZEND_STR_NULL));
- break;
- default:
- err = 1;
- }
- PGSQL_CONV_CHECK_IGNORE();
- if (err) {
- php_error_docref(NULL, E_NOTICE, "Expects NULL or string for PostgreSQL %s field (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
- }
- break;
- case PG_BYTEA:
- switch (Z_TYPE_P(val)) {
- case IS_STRING:
- if (Z_STRLEN_P(val) == 0) {
- ZVAL_STR(&new_val, ZSTR_KNOWN(ZEND_STR_NULL));
- }
- else {
- unsigned char *tmp;
- size_t to_len;
- zend_string *tmp_zstr;
- tmp = PQescapeByteaConn(pg_link, (unsigned char *)Z_STRVAL_P(val), Z_STRLEN_P(val), &to_len);
- tmp_zstr = zend_string_init((char *)tmp, to_len - 1, false); /* PQescapeBytea's to_len includes additional '\0' */
- PQfreemem(tmp);
- ZVAL_STR(&new_val, php_pgsql_add_quotes(tmp_zstr));
- zend_string_release_ex(tmp_zstr, false);
- }
- break;
- case IS_LONG:
- ZVAL_STR(&new_val, zend_long_to_str(Z_LVAL_P(val)));
- break;
- case IS_DOUBLE:
- ZVAL_DOUBLE(&new_val, Z_DVAL_P(val));
- convert_to_string(&new_val);
- break;
- case IS_NULL:
- ZVAL_STR(&new_val, ZSTR_KNOWN(ZEND_STR_NULL));
- break;
- default:
- err = 1;
- }
- PGSQL_CONV_CHECK_IGNORE();
- if (err) {
- php_error_docref(NULL, E_NOTICE, "Expects NULL, string, long or double value for PostgreSQL '%s' (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
- }
- break;
- case PG_MACADDR:
- switch(Z_TYPE_P(val)) {
- case IS_STRING:
- if (Z_STRLEN_P(val) == 0) {
- ZVAL_STR(&new_val, ZSTR_KNOWN(ZEND_STR_NULL));
- }
- else {
- #define REGEX0 "^([0-9a-f]{2,2}:){5,5}[0-9a-f]{2,2}$"
- if (php_pgsql_convert_match(Z_STR_P(val), REGEX0, sizeof(REGEX0)-1, 1) == FAILURE) {
- err = 1;
- }
- else {
- ZVAL_STR(&new_val, php_pgsql_add_quotes(Z_STR_P(val)));
- }
- #undef REGEX0
- }
- break;
- case IS_NULL:
- ZVAL_STR(&new_val, ZSTR_KNOWN(ZEND_STR_NULL));
- break;
- default:
- err = 1;
- }
- PGSQL_CONV_CHECK_IGNORE();
- if (err) {
- php_error_docref(NULL, E_NOTICE, "Expects NULL or string for PostgreSQL %s field (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
- }
- break;
- default:
- /* should not happen */
- php_error_docref(NULL, E_NOTICE, "Unknown or system data type '%s' for '%s'. Report error", Z_STRVAL_P(type), ZSTR_VAL(field));
- err = 1;
- break;
- } /* switch */
- if (err) {
- zval_ptr_dtor(&new_val);
- break; /* break out for() */
- }
- /* If field is NULL and HAS DEFAULT, should be skipped */
- if (!skip_field) {
- if (_php_pgsql_identifier_is_escaped(ZSTR_VAL(field), ZSTR_LEN(field))) {
- zend_hash_update(Z_ARRVAL_P(result), field, &new_val);
- } else {
- char *escaped = PQescapeIdentifier(pg_link, ZSTR_VAL(field), ZSTR_LEN(field));
- add_assoc_zval(result, escaped, &new_val);
- PQfreemem(escaped);
- }
- }
- } ZEND_HASH_FOREACH_END(); /* for */
- zval_ptr_dtor(&meta);
- if (err) {
- /* shouldn't destroy & free zval here */
- return FAILURE;
- }
- return SUCCESS;
- }
- /* }}} */
- /* {{{ Check and convert values for PostgreSQL SQL statement */
- PHP_FUNCTION(pg_convert)
- {
- zval *pgsql_link, *values;
- pgsql_link_handle *link;
- zend_string *table_name;
- zend_ulong option = 0;
- PGconn *pg_link;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "OPa|l", &pgsql_link, pgsql_link_ce, &table_name, &values, &option) == FAILURE) {
- RETURN_THROWS();
- }
- if (ZSTR_LEN(table_name) == 0) {
- zend_argument_value_error(2, "cannot be empty");
- RETURN_THROWS();
- }
- if (option & ~PGSQL_CONV_OPTS) {
- zend_argument_value_error(4, "must be a valid bit mask of PGSQL_CONV_IGNORE_DEFAULT, "
- "PGSQL_CONV_FORCE_NULL, and PGSQL_CONV_IGNORE_NOT_NULL");
- RETURN_THROWS();
- }
- link = Z_PGSQL_LINK_P(pgsql_link);
- CHECK_PGSQL_LINK(link);
- pg_link = link->conn;
- if (php_pgsql_flush_query(pg_link)) {
- php_error_docref(NULL, E_NOTICE, "Detected unhandled result(s) in connection");
- }
- array_init(return_value);
- if (php_pgsql_convert(pg_link, table_name, values, return_value, option) == FAILURE) {
- zend_array_destroy(Z_ARR_P(return_value));
- RETURN_FALSE;
- }
- }
- /* }}} */
- static bool do_exec(smart_str *querystr, ExecStatusType expect, PGconn *pg_link, zend_ulong opt) /* {{{ */
- {
- if (opt & PGSQL_DML_ASYNC) {
- if (PQsendQuery(pg_link, ZSTR_VAL(querystr->s))) {
- return true;
- }
- } else {
- PGresult *pg_result;
- pg_result = PQexec(pg_link, ZSTR_VAL(querystr->s));
- if (PQresultStatus(pg_result) == expect) {
- PQclear(pg_result);
- return true;
- } else {
- php_error_docref(NULL, E_WARNING, "%s", PQresultErrorMessage(pg_result));
- PQclear(pg_result);
- }
- }
- return false;
- }
- /* }}} */
- static inline void build_tablename(smart_str *querystr, PGconn *pg_link, const zend_string *table) /* {{{ */
- {
- /* schema.table should be "schema"."table" */
- const char *dot = memchr(ZSTR_VAL(table), '.', ZSTR_LEN(table));
- size_t len = dot ? dot - ZSTR_VAL(table) : ZSTR_LEN(table);
- if (_php_pgsql_identifier_is_escaped(ZSTR_VAL(table), len)) {
- smart_str_appendl(querystr, ZSTR_VAL(table), len);
- } else {
- char *escaped = PQescapeIdentifier(pg_link, ZSTR_VAL(table), len);
- smart_str_appends(querystr, escaped);
- PQfreemem(escaped);
- }
- if (dot) {
- const char *after_dot = dot + 1;
- len = ZSTR_LEN(table) - len - 1;
- /* "schema"."table" format */
- if (_php_pgsql_identifier_is_escaped(after_dot, len)) {
- smart_str_appendc(querystr, '.');
- smart_str_appendl(querystr, after_dot, len);
- } else {
- char *escaped = PQescapeIdentifier(pg_link, after_dot, len);
- smart_str_appendc(querystr, '.');
- smart_str_appends(querystr, escaped);
- PQfreemem(escaped);
- }
- }
- }
- /* }}} */
- /* {{{ php_pgsql_insert */
- PHP_PGSQL_API zend_result php_pgsql_insert(PGconn *pg_link, const zend_string *table, zval *var_array, zend_ulong opt, zend_string **sql)
- {
- zval *val, converted;
- char buf[256];
- char *tmp;
- smart_str querystr = {0};
- zend_result ret = FAILURE;
- zend_string *fld;
- ZEND_ASSERT(pg_link != NULL);
- ZEND_ASSERT(table != NULL);
- ZEND_ASSERT(Z_TYPE_P(var_array) == IS_ARRAY);
- ZVAL_UNDEF(&converted);
- if (zend_hash_num_elements(Z_ARRVAL_P(var_array)) == 0) {
- smart_str_appends(&querystr, "INSERT INTO ");
- build_tablename(&querystr, pg_link, table);
- smart_str_appends(&querystr, " DEFAULT VALUES");
- goto no_values;
- }
- /* convert input array if needed */
- if (!(opt & (PGSQL_DML_NO_CONV|PGSQL_DML_ESCAPE))) {
- array_init(&converted);
- if (php_pgsql_convert(pg_link, table, var_array, &converted, (opt & PGSQL_CONV_OPTS)) == FAILURE) {
- goto cleanup;
- }
- var_array = &converted;
- }
- smart_str_appends(&querystr, "INSERT INTO ");
- build_tablename(&querystr, pg_link, table);
- smart_str_appends(&querystr, " (");
- ZEND_HASH_FOREACH_STR_KEY(Z_ARRVAL_P(var_array), fld) {
- if (fld == NULL) {
- zend_value_error("Array of values must be an associative array with string keys");
- goto cleanup;
- }
- if (opt & PGSQL_DML_ESCAPE) {
- tmp = PQescapeIdentifier(pg_link, ZSTR_VAL(fld), ZSTR_LEN(fld) + 1);
- smart_str_appends(&querystr, tmp);
- PQfreemem(tmp);
- } else {
- smart_str_append(&querystr, fld);
- }
- smart_str_appendc(&querystr, ',');
- } ZEND_HASH_FOREACH_END();
- ZSTR_LEN(querystr.s)--;
- smart_str_appends(&querystr, ") VALUES (");
- /* make values string */
- ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(var_array), val) {
- /* we can avoid the key_type check here, because we tested it in the other loop */
- switch (Z_TYPE_P(val)) {
- case IS_STRING:
- if (opt & PGSQL_DML_ESCAPE) {
- size_t new_len;
- char *tmp;
- tmp = (char *)safe_emalloc(Z_STRLEN_P(val), 2, 1);
- new_len = PQescapeStringConn(pg_link, tmp, Z_STRVAL_P(val), Z_STRLEN_P(val), NULL);
- smart_str_appendc(&querystr, '\'');
- smart_str_appendl(&querystr, tmp, new_len);
- smart_str_appendc(&querystr, '\'');
- efree(tmp);
- } else {
- smart_str_append(&querystr, Z_STR_P(val));
- }
- break;
- case IS_LONG:
- smart_str_append_long(&querystr, Z_LVAL_P(val));
- break;
- case IS_DOUBLE:
- smart_str_appendl(&querystr, buf, snprintf(buf, sizeof(buf), "%F", Z_DVAL_P(val)));
- break;
- case IS_NULL:
- smart_str_appendl(&querystr, "NULL", sizeof("NULL")-1);
- break;
- default:
- zend_type_error("Value must be of type string|int|float|null, %s given", zend_zval_type_name(val));
- goto cleanup;
- }
- smart_str_appendc(&querystr, ',');
- } ZEND_HASH_FOREACH_END();
- /* Remove the trailing "," */
- ZSTR_LEN(querystr.s)--;
- smart_str_appends(&querystr, ");");
- no_values:
- smart_str_0(&querystr);
- if ((opt & (PGSQL_DML_EXEC|PGSQL_DML_ASYNC)) &&
- do_exec(&querystr, PGRES_COMMAND_OK, pg_link, (opt & PGSQL_CONV_OPTS))) {
- ret = SUCCESS;
- }
- else if (opt & PGSQL_DML_STRING) {
- ret = SUCCESS;
- }
- cleanup:
- zval_ptr_dtor(&converted);
- if (ret == SUCCESS && (opt & PGSQL_DML_STRING)) {
- *sql = querystr.s;
- }
- else {
- smart_str_free(&querystr);
- }
- return ret;
- }
- /* }}} */
- /* {{{ Insert values (filed=>value) to table */
- PHP_FUNCTION(pg_insert)
- {
- zval *pgsql_link, *values;
- pgsql_link_handle *link;
- zend_string *table;
- zend_ulong option = PGSQL_DML_EXEC, return_sql;
- PGconn *pg_link;
- PGresult *pg_result;
- ExecStatusType status;
- zend_string *sql = NULL;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "OPa|l",
- &pgsql_link, pgsql_link_ce, &table, &values, &option) == FAILURE
- ) {
- RETURN_THROWS();
- }
- if (ZSTR_LEN(table) == 0) {
- zend_argument_value_error(2, "cannot be empty");
- RETURN_THROWS();
- }
- if (option & ~(PGSQL_CONV_OPTS|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_ASYNC|PGSQL_DML_STRING|PGSQL_DML_ESCAPE)) {
- zend_argument_value_error(4, "must be a valid bit mask of PGSQL_CONV_FORCE_NULL, PGSQL_DML_NO_CONV, "
- "PGSQL_DML_ESCAPE, PGSQL_DML_EXEC, PGSQL_DML_ASYNC, and PGSQL_DML_STRING");
- RETURN_THROWS();
- }
- link = Z_PGSQL_LINK_P(pgsql_link);
- CHECK_PGSQL_LINK(link);
- pg_link = link->conn;
- if (php_pgsql_flush_query(pg_link)) {
- php_error_docref(NULL, E_NOTICE, "Detected unhandled result(s) in connection");
- }
- return_sql = option & PGSQL_DML_STRING;
- if (option & PGSQL_DML_EXEC) {
- /* return object when executed */
- option = option & ~PGSQL_DML_EXEC;
- if (php_pgsql_insert(pg_link, table, values, option|PGSQL_DML_STRING, &sql) == FAILURE) {
- RETURN_FALSE;
- }
- pg_result = PQexec(pg_link, ZSTR_VAL(sql));
- if ((PGG(auto_reset_persistent) & 2) && PQstatus(pg_link) != CONNECTION_OK) {
- PQclear(pg_result);
- PQreset(pg_link);
- pg_result = PQexec(pg_link, ZSTR_VAL(sql));
- }
- efree(sql);
- if (pg_result) {
- status = PQresultStatus(pg_result);
- } else {
- status = (ExecStatusType) PQstatus(pg_link);
- }
- switch (status) {
- case PGRES_EMPTY_QUERY:
- case PGRES_BAD_RESPONSE:
- case PGRES_NONFATAL_ERROR:
- case PGRES_FATAL_ERROR:
- PHP_PQ_ERROR("Query failed: %s", pg_link);
- PQclear(pg_result);
- RETURN_FALSE;
- break;
- case PGRES_COMMAND_OK: /* successful command that did not return rows */
- default:
- if (pg_result) {
- object_init_ex(return_value, pgsql_result_ce);
- pgsql_result_handle *pg_res = Z_PGSQL_RESULT_P(return_value);
- pg_res->conn = pg_link;
- pg_res->result = pg_result;
- pg_res->row = 0;
- return;
- } else {
- PQclear(pg_result);
- RETURN_FALSE;
- }
- break;
- }
- } else if (php_pgsql_insert(pg_link, table, values, option, &sql) == FAILURE) {
- RETURN_FALSE;
- }
- if (return_sql) {
- RETURN_STR(sql);
- return;
- }
- RETURN_TRUE;
- }
- /* }}} */
- static inline int build_assignment_string(PGconn *pg_link, smart_str *querystr, HashTable *ht, int where_cond, const char *pad, int pad_len, zend_ulong opt) /* {{{ */
- {
- zend_string *fld;
- zval *val;
- ZEND_HASH_FOREACH_STR_KEY_VAL(ht, fld, val) {
- if (fld == NULL) {
- zend_value_error("Array of values must be an associative array with string keys");
- return -1;
- }
- if (opt & PGSQL_DML_ESCAPE) {
- char *tmp = PQescapeIdentifier(pg_link, ZSTR_VAL(fld), ZSTR_LEN(fld) + 1);
- smart_str_appends(querystr, tmp);
- PQfreemem(tmp);
- } else {
- smart_str_append(querystr, fld);
- }
- if (where_cond && (Z_TYPE_P(val) == IS_TRUE || Z_TYPE_P(val) == IS_FALSE ||
- (Z_TYPE_P(val) == IS_STRING && zend_string_equals_literal(Z_STR_P(val), "NULL")))) {
- smart_str_appends(querystr, " IS ");
- } else {
- smart_str_appendc(querystr, '=');
- }
- switch (Z_TYPE_P(val)) {
- case IS_STRING:
- if (opt & PGSQL_DML_ESCAPE) {
- char *tmp = (char *)safe_emalloc(Z_STRLEN_P(val), 2, 1);
- size_t new_len = PQescapeStringConn(pg_link, tmp, Z_STRVAL_P(val), Z_STRLEN_P(val), NULL);
- smart_str_appendc(querystr, '\'');
- smart_str_appendl(querystr, tmp, new_len);
- smart_str_appendc(querystr, '\'');
- efree(tmp);
- } else {
- smart_str_append(querystr, Z_STR_P(val));
- }
- break;
- case IS_LONG:
- smart_str_append_long(querystr, Z_LVAL_P(val));
- break;
- case IS_DOUBLE: {
- char buf[256];
- smart_str_appendl(querystr, buf, MIN(snprintf(buf, sizeof(buf), "%F", Z_DVAL_P(val)), sizeof(buf) - 1));
- }
- break;
- case IS_NULL:
- smart_str_appendl(querystr, "NULL", sizeof("NULL")-1);
- break;
- default:
- zend_type_error("Value must be of type string|int|float|null, %s given", zend_zval_type_name(val));
- return -1;
- }
- smart_str_appendl(querystr, pad, pad_len);
- } ZEND_HASH_FOREACH_END();
- if (querystr->s) {
- ZSTR_LEN(querystr->s) -= pad_len;
- }
- return 0;
- }
- /* }}} */
- /* {{{ php_pgsql_update */
- PHP_PGSQL_API zend_result php_pgsql_update(PGconn *pg_link, const zend_string *table, zval *var_array, zval *ids_array, zend_ulong opt, zend_string **sql)
- {
- zval var_converted, ids_converted;
- smart_str querystr = {0};
- zend_result ret = FAILURE;
- ZEND_ASSERT(pg_link != NULL);
- ZEND_ASSERT(table != NULL);
- ZEND_ASSERT(Z_TYPE_P(var_array) == IS_ARRAY);
- ZEND_ASSERT(Z_TYPE_P(ids_array) == IS_ARRAY);
- ZEND_ASSERT(!(opt & ~(PGSQL_CONV_OPTS|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_STRING|PGSQL_DML_ESCAPE)));
- if (zend_hash_num_elements(Z_ARRVAL_P(var_array)) == 0
- || zend_hash_num_elements(Z_ARRVAL_P(ids_array)) == 0) {
- return FAILURE;
- }
- ZVAL_UNDEF(&var_converted);
- ZVAL_UNDEF(&ids_converted);
- if (!(opt & (PGSQL_DML_NO_CONV|PGSQL_DML_ESCAPE))) {
- array_init(&var_converted);
- if (php_pgsql_convert(pg_link, table, var_array, &var_converted, (opt & PGSQL_CONV_OPTS)) == FAILURE) {
- goto cleanup;
- }
- var_array = &var_converted;
- array_init(&ids_converted);
- if (php_pgsql_convert(pg_link, table, ids_array, &ids_converted, (opt & PGSQL_CONV_OPTS)) == FAILURE) {
- goto cleanup;
- }
- ids_array = &ids_converted;
- }
- smart_str_appends(&querystr, "UPDATE ");
- build_tablename(&querystr, pg_link, table);
- smart_str_appends(&querystr, " SET ");
- if (build_assignment_string(pg_link, &querystr, Z_ARRVAL_P(var_array), 0, ",", 1, opt))
- goto cleanup;
- smart_str_appends(&querystr, " WHERE ");
- if (build_assignment_string(pg_link, &querystr, Z_ARRVAL_P(ids_array), 1, " AND ", sizeof(" AND ")-1, opt))
- goto cleanup;
- smart_str_appendc(&querystr, ';');
- smart_str_0(&querystr);
- if ((opt & PGSQL_DML_EXEC) && do_exec(&querystr, PGRES_COMMAND_OK, pg_link, opt)) {
- ret = SUCCESS;
- } else if (opt & PGSQL_DML_STRING) {
- ret = SUCCESS;
- }
- cleanup:
- zval_ptr_dtor(&var_converted);
- zval_ptr_dtor(&ids_converted);
- if (ret == SUCCESS && (opt & PGSQL_DML_STRING)) {
- *sql = querystr.s;
- }
- else {
- smart_str_free(&querystr);
- }
- return ret;
- }
- /* }}} */
- /* {{{ Update table using values (field=>value) and ids (id=>value) */
- PHP_FUNCTION(pg_update)
- {
- zval *pgsql_link, *values, *ids;
- pgsql_link_handle *link;
- zend_string *table;
- zend_ulong option = PGSQL_DML_EXEC;
- PGconn *pg_link;
- zend_string *sql = NULL;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "OPaa|l",
- &pgsql_link, pgsql_link_ce, &table, &values, &ids, &option) == FAILURE
- ) {
- RETURN_THROWS();
- }
- if (ZSTR_LEN(table) == 0) {
- zend_argument_value_error(2, "cannot be empty");
- RETURN_THROWS();
- }
- if (option & ~(PGSQL_CONV_OPTS|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_STRING|PGSQL_DML_ESCAPE)) {
- zend_argument_value_error(5, "must be a valid bit mask of PGSQL_CONV_FORCE_NULL, PGSQL_DML_NO_CONV, "
- "PGSQL_DML_ESCAPE, PGSQL_DML_EXEC, PGSQL_DML_ASYNC, and PGSQL_DML_STRING");
- RETURN_THROWS();
- }
- link = Z_PGSQL_LINK_P(pgsql_link);
- CHECK_PGSQL_LINK(link);
- pg_link = link->conn;
- if (php_pgsql_flush_query(pg_link)) {
- php_error_docref(NULL, E_NOTICE, "Detected unhandled result(s) in connection");
- }
- if (php_pgsql_update(pg_link, table, values, ids, option, &sql) == FAILURE) {
- RETURN_FALSE;
- }
- if (option & PGSQL_DML_STRING) {
- RETURN_STR(sql);
- }
- RETURN_TRUE;
- }
- /* }}} */
- /* {{{ php_pgsql_delete */
- PHP_PGSQL_API zend_result php_pgsql_delete(PGconn *pg_link, const zend_string *table, zval *ids_array, zend_ulong opt, zend_string **sql)
- {
- zval ids_converted;
- smart_str querystr = {0};
- zend_result ret = FAILURE;
- ZEND_ASSERT(pg_link != NULL);
- ZEND_ASSERT(table != NULL);
- ZEND_ASSERT(Z_TYPE_P(ids_array) == IS_ARRAY);
- ZEND_ASSERT(!(opt & ~(PGSQL_CONV_FORCE_NULL|PGSQL_DML_EXEC|PGSQL_DML_STRING|PGSQL_DML_ESCAPE)));
- if (zend_hash_num_elements(Z_ARRVAL_P(ids_array)) == 0) {
- return FAILURE;
- }
- ZVAL_UNDEF(&ids_converted);
- if (!(opt & (PGSQL_DML_NO_CONV|PGSQL_DML_ESCAPE))) {
- array_init(&ids_converted);
- if (php_pgsql_convert(pg_link, table, ids_array, &ids_converted, (opt & PGSQL_CONV_OPTS)) == FAILURE) {
- goto cleanup;
- }
- ids_array = &ids_converted;
- }
- smart_str_appends(&querystr, "DELETE FROM ");
- build_tablename(&querystr, pg_link, table);
- smart_str_appends(&querystr, " WHERE ");
- if (build_assignment_string(pg_link, &querystr, Z_ARRVAL_P(ids_array), 1, " AND ", sizeof(" AND ")-1, opt))
- goto cleanup;
- smart_str_appendc(&querystr, ';');
- smart_str_0(&querystr);
- if ((opt & PGSQL_DML_EXEC) && do_exec(&querystr, PGRES_COMMAND_OK, pg_link, opt)) {
- ret = SUCCESS;
- } else if (opt & PGSQL_DML_STRING) {
- ret = SUCCESS;
- }
- cleanup:
- zval_ptr_dtor(&ids_converted);
- if (ret == SUCCESS && (opt & PGSQL_DML_STRING)) {
- *sql = querystr.s;
- }
- else {
- smart_str_free(&querystr);
- }
- return ret;
- }
- /* }}} */
- /* {{{ Delete records has ids (id=>value) */
- PHP_FUNCTION(pg_delete)
- {
- zval *pgsql_link, *ids;
- pgsql_link_handle *link;
- zend_string *table;
- zend_ulong option = PGSQL_DML_EXEC;
- PGconn *pg_link;
- zend_string *sql;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "OPa|l",
- &pgsql_link, pgsql_link_ce, &table, &ids, &option
- ) == FAILURE) {
- RETURN_THROWS();
- }
- if (ZSTR_LEN(table) == 0) {
- zend_argument_value_error(2, "cannot be empty");
- RETURN_THROWS();
- }
- if (option & ~(PGSQL_CONV_FORCE_NULL|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_STRING|PGSQL_DML_ESCAPE)) {
- zend_argument_value_error(4, "must be a valid bit mask of PGSQL_CONV_FORCE_NULL, PGSQL_DML_NO_CONV, "
- "PGSQL_DML_ESCAPE, PGSQL_DML_EXEC, PGSQL_DML_ASYNC, and PGSQL_DML_STRING");
- RETURN_THROWS();
- }
- link = Z_PGSQL_LINK_P(pgsql_link);
- CHECK_PGSQL_LINK(link);
- pg_link = link->conn;
- if (php_pgsql_flush_query(pg_link)) {
- php_error_docref(NULL, E_NOTICE, "Detected unhandled result(s) in connection");
- }
- if (php_pgsql_delete(pg_link, table, ids, option, &sql) == FAILURE) {
- RETURN_FALSE;
- }
- if (option & PGSQL_DML_STRING) {
- RETURN_STR(sql);
- }
- RETURN_TRUE;
- }
- /* }}} */
- /* {{{ php_pgsql_result2array */
- PHP_PGSQL_API void php_pgsql_result2array(PGresult *pg_result, zval *ret_array, long result_type)
- {
- zval row;
- char *field_name;
- size_t num_fields;
- int pg_numrows, pg_row;
- uint32_t i;
- ZEND_ASSERT(Z_TYPE_P(ret_array) == IS_ARRAY);
- pg_numrows = PQntuples(pg_result);
- for (pg_row = 0; pg_row < pg_numrows; pg_row++) {
- array_init(&row);
- for (i = 0, num_fields = PQnfields(pg_result); i < num_fields; i++) {
- field_name = PQfname(pg_result, i);
- if (PQgetisnull(pg_result, pg_row, i)) {
- if (result_type & PGSQL_ASSOC) {
- add_assoc_null(&row, field_name);
- }
- if (result_type & PGSQL_NUM) {
- add_next_index_null(&row);
- }
- } else {
- char *element = PQgetvalue(pg_result, pg_row, i);
- if (element) {
- const size_t element_len = strlen(element);
- if (result_type & PGSQL_ASSOC) {
- add_assoc_stringl(&row, field_name, element, element_len);
- }
- if (result_type & PGSQL_NUM) {
- add_next_index_stringl(&row, element, element_len);
- }
- }
- }
- }
- add_index_zval(ret_array, pg_row, &row);
- }
- }
- /* }}} */
- /* {{{ php_pgsql_select */
- PHP_PGSQL_API zend_result php_pgsql_select(PGconn *pg_link, const zend_string *table, zval *ids_array, zval *ret_array, zend_ulong opt, long result_type, zend_string **sql)
- {
- zval ids_converted;
- smart_str querystr = {0};
- zend_result ret = FAILURE;
- PGresult *pg_result;
- ZEND_ASSERT(pg_link != NULL);
- ZEND_ASSERT(table != NULL);
- ZEND_ASSERT(Z_TYPE_P(ids_array) == IS_ARRAY);
- ZEND_ASSERT(Z_TYPE_P(ret_array) == IS_ARRAY);
- ZEND_ASSERT(!(opt & ~(PGSQL_CONV_OPTS|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_ASYNC|PGSQL_DML_STRING|PGSQL_DML_ESCAPE)));
- if (zend_hash_num_elements(Z_ARRVAL_P(ids_array)) == 0) {
- return FAILURE;
- }
- ZVAL_UNDEF(&ids_converted);
- if (!(opt & (PGSQL_DML_NO_CONV|PGSQL_DML_ESCAPE))) {
- array_init(&ids_converted);
- if (php_pgsql_convert(pg_link, table, ids_array, &ids_converted, (opt & PGSQL_CONV_OPTS)) == FAILURE) {
- goto cleanup;
- }
- ids_array = &ids_converted;
- }
- smart_str_appends(&querystr, "SELECT * FROM ");
- build_tablename(&querystr, pg_link, table);
- smart_str_appends(&querystr, " WHERE ");
- if (build_assignment_string(pg_link, &querystr, Z_ARRVAL_P(ids_array), 1, " AND ", sizeof(" AND ")-1, opt))
- goto cleanup;
- smart_str_appendc(&querystr, ';');
- smart_str_0(&querystr);
- pg_result = PQexec(pg_link, ZSTR_VAL(querystr.s));
- if (PQresultStatus(pg_result) == PGRES_TUPLES_OK) {
- php_pgsql_result2array(pg_result, ret_array, result_type);
- ret = SUCCESS;
- } else {
- php_error_docref(NULL, E_NOTICE, "Failed to execute '%s'", ZSTR_VAL(querystr.s));
- }
- PQclear(pg_result);
- cleanup:
- zval_ptr_dtor(&ids_converted);
- if (ret == SUCCESS && (opt & PGSQL_DML_STRING)) {
- *sql = querystr.s;
- }
- else {
- smart_str_free(&querystr);
- }
- return ret;
- }
- /* }}} */
- /* {{{ Select records that has ids (id=>value) */
- PHP_FUNCTION(pg_select)
- {
- zval *pgsql_link, *ids;
- pgsql_link_handle *link;
- zend_string *table;
- zend_ulong option = PGSQL_DML_EXEC;
- zend_long result_type = PGSQL_ASSOC;
- PGconn *pg_link;
- zend_string *sql = NULL;
- /* TODO Document result_type param on php.net (apparently it was added in PHP 7.1) */
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "OPa|ll",
- &pgsql_link, pgsql_link_ce, &table, &ids, &option, &result_type
- ) == FAILURE) {
- RETURN_THROWS();
- }
- if (ZSTR_LEN(table) == 0) {
- zend_argument_value_error(2, "cannot be empty");
- RETURN_THROWS();
- }
- if (option & ~(PGSQL_CONV_FORCE_NULL|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_ASYNC|PGSQL_DML_STRING|PGSQL_DML_ESCAPE)) {
- zend_argument_value_error(4, "must be a valid bit mask of PGSQL_CONV_FORCE_NULL, PGSQL_DML_NO_CONV, "
- "PGSQL_DML_ESCAPE, PGSQL_DML_EXEC, PGSQL_DML_ASYNC, and PGSQL_DML_STRING");
- RETURN_THROWS();
- }
- if (!(result_type & PGSQL_BOTH)) {
- zend_argument_value_error(5, "must be one of PGSQL_ASSOC, PGSQL_NUM, or PGSQL_BOTH");
- RETURN_THROWS();
- }
- link = Z_PGSQL_LINK_P(pgsql_link);
- CHECK_PGSQL_LINK(link);
- pg_link = link->conn;
- if (php_pgsql_flush_query(pg_link)) {
- php_error_docref(NULL, E_NOTICE, "Detected unhandled result(s) in connection");
- }
- array_init(return_value);
- if (php_pgsql_select(pg_link, table, ids, return_value, option, result_type, &sql) == FAILURE) {
- zval_ptr_dtor(return_value);
- RETURN_FALSE;
- }
- if (option & PGSQL_DML_STRING) {
- zval_ptr_dtor(return_value);
- RETURN_STR(sql);
- }
- return;
- }
- /* }}} */
- #endif
|