PNG  IHDRQgAMA a cHRMz&u0`:pQ<bKGDgmIDATxwUﹻ& ^CX(J I@ "% (** BX +*i"]j(IH{~R)[~>h{}gy)I$Ij .I$I$ʊy@}x.: $I$Ii}VZPC)I$IF ^0ʐJ$I$Q^}{"r=OzI$gRZeC.IOvH eKX $IMpxsk.쒷/&r[޳<v| .I~)@$updYRa$I |M.e JaֶpSYR6j>h%IRز if&uJ)M$I vLi=H;7UJ,],X$I1AҒJ$ XY XzI@GNҥRT)E@;]K*Mw;#5_wOn~\ DC&$(A5 RRFkvIR}l!RytRl;~^ǷJj اy뷦BZJr&ӥ8Pjw~vnv X^(I;4R=P[3]J,]ȏ~:3?[ a&e)`e*P[4]T=Cq6R[ ~ޤrXR Հg(t_HZ-Hg M$ãmL5R uk*`%C-E6/%[t X.{8P9Z.vkXŐKjgKZHg(aK9ڦmKjѺm_ \#$5,)-  61eJ,5m| r'= &ڡd%-]J on Xm|{ RҞe $eڧY XYrԮ-a7RK6h>n$5AVڴi*ֆK)mѦtmr1p| q:흺,)Oi*ֺK)ܬ֦K-5r3>0ԔHjJئEZj,%re~/z%jVMڸmrt)3]J,T K֦OvԒgii*bKiNO~%PW0=dii2tJ9Jݕ{7"I P9JKTbu,%r"6RKU}Ij2HKZXJ,妝 XYrP ެ24c%i^IK|.H,%rb:XRl1X4Pe/`x&P8Pj28Mzsx2r\zRPz4J}yP[g=L) .Q[6RjWgp FIH*-`IMRaK9TXcq*I y[jE>cw%gLRԕiFCj-ďa`#e~I j,%r,)?[gp FI˨mnWX#>mʔ XA DZf9,nKҲzIZXJ,L#kiPz4JZF,I,`61%2s $,VOϚ2/UFJfy7K> X+6 STXIeJILzMfKm LRaK9%|4p9LwJI!`NsiazĔ)%- XMq>pk$-$Q2x#N ؎-QR}ᶦHZډ)J,l#i@yn3LN`;nڔ XuX5pF)m|^0(>BHF9(cզEerJI rg7 4I@z0\JIi䵙RR0s;$s6eJ,`n 䂦0a)S)A 1eJ,堌#635RIgpNHuTH_SԕqVe ` &S)>p;S$魁eKIuX`I4춒o}`m$1":PI<[v9^\pTJjriRŭ P{#{R2,`)e-`mgj~1ϣLKam7&U\j/3mJ,`F;M'䱀 .KR#)yhTq;pcK9(q!w?uRR,n.yw*UXj#\]ɱ(qv2=RqfB#iJmmL<]Y͙#$5 uTU7ӦXR+q,`I}qL'`6Kͷ6r,]0S$- [RKR3oiRE|nӦXR.(i:LDLTJjY%o:)6rxzҒqTJjh㞦I.$YR.ʼnGZ\ֿf:%55 I˼!6dKxm4E"mG_ s? .e*?LRfK9%q#uh$)i3ULRfK9yxm܌bj84$i1U^@Wbm4uJ,ҪA>_Ij?1v32[gLRD96oTaR׿N7%L2 NT,`)7&ƝL*꽙yp_$M2#AS,`)7$rkTA29_Iye"|/0t)$n XT2`YJ;6Jx".e<`$) PI$5V4]29SRI>~=@j]lp2`K9Jaai^" Ԋ29ORI%:XV5]JmN9]H;1UC39NI%Xe78t)a;Oi Ҙ>Xt"~G>_mn:%|~ޅ_+]$o)@ǀ{hgN;IK6G&rp)T2i୦KJuv*T=TOSV>(~D>dm,I*Ɛ:R#ۙNI%D>G.n$o;+#RR!.eU˽TRI28t)1LWϚ>IJa3oFbu&:tJ*(F7y0ZR ^p'Ii L24x| XRI%ۄ>S1]Jy[zL$adB7.eh4%%누>WETf+3IR:I3Xה)3אOۦSRO'ٺ)S}"qOr[B7ϙ.edG)^ETR"RtRݜh0}LFVӦDB^k_JDj\=LS(Iv─aTeZ%eUAM-0;~˃@i|l @S4y72>sX-vA}ϛBI!ݎߨWl*)3{'Y|iSlEڻ(5KtSI$Uv02,~ԩ~x;P4ցCrO%tyn425:KMlD ^4JRxSهF_}شJTS6uj+ﷸk$eZO%G*^V2u3EMj3k%)okI]dT)URKDS 7~m@TJR~荪fT"֛L \sM -0T KfJz+nإKr L&j()[E&I ߴ>e FW_kJR|!O:5/2跌3T-'|zX ryp0JS ~^F>-2< `*%ZFP)bSn"L :)+pʷf(pO3TMW$~>@~ū:TAIsV1}S2<%ޟM?@iT ,Eūoz%i~g|`wS(]oȤ8)$ ntu`өe`6yPl IzMI{ʣzʨ )IZ2= ld:5+請M$-ї;U>_gsY$ÁN5WzWfIZ)-yuXIfp~S*IZdt;t>KūKR|$#LcԀ+2\;kJ`]YǔM1B)UbG"IRߊ<xܾӔJ0Z='Y嵤 Leveg)$znV-º^3Ւof#0Tfk^Zs[*I꯳3{)ˬW4Ւ4 OdpbZRS|*I 55#"&-IvT&/윚Ye:i$ 9{LkuRe[I~_\ؠ%>GL$iY8 9ܕ"S`kS.IlC;Ҏ4x&>u_0JLr<J2(^$5L s=MgV ~,Iju> 7r2)^=G$1:3G< `J3~&IR% 6Tx/rIj3O< ʔ&#f_yXJiގNSz; Tx(i8%#4 ~AS+IjerIUrIj362v885+IjAhK__5X%nV%Iͳ-y|7XV2v4fzo_68"S/I-qbf; LkF)KSM$ Ms>K WNV}^`-큧32ŒVؙGdu,^^m%6~Nn&͓3ŒVZMsRpfEW%IwdǀLm[7W&bIRL@Q|)* i ImsIMmKmyV`i$G+R 0tV'!V)֏28vU7͒vHꦼtxꗞT ;S}7Mf+fIRHNZUkUx5SAJㄌ9MqμAIRi|j5)o*^'<$TwI1hEU^c_j?Е$%d`z cyf,XO IJnTgA UXRD }{H}^S,P5V2\Xx`pZ|Yk:$e ~ @nWL.j+ϝYb퇪bZ BVu)u/IJ_ 1[p.p60bC >|X91P:N\!5qUB}5a5ja `ubcVxYt1N0Zzl4]7­gKj]?4ϻ *[bg$)+À*x쳀ogO$~,5 زUS9 lq3+5mgw@np1sso Ӻ=|N6 /g(Wv7U;zωM=wk,0uTg_`_P`uz?2yI!b`kĸSo+Qx%!\οe|އԁKS-s6pu_(ֿ$i++T8=eY; צP+phxWQv*|p1. ά. XRkIQYP,drZ | B%wP|S5`~́@i޾ E;Չaw{o'Q?%iL{u D?N1BD!owPHReFZ* k_-~{E9b-~P`fE{AܶBJAFO wx6Rox5 K5=WwehS8 (JClJ~ p+Fi;ŗo+:bD#g(C"wA^ r.F8L;dzdIHUX݆ϞXg )IFqem%I4dj&ppT{'{HOx( Rk6^C٫O.)3:s(۳(Z?~ٻ89zmT"PLtw䥈5&b<8GZ-Y&K?e8,`I6e(֍xb83 `rzXj)F=l($Ij 2*(F?h(/9ik:I`m#p3MgLaKjc/U#n5S# m(^)=y=đx8ŬI[U]~SцA4p$-F i(R,7Cx;X=cI>{Km\ o(Tv2vx2qiiDJN,Ҏ!1f 5quBj1!8 rDFd(!WQl,gSkL1Bxg''՞^ǘ;pQ P(c_ IRujg(Wz bs#P­rz> k c&nB=q+ؔXn#r5)co*Ũ+G?7< |PQӣ'G`uOd>%Mctz# Ԫڞ&7CaQ~N'-P.W`Oedp03C!IZcIAMPUۀ5J<\u~+{9(FbbyAeBhOSܳ1 bÈT#ŠyDžs,`5}DC-`̞%r&ڙa87QWWp6e7 Rϫ/oY ꇅ Nܶըtc!LA T7V4Jsū I-0Pxz7QNF_iZgúWkG83 0eWr9 X]㾮݁#Jˢ C}0=3ݱtBi]_ &{{[/o[~ \q鯜00٩|cD3=4B_b RYb$óBRsf&lLX#M*C_L܄:gx)WΘsGSbuL rF$9';\4Ɍq'n[%p.Q`u hNb`eCQyQ|l_C>Lb꟟3hSb #xNxSs^ 88|Mz)}:](vbۢamŖ࿥ 0)Q7@0=?^k(*J}3ibkFn HjB׻NO z x}7p 0tfDX.lwgȔhԾŲ }6g E |LkLZteu+=q\Iv0쮑)QٵpH8/2?Σo>Jvppho~f>%bMM}\//":PTc(v9v!gոQ )UfVG+! 35{=x\2+ki,y$~A1iC6#)vC5^>+gǵ@1Hy٪7u;p psϰu/S <aʸGu'tD1ԝI<pg|6j'p:tպhX{o(7v],*}6a_ wXRk,O]Lܳ~Vo45rp"N5k;m{rZbΦ${#)`(Ŵg,;j%6j.pyYT?}-kBDc3qA`NWQū20/^AZW%NQ MI.X#P#,^Ebc&?XR tAV|Y.1!؅⨉ccww>ivl(JT~ u`ٵDm q)+Ri x/x8cyFO!/*!/&,7<.N,YDŽ&ܑQF1Bz)FPʛ?5d 6`kQձ λc؎%582Y&nD_$Je4>a?! ͨ|ȎWZSsv8 j(I&yj Jb5m?HWp=g}G3#|I,5v珿] H~R3@B[☉9Ox~oMy=J;xUVoj bUsl_35t-(ՃɼRB7U!qc+x4H_Qo֮$[GO<4`&č\GOc[.[*Af%mG/ ňM/r W/Nw~B1U3J?P&Y )`ѓZ1p]^l“W#)lWZilUQu`-m|xĐ,_ƪ|9i:_{*(3Gѧ}UoD+>m_?VPۅ15&}2|/pIOʵ> GZ9cmíتmnz)yߐbD >e}:) r|@R5qVSA10C%E_'^8cR7O;6[eKePGϦX7jb}OTGO^jn*媓7nGMC t,k31Rb (vyܴʭ!iTh8~ZYZp(qsRL ?b}cŨʊGO^!rPJO15MJ[c&~Z`"ѓޔH1C&^|Ш|rʼ,AwĴ?b5)tLU)F| &g٣O]oqSUjy(x<Ϳ3 .FSkoYg2 \_#wj{u'rQ>o;%n|F*O_L"e9umDds?.fuuQbIWz |4\0 sb;OvxOSs; G%T4gFRurj(֍ڑb uԖKDu1MK{1^ q; C=6\8FR艇!%\YÔU| 88m)֓NcLve C6z;o&X x59:q61Z(T7>C?gcļxѐ Z oo-08jہ x,`' ҔOcRlf~`jj".Nv+sM_]Zk g( UOPyεx%pUh2(@il0ݽQXxppx-NS( WO+轾 nFߢ3M<;z)FBZjciu/QoF 7R¥ ZFLF~#ȣߨ^<쩡ݛкvџ))ME>ώx4m#!-m!L;vv#~Y[đKmx9.[,UFS CVkZ +ߟrY٧IZd/ioi$%͝ب_ֶX3ܫhNU ZZgk=]=bbJS[wjU()*I =ώ:}-蹞lUj:1}MWm=̛ _ ¾,8{__m{_PVK^n3esw5ӫh#$-q=A̟> ,^I}P^J$qY~Q[ Xq9{#&T.^GVj__RKpn,b=`żY@^՝;z{paVKkQXj/)y TIc&F;FBG7wg ZZDG!x r_tƢ!}i/V=M/#nB8 XxЫ ^@CR<{䤭YCN)eKOSƟa $&g[i3.C6xrOc8TI;o hH6P&L{@q6[ Gzp^71j(l`J}]e6X☉#͕ ׈$AB1Vjh㭦IRsqFBjwQ_7Xk>y"N=MB0 ,C #o6MRc0|$)ف"1!ixY<B9mx `,tA>)5ػQ?jQ?cn>YZe Tisvh# GMމȇp:ԴVuږ8ɼH]C.5C!UV;F`mbBk LTMvPʍϤj?ԯ/Qr1NB`9s"s TYsz &9S%U԰> {<ؿSMxB|H\3@!U| k']$U+> |HHMLޢ?V9iD!-@x TIî%6Z*9X@HMW#?nN ,oe6?tQwڱ.]-y':mW0#!J82qFjH -`ѓ&M0u Uγmxϵ^-_\])@0Rt.8/?ٰCY]x}=sD3ojަЫNuS%U}ԤwHH>ڗjܷ_3gN q7[q2la*ArǓԖ+p8/RGM ]jacd(JhWko6ڎbj]i5Bj3+3!\j1UZLsLTv8HHmup<>gKMJj0@H%,W΃7R) ">c, xixј^ aܖ>H[i.UIHc U1=yW\=S*GR~)AF=`&2h`DzT󑓶J+?W+}C%P:|0H܆}-<;OC[~o.$~i}~HQ TvXΈr=b}$vizL4:ȰT|4~*!oXQR6Lk+#t/g lԁߖ[Jڶ_N$k*". xsxX7jRVbAAʯKҎU3)zSNN _'s?f)6X!%ssAkʱ>qƷb hg %n ~p1REGMHH=BJiy[<5 ǁJҖgKR*倳e~HUy)Ag,K)`Vw6bRR:qL#\rclK/$sh*$ 6덤 KԖc 3Z9=Ɣ=o>X Ώ"1 )a`SJJ6k(<c e{%kϊP+SL'TcMJWRm ŏ"w)qc ef꒵i?b7b('"2r%~HUS1\<(`1Wx9=8HY9m:X18bgD1u ~|H;K-Uep,, C1 RV.MR5άh,tWO8WC$ XRVsQS]3GJ|12 [vM :k#~tH30Rf-HYݺ-`I9%lIDTm\ S{]9gOڒMNCV\G*2JRŨ;Rҏ^ڽ̱mq1Eu?To3I)y^#jJw^Ńj^vvlB_⋌P4x>0$c>K†Aļ9s_VjTt0l#m>E-,,x,-W)سo&96RE XR.6bXw+)GAEvL)͞K4$p=Ũi_ѱOjb HY/+@θH9޼]Nԥ%n{ &zjT? Ty) s^ULlb,PiTf^<À] 62R^V7)S!nllS6~͝V}-=%* ʻ>G DnK<y&>LPy7'r=Hj 9V`[c"*^8HpcO8bnU`4JȪAƋ#1_\ XϘHPRgik(~G~0DAA_2p|J묭a2\NCr]M_0 ^T%e#vD^%xy-n}-E\3aS%yN!r_{ )sAw ڼp1pEAk~v<:`'ӭ^5 ArXOI驻T (dk)_\ PuA*BY]yB"l\ey hH*tbK)3 IKZ򹞋XjN n *n>k]X_d!ryBH ]*R 0(#'7 %es9??ښFC,ՁQPjARJ\Ρw K#jahgw;2$l*) %Xq5!U᢯6Re] |0[__64ch&_}iL8KEgҎ7 M/\`|.p,~`a=BR?xܐrQ8K XR2M8f ?`sgWS%" Ԉ 7R%$ N}?QL1|-эټwIZ%pvL3Hk>,ImgW7{E xPHx73RA @RS CC !\ȟ5IXR^ZxHл$Q[ŝ40 (>+ _C >BRt<,TrT {O/H+˟Pl6 I B)/VC<6a2~(XwV4gnXR ϱ5ǀHٻ?tw똤Eyxp{#WK qG%5],(0ӈH HZ])ג=K1j&G(FbM@)%I` XRg ʔ KZG(vP,<`[ Kn^ SJRsAʠ5xՅF`0&RbV tx:EaUE/{fi2;.IAwW8/tTxAGOoN?G}l L(n`Zv?pB8K_gI+ܗ #i?ޙ.) p$utc ~DžfՈEo3l/)I-U?aԅ^jxArA ΧX}DmZ@QLےbTXGd.^|xKHR{|ΕW_h] IJ`[G9{).y) 0X YA1]qp?p_k+J*Y@HI>^?gt.06Rn ,` ?);p pSF9ZXLBJPWjgQ|&)7! HjQt<| ؅W5 x W HIzYoVMGP Hjn`+\(dNW)F+IrS[|/a`K|ͻ0Hj{R,Q=\ (F}\WR)AgSG`IsnAR=|8$}G(vC$)s FBJ?]_u XRvύ6z ŨG[36-T9HzpW̞ú Xg큽=7CufzI$)ki^qk-) 0H*N` QZkk]/tnnsI^Gu't=7$ Z;{8^jB% IItRQS7[ϭ3 $_OQJ`7!]W"W,)Iy W AJA;KWG`IY{8k$I$^%9.^(`N|LJ%@$I}ֽp=FB*xN=gI?Q{٥4B)mw $Igc~dZ@G9K X?7)aK%݅K$IZ-`IpC U6$I\0>!9k} Xa IIS0H$I H ?1R.Чj:4~Rw@p$IrA*u}WjWFPJ$I➓/6#! LӾ+ X36x8J |+L;v$Io4301R20M I$-E}@,pS^ޟR[/s¹'0H$IKyfŸfVOπFT*a$I>He~VY/3R/)>d$I>28`Cjw,n@FU*9ttf$I~<;=/4RD~@ X-ѕzἱI$: ԍR a@b X{+Qxuq$IЛzo /~3\8ڒ4BN7$IҀj V]n18H$IYFBj3̵̚ja pp $Is/3R Ӻ-Yj+L;.0ŔI$Av? #!5"aʄj}UKmɽH$IjCYs?h$IDl843.v}m7UiI=&=0Lg0$I4: embe` eQbm0u? $IT!Sƍ'-sv)s#C0:XB2a w I$zbww{."pPzO =Ɔ\[ o($Iaw]`E).Kvi:L*#gР7[$IyGPI=@R 4yR~̮´cg I$I/<tPͽ hDgo 94Z^k盇΄8I56^W$I^0̜N?4*H`237}g+hxoq)SJ@p|` $I%>-hO0eO>\ԣNߌZD6R=K ~n($I$y3D>o4b#px2$yڪtzW~a $I~?x'BwwpH$IZݑnC㧄Pc_9sO gwJ=l1:mKB>Ab<4Lp$Ib o1ZQ@85b̍ S'F,Fe,^I$IjEdù{l4 8Ys_s Z8.x m"+{~?q,Z D!I$ϻ'|XhB)=…']M>5 rgotԎ 獽PH$IjIPhh)n#cÔqA'ug5qwU&rF|1E%I$%]!'3AFD/;Ck_`9 v!ٴtPV;x`'*bQa w I$Ix5 FC3D_~A_#O݆DvV?<qw+I$I{=Z8".#RIYyjǪ=fDl9%M,a8$I$Ywi[7ݍFe$s1ՋBVA?`]#!oz4zjLJo8$I$%@3jAa4(o ;p,,dya=F9ً[LSPH$IJYЉ+3> 5"39aZ<ñh!{TpBGkj}Sp $IlvF.F$I z< '\K*qq.f<2Y!S"-\I$IYwčjF$ w9 \ߪB.1v!Ʊ?+r:^!I$BϹB H"B;L'G[ 4U#5>੐)|#o0aڱ$I>}k&1`U#V?YsV x>{t1[I~D&(I$I/{H0fw"q"y%4 IXyE~M3 8XψL}qE$I[> nD?~sf ]o΁ cT6"?'_Ἣ $I>~.f|'!N?⟩0G KkXZE]ޡ;/&?k OۘH$IRۀwXӨ<7@PnS04aӶp.:@\IWQJ6sS%I$e5ڑv`3:x';wq_vpgHyXZ 3gЂ7{{EuԹn±}$I$8t;b|591nءQ"P6O5i }iR̈́%Q̄p!I䮢]O{H$IRϻ9s֧ a=`- aB\X0"+5"C1Hb?߮3x3&gşggl_hZ^,`5?ߎvĸ%̀M!OZC2#0x LJ0 Gw$I$I}<{Eb+y;iI,`ܚF:5ܛA8-O-|8K7s|#Z8a&><a&/VtbtLʌI$I$I$I$I$I$IRjDD%tEXtdate:create2022-05-31T04:40:26+00:00!Î%tEXtdate:modify2022-05-31T04:40:26+00:00|{2IENDB` sh-3ll

HOME


sh-3ll 1.0
DIR:/home/ami/.trash/guhisha ibyambere.1/maintenance/ecrire/base/
Upload File :
Current File : /home/ami/.trash/guhisha ibyambere.1/maintenance/ecrire/base/abstract_sql.php
<?php

/* *************************************************************************\
 *  SPIP, Systeme de publication pour l'internet                           *
 *                                                                         *
 *  Copyright (c) 2001-2016                                                *
 *  Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James  *
 *                                                                         *
 *  Ce programme est un logiciel libre distribue sous licence GNU/GPL.     *
 *  Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne.   *
\***************************************************************************/

/**
 * Definition de l'API SQL
 *
 * Ce fichier definit la couche d'abstraction entre SPIP et ses serveurs SQL.
 * Cette version 1 est un ensemble de fonctions ecrites rapidement
 * pour generaliser le code strictement MySQL de SPIP <= 1.9.2
 * Des retouches sont a prevoir apres l'experience des premiers portages.
 * Les symboles sql_* (constantes et nom de fonctions) sont reserves
 * a cette interface, sans quoi le gestionnaire de version dysfonctionnera.
 *
 * @package SPIP\Core\SQL\API
 * @version 1
 */

if (!defined('_ECRIRE_INC_VERSION')) {
	return;
}

/** Version de l'API SQL */
define('sql_ABSTRACT_VERSION', 1);
include_spip('base/connect_sql');

/**
 * Retourne la pile de fonctions utilisée lors de la précence d'une erreur SQL
 *
 * @note
 *     Ignore les fonctions `include_once`, `include_spip`, `find_in_path`
 * @param bool $compil_info
 *      - false : Retourne un texte présentant les fonctions utilisées
 *      - true : retourne un tableau indiquant un contexte de compilation à l'origine de la requête,
 *               utile pour présenter une erreur au débuggueur via `erreur_squelette()`
 * @return array|string
 *     contexte de l'erreur
 **/
function sql_error_backtrace($compil_info = false) {
	$trace = debug_backtrace();
	$caller = array_shift($trace);
	while (count($trace) and (empty($trace[0]['file']) or $trace[0]['file'] === $caller['file'] or $trace[0]['file'] === __FILE__)) {
		array_shift($trace);
	}

	if ($compil_info) {
		$contexte_compil = array(
			$trace[0]['file'],// sourcefile
			'', //nom
			(isset($trace[1]) ? $trace[1]['function'] . "(){\n" : '')
			. $trace[0]['function'] . "();"
			. (isset($trace[1]) ? "\n}" : ''), //id_boucle
			$trace[0]['line'], // ligne
			$GLOBALS['spip_lang'], // lang
		);

		return $contexte_compil;
	}

	$message = count($trace) ? $trace[0]['file'] . " L" . $trace[0]['line'] : "";
	$f = array();
	while (count($trace) and $t = array_shift($trace)) {
		if (in_array($t['function'], array('include_once', 'include_spip', 'find_in_path'))) {
			break;
		}
		$f[] = $t['function'];
	}
	if (count($f)) {
		$message .= " [" . implode("(),", $f) . "()]";
	}

	return $message;
}


/**
 * Charge le serveur de base de donnees
 *
 * Fonction principale. Elle charge l'interface au serveur de base de donnees
 * via la fonction spip_connect_version qui etablira la connexion au besoin.
 * Elle retourne la fonction produisant la requete SQL demandee
 * Erreur fatale si la fonctionnalite est absente sauf si le 3e arg <> false
 *
 * @internal Cette fonction de base est appelee par les autres fonctions sql_*
 * @param string $ins_sql
 *    Instruction de l'API SQL demandee (insertq, update, select...)
 * @param string $serveur
 *    Nom du connecteur ('' pour celui par defaut a l'installation de SPIP)
 * @param bool $continue
 *    true pour ne pas generer d'erreur si le serveur SQL ne dispose pas de la fonction demandee
 * @return string|array
 *    Nom de la fonction a appeler pour l'instruction demandee pour le type de serveur SQL correspondant au fichier de connexion.
 *    Si l'instruction demandee n'existe pas, retourne la liste de toutes les instructions du serveur SQL avec $continue a true.
 *
 **/
function sql_serveur($ins_sql = '', $serveur = '', $continue = false) {
	static $sql_serveur = array();
	if (!isset($sql_serveur[$serveur][$ins_sql])) {
		$f = spip_connect_sql(sql_ABSTRACT_VERSION, $ins_sql, $serveur, $continue);
		if (!is_string($f) or !$f) {
			return $f;
		}
		$sql_serveur[$serveur][$ins_sql] = $f;
	}

	return $sql_serveur[$serveur][$ins_sql];
}

/**
 * Demande si un charset est disponible
 *
 * Demande si un charset (tel que utf-8) est disponible
 * sur le gestionnaire de base de données de la connexion utilisée
 *
 * @api
 * @see sql_set_charset() pour utiliser un charset
 *
 * @param string $charset
 *     Le charset souhaité
 * @param string $serveur
 *     Le nom du connecteur
 * @param bool $option
 *     Inutilise
 * @return string|bool
 *     Retourne le nom du charset si effectivement trouvé, sinon false.
 **/
function sql_get_charset($charset, $serveur = '', $option = true) {
	// le nom http du charset differe parfois du nom SQL utf-8 ==> utf8 etc.
	$desc = sql_serveur('', $serveur, true, true);
	$desc = $desc[sql_ABSTRACT_VERSION];
	$c = $desc['charsets'][$charset];
	if ($c) {
		if (function_exists($f = @$desc['get_charset'])) {
			if ($f($c, $serveur, $option !== false)) {
				return $c;
			}
		}
	}
	spip_log("SPIP ne connait pas les Charsets disponibles sur le serveur $serveur. Le serveur choisira seul.",
		_LOG_AVERTISSEMENT);

	return false;
}


/**
 * Regler le codage de connexion
 *
 * Affecte un charset (tel que utf-8) sur la connexion utilisee
 * avec le gestionnaire de base de donnees
 *
 * @api
 * @see sql_get_charset() pour tester l'utilisation d'un charset
 *
 * @param string $charset
 *    Le charset souhaite
 * @param string $serveur
 *    Le nom du connecteur
 * @param bool|string $option
 *    Peut avoir 2 valeurs :
 *    - true pour executer la requete.
 *    - continue pour ne pas echouer en cas de serveur sql indisponible.
 *
 * @return bool
 *    Retourne true si elle reussie.
 **/
function sql_set_charset($charset, $serveur = '', $option = true) {
	$f = sql_serveur('set_charset', $serveur, $option === 'continue' or $option === false);
	if (!is_string($f) or !$f) {
		return false;
	}

	return $f($charset, $serveur, $option !== false);
}


/**
 * Effectue une requête de selection
 *
 * Fonction de selection (SELECT), retournant la ressource interrogeable par sql_fetch.
 *
 * @api
 * @see sql_fetch()      Pour boucler sur les resultats de cette fonction
 *
 * @param array|string $select
 *     Liste des champs a recuperer (Select)
 * @param array|string $from
 *     Tables a consulter (From)
 * @param array|string $where
 *     Conditions a remplir (Where)
 * @param array|string $groupby
 *     Critere de regroupement (Group by)
 * @param array|string $orderby
 *     Tableau de classement (Order By)
 * @param string $limit
 *     Critere de limite (Limit)
 * @param array $having
 *     Tableau des des post-conditions a remplir (Having)
 * @param string $serveur
 *     Le serveur sollicite (pour retrouver la connexion)
 * @param bool|string $option
 *     Peut avoir 3 valeurs :
 *
 *     - false -> ne pas l'exécuter mais la retourner,
 *     - continue -> ne pas echouer en cas de serveur sql indisponible,
 *     - true|array -> executer la requête.
 *     Le cas array est, pour une requete produite par le compilateur,
 *     un tableau donnnant le contexte afin d'indiquer le lieu de l'erreur au besoin
 *
 *
 * @return mixed
 *     Ressource SQL
 *
 *     - Ressource SQL pour sql_fetch, si la requete est correcte
 *     - false en cas d'erreur
 *     - Chaine contenant la requete avec $option=false
 *
 * Retourne false en cas d'erreur, apres l'avoir denoncee.
 * Les portages doivent retourner la requete elle-meme en cas d'erreur,
 * afin de disposer du texte brut.
 *
 **/
function sql_select(
	$select = array(),
	$from = array(),
	$where = array(),
	$groupby = array(),
	$orderby = array(),
	$limit = '',
	$having = array(),
	$serveur = '',
	$option = true
) {
	$f = sql_serveur('select', $serveur, $option === 'continue' or $option === false);
	if (!is_string($f) or !$f) {
		return false;
	}

	$debug = (defined('_VAR_MODE') and _VAR_MODE == 'debug');
	if (($option !== false) and !$debug) {
		$res = $f($select, $from, $where, $groupby, $orderby, $limit, $having, $serveur,
			is_array($option) ? true : $option);
	} else {
		$query = $f($select, $from, $where, $groupby, $orderby, $limit, $having, $serveur, false);
		if (!$option) {
			return $query;
		}
		// le debug, c'est pour ce qui a ete produit par le compilateur
		if (isset($GLOBALS['debug']['aucasou'])) {
			list($table, $id, ) = $GLOBALS['debug']['aucasou'];
			$nom = $GLOBALS['debug_objets']['courant'] . $id;
			$GLOBALS['debug_objets']['requete'][$nom] = $query;
		}
		$res = $f($select, $from, $where, $groupby, $orderby, $limit, $having, $serveur, true);
	}

	// en cas d'erreur
	if (!is_string($res)) {
		return $res;
	}
	// denoncer l'erreur SQL dans sa version brute
	spip_sql_erreur($serveur);
	// idem dans sa version squelette (prefixe des tables non substitue)
	$contexte_compil = sql_error_backtrace(true);
	erreur_squelette(array(sql_errno($serveur), sql_error($serveur), $res), $contexte_compil);

	return false;
}


/**
 * Recupere la syntaxe de la requete select sans l'executer
 *
 * Passe simplement $option a false au lieu de true
 * sans obliger a renseigner tous les arguments de sql_select.
 * Les autres parametres sont identiques.
 *
 * @api
 * @uses sql_select()
 *
 * @param array|string $select
 *    Liste des champs a recuperer (Select)
 * @param array|string $from
 *    Tables a consulter (From)
 * @param array|string $where
 *    Conditions a remplir (Where)
 * @param array|string $groupby
 *    Critere de regroupement (Group by)
 * @param array|string $orderby
 *    Tableau de classement (Order By)
 * @param string $limit
 *    Critere de limite (Limit)
 * @param array $having
 *    Tableau des des post-conditions a remplir (Having)
 * @param string $serveur
 *    Le serveur sollicite (pour retrouver la connexion)
 *
 * @return mixed
 *    Chaine contenant la requete
 *    ou false en cas d'erreur
 *
 **/
function sql_get_select(
	$select = array(),
	$from = array(),
	$where = array(),
	$groupby = array(),
	$orderby = array(),
	$limit = '',
	$having = array(),
	$serveur = ''
) {
	return sql_select($select, $from, $where, $groupby, $orderby, $limit, $having, $serveur, false);
}


/**
 * Retourne le nombre de lignes d'une sélection
 *
 * Ramène seulement et tout de suite le nombre de lignes
 * Pas de colonne ni de tri à donner donc.
 *
 * @api
 * @see sql_count()
 * @example
 *     ```
 *     if (sql_countsel('spip_mots_liens', array(
 *         "objet=".sql_quote('article'),
 *         "id_article=".sql_quote($id_article)) > 0) {
 *             // ...
 *     }
 *     ```
 *
 * @param array|string $from
 *    Tables a consulter (From)
 * @param array|string $where
 *    Conditions a remplir (Where)
 * @param array|string $groupby
 *    Critere de regroupement (Group by)
 * @param array $having
 *    Tableau des des post-conditions a remplir (Having)
 * @param string $serveur
 *    Le serveur sollicite (pour retrouver la connexion)
 * @param bool|string $option
 *    Peut avoir 3 valeurs :
 *
 *    - false -> ne pas l'executer mais la retourner,
 *    - continue -> ne pas echouer en cas de serveur sql indisponible,
 *    - true -> executer la requete.
 *
 * @return int|bool
 *     - Nombre de lignes de resultat
 *     - ou false en cas d'erreur
 *
 **/
function sql_countsel(
	$from = array(),
	$where = array(),
	$groupby = array(),
	$having = array(),
	$serveur = '',
	$option = true
) {
	$f = sql_serveur('countsel', $serveur, $option === 'continue' or $option === false);
	if (!is_string($f) or !$f) {
		return false;
	}
	$r = $f($from, $where, $groupby, $having, $serveur, $option !== false);
	if ($r === false) {
		spip_sql_erreur($serveur);
	}

	return $r;
}

/**
 * Modifie la structure de la base de données
 *
 * Effectue une opération ALTER.
 *
 * @example
 *     ```
 *     sql_alter('DROP COLUMN supprimer');
 *     ```
 *
 * @api
 * @param string $q
 *     La requête à exécuter (sans la préceder de 'ALTER ')
 * @param string $serveur
 *     Le serveur sollicite (pour retrouver la connexion)
 * @param bool|string $option
 *     Peut avoir 2 valeurs :
 *
 *     - true : exécuter la requete
 *     - 'continue' : ne pas échouer en cas de serveur sql indisponible
 * @return mixed
 *     2 possibilités :
 *
 *     - Incertain en cas d'exécution correcte de la requête
 *     - false en cas de serveur indiponible ou d'erreur
 *
 *     Ce retour n'est pas pertinent pour savoir si l'opération est correctement réalisée.
 **/
function sql_alter($q, $serveur = '', $option = true) {
	$f = sql_serveur('alter', $serveur, $option === 'continue' or $option === false);
	if (!is_string($f) or !$f) {
		return false;
	}
	$r = $f($q, $serveur, $option !== false);
	if ($r === false) {
		spip_sql_erreur($serveur);
	}

	return $r;
}

/**
 * Retourne un enregistrement d'une selection
 *
 * Retourne un resultat d'une ressource obtenue avec sql_select()
 *
 * @api
 * @param mixed $res
 *    Ressource retournee par sql_select()
 * @param string $serveur
 *    Le nom du connecteur
 * @param bool|string $option
 *    Peut avoir 2 valeurs :
 *    - true -> executer la requete
 *    - continue -> ne pas echouer en cas de serveur sql indisponible
 *
 * @return array
 *    Tableau de cles (colonnes SQL ou alias) / valeurs (valeurs dans la colonne de la table ou calculee)
 *    presentant une ligne de resultat d'une selection
 */
function sql_fetch($res, $serveur = '', $option = true) {
	$f = sql_serveur('fetch', $serveur, $option === 'continue' or $option === false);
	if (!is_string($f) or !$f) {
		return false;
	}

	return $f($res, null, $serveur, $option !== false);
}


/**
 * Retourne tous les enregistrements d'une selection
 *
 * Retourne tous les resultats d'une ressource obtenue avec sql_select()
 * dans un tableau
 *
 * @api
 * @param mixed $res
 *    Ressource retournee par sql_select()
 * @param string $serveur
 *    Le nom du connecteur
 * @param bool|string $option
 *    Peut avoir 2 valeurs :
 *    - true -> executer la requete
 *    - continue -> ne pas echouer en cas de serveur sql indisponible
 *
 * @return array
 *    Tableau contenant les enregistrements.
 *    Chaque entree du tableau est un autre tableau
 *    de cles (colonnes SQL ou alias) / valeurs (valeurs dans la colonne de la table ou calculee)
 *    presentant une ligne de resultat d'une selection
 */
function sql_fetch_all($res, $serveur = '', $option = true) {
	$rows = array();
	if (!$res) {
		return $rows;
	}
	$f = sql_serveur('fetch', $serveur, $option === 'continue' or $option === false);
	if (!is_string($f) or !$f) {
		return array();
	}
	while ($r = $f($res, null, $serveur, $option !== false)) {
		$rows[] = $r;
	}
	sql_free($res, $serveur);

	return $rows;
}

/**
 * Déplace le pointeur d'une ressource de sélection
 *
 * Deplace le pointeur sur un numéro de ligne précisé
 * sur une ressource issue de sql_select, afin que
 * le prochain sql_fetch récupère cette ligne.
 *
 * @api
 * @see sql_skip() Pour sauter des enregistrements
 *
 * @param mixed $res
 *    Ressource issue de sql_select
 * @param int $row_number
 *    Numero de ligne sur laquelle placer le pointeur
 * @param string $serveur
 *    Le nom du connecteur
 * @param bool|string $option
 *    Peut avoir 2 valeurs :
 *    - true -> executer la requete
 *    - continue -> ne pas echouer en cas de serveur sql indisponible
 *
 * @return bool
 *    Operation effectuée (true), sinon false.
 **/
function sql_seek($res, $row_number, $serveur = '', $option = true) {
	$f = sql_serveur('seek', $serveur, $option === 'continue' or $option === false);
	if (!is_string($f) or !$f) {
		return false;
	}
	$r = $f($res, $row_number, $serveur, $option !== false);
	if ($r === false) {
		spip_sql_erreur($serveur);
	}

	return $r;
}


/**
 * Liste des bases de donnees accessibles
 *
 * Retourne un tableau du nom de toutes les bases de donnees
 * accessibles avec les permissions de l'utilisateur SQL
 * de cette connexion.
 * Attention on n'a pas toujours les droits !
 *
 * @api
 * @param string $serveur
 *    Nom du connecteur
 * @param bool|string $option
 *    Peut avoir 2 valeurs :
 *    - true -> executer la requete
 *    - continue -> ne pas echouer en cas de serveur sql indisponible
 *
 * @return array|bool
 *    Tableau contenant chaque nom de base de donnees.
 *    False en cas d'erreur.
 **/
function sql_listdbs($serveur = '', $option = true) {
	$f = sql_serveur('listdbs', $serveur, $option === 'continue' or $option === false);
	if (!is_string($f) or !$f) {
		return false;
	}
	$r = $f($serveur);
	if ($r === false) {
		spip_sql_erreur($serveur);
	}

	return $r;
}


/**
 * Demande d'utiliser d'une base de donnees
 *
 * @api
 * @param string $nom
 *     Nom de la base a utiliser
 * @param string $serveur
 *     Nom du connecteur
 * @param bool|string $option
 *     Peut avoir 2 valeurs :
 *
 *     - true -> executer la requete
 *     - continue -> ne pas echouer en cas de serveur sql indisponible
 *
 * @return bool|string
 *     - True ou nom de la base en cas de success.
 *     - False en cas d'erreur.
 **/
function sql_selectdb($nom, $serveur = '', $option = true) {
	$f = sql_serveur('selectdb', $serveur, $option === 'continue' or $option === false);
	if (!is_string($f) or !$f) {
		return false;
	}
	$r = $f($nom, $serveur, $option !== false);
	if ($r === false) {
		spip_sql_erreur($serveur);
	}

	return $r;
}

/**
 * Retourne le nombre de lignes d’une ressource de sélection obtenue
 * avec `sql_select()`
 *
 * @api
 * @see sql_select()
 * @see sql_countsel()
 *
 * @param Ressource $res
 *     Ressource SQL
 * @param string $serveur
 *     Nom du connecteur
 * @param bool|string $option
 *     Peut avoir 2 valeurs :
 *
 *     - true -> executer la requete
 *     - continue -> ne pas echouer en cas de serveur sql indisponible
 * @return bool|string
 *     - int Nombre de lignes,
 *     - false en cas d'erreur.
 **/
function sql_count($res, $serveur = '', $option = true) {
	$f = sql_serveur('count', $serveur, $option === 'continue' or $option === false);
	if (!is_string($f) or !$f) {
		return false;
	}
	$r = $f($res, $serveur, $option !== false);
	if ($r === false) {
		spip_sql_erreur($serveur);
	}

	return $r;
}

/**
 * Libère une ressource de résultat
 *
 * Indique au gestionnaire SQL de libérer de sa mémoire la ressoucre de
 * résultat indiquée car on n'a plus besoin de l'utiliser.
 *
 * @param Ressource|Object $res
 *     Ressource de résultat
 * @param string $serveur
 *     Nom de la connexion
 * @param bool|string $option
 *     Peut avoir 2 valeurs :
 *
 *     - true -> exécuter la requete
 *     - continue -> ne pas échouer en cas de serveur SQL indisponible
 * @return bool
 *     True si réussi
 */
function sql_free($res, $serveur = '', $option = true) {
	$f = sql_serveur('free', $serveur, $option === 'continue' or $option === false);
	if (!is_string($f) or !$f) {
		return false;
	}

	return $f($res);
}


/**
 * Insère une ligne dans une table
 *
 * @see sql_insertq()
 * @see sql_quote()
 * @note
 *   Cette fonction ne garantit pas une portabilité totale,
 *   et n'est là que pour faciliter des migrations de vieux scripts.
 *   Préférer sql_insertq.
 *
 * @param string $table
 *     Nom de la table SQL
 * @param string $noms
 *     Liste des colonnes impactées,
 * @param string $valeurs
 *     Liste des valeurs,
 * @param array $desc
 *     Tableau de description des colonnes de la table SQL utilisée
 *     (il sera calculé si nécessaire s'il n'est pas transmis).
 * @param string $serveur
 *     Nom du connecteur
 * @param bool|string $option
 *     Peut avoir 3 valeurs :
 *
 *     - false : ne pas l'exécuter mais la retourner,
 *     - true : exécuter la requête
 *     - 'continue' : ne pas échouer en cas de serveur sql indisponible
 *
 * @return bool|string
 *     - int|true identifiant de l'élément inséré (si possible), ou true, si réussite
 *     - Texte de la requête si demandé,
 *     - False en cas d'erreur.
 **/
function sql_insert($table, $noms, $valeurs, $desc = array(), $serveur = '', $option = true) {
	$f = sql_serveur('insert', $serveur, $option === 'continue' or $option === false);
	if (!is_string($f) or !$f) {
		return false;
	}
	$r = $f($table, $noms, $valeurs, $desc, $serveur, $option !== false);
	if ($r === false or $r === null) {
		spip_sql_erreur($serveur);
		$r = false;
	}

	return $r;
}

/**
 * Insère une ligne dans une table
 *
 * Protègera chaque valeur comme sql_quote.
 *
 * @api
 * @see sql_insert()
 * @see sql_insertq_multi()
 * @see sql_quote()
 * @see objet_inserer()
 * @example
 *     ```
 *     $titre = _request('titre');
 *     $id = sql_insertq('spip_rubriques', array('titre' => $titre));
 *     ```
 *
 * @param string $table
 *     Nom de la table SQL
 * @param array $couples
 *     Tableau (nom => valeur)
 * @param array $desc
 *     Tableau de description des colonnes de la table SQL utilisée
 *     (il sera calculé si nécessaire s'il n'est pas transmis).
 * @param string $serveur
 *     Nom du connecteur
 * @param bool|string $option
 *     Peut avoir 3 valeurs :
 *
 *     - false : ne pas l'exécuter mais la retourner,
 *     - true : exécuter la requête
 *     - 'continue' : ne pas échouer en cas de serveur sql indisponible
 *
 * @return bool|string
 *     - int|true identifiant de l'élément inséré (si possible), ou true, si réussite
 *     - Texte de la requête si demandé,
 *     - False en cas d'erreur.
 **/
function sql_insertq($table, $couples = array(), $desc = array(), $serveur = '', $option = true) {
	$f = sql_serveur('insertq', $serveur, $option === 'continue' or $option === false);
	if (!is_string($f) or !$f) {
		return false;
	}
	$r = $f($table, $couples, $desc, $serveur, $option !== false);
	if ($r === false or $r === null) {
		spip_sql_erreur($serveur);
		$r = false;
	}

	return $r;
}

/**
 * Insère plusieurs lignes d'un coup dans une table
 *
 * Insère en une opération plusieurs éléments au schéma identique
 * dans une table de la base de données. Lorsque les portages le permettent,
 * ils utilisent une seule requête SQL pour réaliser l’ajout.
 *
 * @api
 * @see sql_insertq()
 *
 * @param string $table
 *     Nom de la table SQL
 * @param array $couples
 *     Tableau de tableaux associatifs (nom => valeur)
 * @param array $desc
 *     Tableau de description des colonnes de la table SQL utilisée
 *     (il sera calculé si nécessaire s'il n'est pas transmis).
 * @param string $serveur
 *     Nom du connecteur
 * @param bool|string $option
 *     Peut avoir 3 valeurs :
 *
 *     - false : ne pas l'exécuter mais la retourner,
 *     - true : exécuter la requête
 *     - 'continue' : ne pas échouer en cas de serveur sql indisponible
 *
 * @return bool|string
 *     - True en cas de succès,
 *     - Texte de la requête si demandé,
 *     - False en cas d'erreur.
 **/
function sql_insertq_multi($table, $couples = array(), $desc = array(), $serveur = '', $option = true) {
	$f = sql_serveur('insertq_multi', $serveur, $option === 'continue' or $option === false);
	if (!is_string($f) or !$f) {
		return false;
	}
	$r = $f($table, $couples, $desc, $serveur, $option !== false);
	if ($r === false or $r === null) {
		spip_sql_erreur($serveur);
		$r = false;
	}

	return $r;
}

/**
 * Met à jour des enregistrements d'une table SQL
 *
 * Les valeurs ne sont pas échappées, ce qui permet de modifier une colonne
 * en utilisant la valeur d'une autre colonne ou une expression SQL.
 *
 * Il faut alors protéger avec sql_quote() manuellement les valeurs qui
 * en ont besoin.
 *
 * Dans les autres cas, préférer sql_updateq().
 *
 * @api
 * @see sql_updateq()
 *
 * @param string $table
 *     Nom de la table
 * @param array $exp
 *     Couples (colonne => valeur)
 * @param string|array $where
 *     Conditions a remplir (Where)
 * @param array $desc
 *     Tableau de description des colonnes de la table SQL utilisée
 *     (il sera calculé si nécessaire s'il n'est pas transmis).
 * @param string $serveur
 *     Nom de la connexion
 * @param bool|string $option
 *     Peut avoir 3 valeurs :
 *
 *     - false : ne pas l'exécuter mais la retourner,
 *     - true : exécuter la requête
 *     - 'continue' : ne pas échouer en cas de serveur sql indisponible
 * @return array|bool|string
 *     - string : texte de la requête si demandé
 *     - true si la requête a réussie, false sinon
 *     - array Tableau décrivant la requête et son temps d'exécution si var_profile est actif
 */
function sql_update($table, $exp, $where = '', $desc = array(), $serveur = '', $option = true) {
	$f = sql_serveur('update', $serveur, $option === 'continue' or $option === false);
	if (!is_string($f) or !$f) {
		return false;
	}
	$r = $f($table, $exp, $where, $desc, $serveur, $option !== false);
	if ($r === false) {
		spip_sql_erreur($serveur);
	}

	return $r;
}


/**
 * Met à jour du contenu d’une table SQL
 *
 * Le contenu transmis à la fonction est protégé automatiquement
 * comme sql_quote().
 *
 * @api
 * @see sql_quote()
 * @see sql_update()
 * @example
 *     ```
 *     sql_updateq('table', array('colonne' => $valeur), 'id_table=' . intval($id_table));
 *     sql_updateq("spip_auteurs", array("statut" => '6forum'), "id_auteur=$id_auteur") ;
 *     ```
 * @note
 *   sql_update() est presque toujours appelée sur des constantes ou des dates
 *   Cette fonction (sql_updateq) est donc plus utile que la précédente,
 *   d'autant qu'elle permet de gerer les différences de représentation des constantes.
 *
 * @param string $table
 *     Nom de la table SQL
 * @param array $exp
 *     Couples (colonne => valeur)
 * @param array|string $where
 *     Conditions à vérifier
 * @param array $desc
 *     Tableau de description des colonnes de la table SQL utilisée
 *     (il sera calculé si nécessaire s'il n'est pas transmis).
 * @param string $serveur
 *     Nom du connecteur
 * @param bool|string $option
 *     Peut avoir 3 valeurs :
 *
 *     - false : ne pas l'exécuter mais la retourner,
 *     - true : exécuter la requête
 *     - 'continue' : ne pas échouer en cas de serveur sql indisponible
 * @return bool|string
 *     - true si réussite
 *     - Texte de la requête si demandé,
 *     - False en cas d'erreur.
 **/
function sql_updateq($table, $exp, $where = '', $desc = array(), $serveur = '', $option = true) {
	$f = sql_serveur('updateq', $serveur, $option === 'continue' or $option === false);
	if (!is_string($f) or !$f) {
		return false;
	}
	$r = $f($table, $exp, $where, $desc, $serveur, $option !== false);
	if ($r === false) {
		spip_sql_erreur($serveur);
	}

	return $r;
}

/**
 * Supprime des enregistrements d'une table
 *
 * @example
 *     ```
 *     sql_delete('spip_articles', 'id_article='.sql_quote($id_article));
 *     ```
 *
 * @api
 * @param string $table
 *     Nom de la table SQL
 * @param string|array $where
 *     Conditions à vérifier
 * @param string $serveur
 *     Nom du connecteur
 * @param bool|string $option
 *     Peut avoir 3 valeurs :
 *
 *     - false : ne pas l'exécuter mais la retourner,
 *     - true : exécuter la requête
 *     - 'continue' : ne pas échouer en cas de serveur sql indisponible
 *
 * @return bool|string
 *     - int : nombre de suppressions réalisées,
 *     - Texte de la requête si demandé,
 *     - False en cas d'erreur.
 **/
function sql_delete($table, $where = '', $serveur = '', $option = true) {
	$f = sql_serveur('delete', $serveur, $option === 'continue' or $option === false);
	if (!is_string($f) or !$f) {
		return false;
	}
	$r = $f($table, $where, $serveur, $option !== false);
	if ($r === false) {
		spip_sql_erreur($serveur);
	}

	return $r;
}

/**
 * Insère où met à jour une entrée d’une table SQL
 *
 * La clé ou les cles primaires doivent être présentes dans les données insérés.
 * La fonction effectue une protection automatique des données.
 *
 * Préférez sql_insertq() et sql_updateq().
 *
 * @see sql_insertq()
 * @see sql_updateq()
 *
 * @param string $table
 *     Nom de la table SQL
 * @param array $couples
 *     Couples colonne / valeur à modifier,
 * @param array $desc
 *     Tableau de description des colonnes de la table SQL utilisée
 *     (il sera calculé si nécessaire s'il n'est pas transmis).
 * @param string $serveur
 *     Nom du connecteur
 * @param bool|string $option
 *     Peut avoir 3 valeurs :
 *
 *     - false : ne pas l'exécuter mais la retourner,
 *     - true : exécuter la requête
 *     - 'continue' : ne pas échouer en cas de serveur sql indisponible
 *
 * @return bool|string
 *     - true si réussite
 *     - Texte de la requête si demandé,
 *     - False en cas d'erreur.
 **/
function sql_replace($table, $couples, $desc = array(), $serveur = '', $option = true) {
	$f = sql_serveur('replace', $serveur, $option === 'continue' or $option === false);
	if (!is_string($f) or !$f) {
		return false;
	}
	$r = $f($table, $couples, $desc, $serveur, $option !== false);
	if ($r === false) {
		spip_sql_erreur($serveur);
	}

	return $r;
}


/**
 * Insère où met à jour des entrées d’une table SQL
 *
 * La clé ou les cles primaires doivent être présentes dans les données insérés.
 * La fonction effectue une protection automatique des données.
 *
 * Préférez sql_insertq_multi() et sql_updateq().
 *
 * @see sql_insertq_multi()
 * @see sql_updateq()
 * @see sql_replace()
 *
 * @param string $table
 *     Nom de la table SQL
 * @param array $tab_couples
 *     Tableau de tableau (colonne / valeur à modifier),
 * @param array $desc
 *     Tableau de description des colonnes de la table SQL utilisée
 *     (il sera calculé si nécessaire s'il n'est pas transmis).
 * @param string $serveur
 *     Nom du connecteur
 * @param bool|string $option
 *     Peut avoir 3 valeurs :
 *
 *     - false : ne pas l'exécuter mais la retourner,
 *     - true : exécuter la requête
 *     - 'continue' : ne pas échouer en cas de serveur sql indisponible
 *
 * @return bool|string
 *     - true si réussite
 *     - Texte de la requête si demandé,
 *     - False en cas d'erreur.
 **/
function sql_replace_multi($table, $tab_couples, $desc = array(), $serveur = '', $option = true) {
	$f = sql_serveur('replace_multi', $serveur, $option === 'continue' or $option === false);
	if (!is_string($f) or !$f) {
		return false;
	}
	$r = $f($table, $tab_couples, $desc, $serveur, $option !== false);
	if ($r === false) {
		spip_sql_erreur($serveur);
	}

	return $r;
}

/**
 * Supprime une table SQL (structure et données)
 *
 * @api
 * @see sql_create()
 * @see sql_drop_view()
 *
 * @param string $table
 *     Nom de la table
 * @param string $exist
 *     true pour ajouter un test sur l'existence de la table, false sinon
 * @param string $serveur
 *     Nom du connecteur
 * @param bool|string $option
 *     Peut avoir 3 valeurs :
 *
 *     - false : ne pas l'exécuter mais la retourner,
 *     - true : exécuter la requête
 *     - 'continue' : ne pas échouer en cas de serveur sql indisponible
 * @return bool|string
 *     - True en cas de succès,
 *     - Texte de la requête si demandé,
 *     - False en cas d'erreur.
 **/
function sql_drop_table($table, $exist = '', $serveur = '', $option = true) {
	$f = sql_serveur('drop_table', $serveur, $option === 'continue' or $option === false);
	if (!is_string($f) or !$f) {
		return false;
	}
	$r = $f($table, $exist, $serveur, $option !== false);
	if ($r === false) {
		spip_sql_erreur($serveur);
	}

	return $r;
}

/**
 * Supprime une vue SQL
 *
 * @api
 * @see sql_create_view()
 * @see sql_drop_table()
 *
 * @param string $table Nom de la vue SQL
 * @param string $exist True pour ajouter un test d'existence avant de supprimer
 * @param string $serveur Nom de la connexion
 * @param bool $option
 *     Peut avoir 3 valeurs :
 *
 *     - false : ne pas l'exécuter mais la retourner,
 *     - true : exécuter la requête
 *     - 'continue' : ne pas échouer en cas de serveur sql indisponible
 * @return bool|string
 *     - string Texte de la requête si demandé
 *     - true si la requête a réussie, false sinon
 */
function sql_drop_view($table, $exist = '', $serveur = '', $option = true) {
	$f = sql_serveur('drop_view', $serveur, $option === 'continue' or $option === false);
	if (!is_string($f) or !$f) {
		return false;
	}
	$r = $f($table, $exist, $serveur, $option !== false);
	if ($r === false) {
		spip_sql_erreur($serveur);
	}

	return $r;
}

/**
 * Retourne une ressource de la liste des tables de la base de données
 *
 * @api
 * @see sql_alltable()
 *
 * @param string $spip
 *     Filtre sur tables retournées
 *     - NULL : retourne les tables SPIP uniquement (tables préfixées avec le préfixe de la connexion)
 *     - '%' : retourne toutes les tables de la base
 * @param string $serveur
 *     Le nom du connecteur
 * @param bool|string $option
 *     Peut avoir 3 valeurs :
 *     - false -> ne pas l'executer mais la retourner,
 *     - continue -> ne pas echouer en cas de serveur sql indisponible,
 *     - true -> executer la requete.
 * @return ressource
 *     Ressource à utiliser avec sql_fetch()
 **/
function sql_showbase($spip = null, $serveur = '', $option = true) {
	$f = sql_serveur('showbase', $serveur, $option === 'continue' or $option === false);
	if (!is_string($f) or !$f) {
		return false;
	}

	// la globale n'est remplie qu'apres l'appel de sql_serveur.
	if ($spip == null) {
		$connexion = $GLOBALS['connexions'][$serveur ? strtolower($serveur) : 0];
		$spip = $connexion['prefixe'] . '\_%';
	}

	return $f($spip, $serveur, $option !== false);
}

/**
 * Retourne la liste des tables SQL
 *
 * @api
 * @uses sql_showbase()
 * @param string $spip
 *     Filtre sur tables retournées
 *     - NULL : retourne les tables SPIP uniquement (tables préfixées avec le préfixe de la connexion)
 *     - '%' : retourne toutes les tables de la base
 * @param string $serveur
 *     Le nom du connecteur
 * @param bool|string $option
 *     Peut avoir 3 valeurs :
 *     - false -> ne pas l'executer mais la retourner,
 *     - continue -> ne pas echouer en cas de serveur sql indisponible,
 *     - true -> executer la requete.
 * @return array
 *     Liste des tables SQL
 **/
function sql_alltable($spip = null, $serveur = '', $option = true) {
	$q = sql_showbase($spip, $serveur, $option);
	$r = array();
	if ($q) {
		while ($t = sql_fetch($q, $serveur)) {
			$r[] = array_shift($t);
		}
	}

	return $r;
}

/**
 * Retourne la liste (et description) des colonnes et key d’une table SQL
 *
 * @note
 *     Dans la plupart des situations, il vaut mieux utiliser directement
 *     la fonction trouver_table() qui possède un cache.
 *
 * @api
 * @see base_trouver_table_dist()
 *
 * @param string $table
 *     Nom de la table SQL
 * @param bool $table_spip
 *     true pour remplacer automatiquement « spip » par le vrai préfixe de table
 * @param string $serveur
 *     Nom du connecteur
 * @param bool|string $option
 *     Peut avoir 3 valeurs :
 *
 *     - false : ne pas l'exécuter mais la retourner,
 *     - 'continue' : ne pas échouer en cas de serveur SQL indisponible,
 *     - true : exécuter la requete.
 * @return bool|array
 *     - false en cas d'echec
 *     - sinon array : Tableau avec
 *       - 'field' => array(colonne => description)
 *       - 'key' => array(type => key)
 *       - 'join' => array() // jointures, si déclarées.
 **/
function sql_showtable($table, $table_spip = false, $serveur = '', $option = true) {
	$f = sql_serveur('showtable', $serveur, $option === 'continue' or $option === false);
	if (!is_string($f) or !$f) {
		return false;
	}

	// la globale n'est remplie qu'apres l'appel de sql_serveur.
	if ($table_spip) {
		$connexion = $GLOBALS['connexions'][$serveur ? strtolower($serveur) : 0];
		$prefixe = $connexion['prefixe'];
		$vraie_table = preg_replace('/^spip/', $prefixe, $table);
	} else {
		$vraie_table = $table;
	}

	$f = $f($vraie_table, $serveur, $option !== false);
	if (!$f) {
		return array();
	}
	if (isset($GLOBALS['tables_principales'][$table]['join'])) {
		$f['join'] = $GLOBALS['tables_principales'][$table]['join'];
	} elseif (isset($GLOBALS['tables_auxiliaires'][$table]['join'])) {
		$f['join'] = $GLOBALS['tables_auxiliaires'][$table]['join'];
	}

	return $f;
}

/**
 * Crée une table dans la base de données
 *
 * @api
 * @example
 *     ```
 *     sql_create("spip_tables",
 *       array(
 *           "id_table" => "bigint(20) NOT NULL default '0'",
 *           "colonne1"=> "varchar(3) NOT NULL default 'oui'",
 *           "colonne2"=> "text NOT NULL default ''"
 *        ),
 *        array(
 *           'PRIMARY KEY' => "id_table",
 *           'KEY colonne1' => "colonne1"
 *        )
 *     );
 *     ```
 *
 * @param string $nom
 *     Nom de la table
 * @param array $champs
 *     Couples (colonne => description)
 * @param array $cles
 *     Clé (nomdelaclef => champ)
 * @param bool $autoinc
 *     Si un champ est clef primaire est numérique alors la propriété
 *     d’autoincrémentation sera ajoutée
 * @param bool $temporary
 *     true pour créer une table temporaire (au sens SQL)
 * @param string $serveur
 *     Nom du connecteur
 * @param bool|string $option
 *     Peut avoir 3 valeurs :
 *
 *     - false : ne pas l'exécuter mais la retourner,
 *     - 'continue' : ne pas échouer en cas de serveur SQL indisponible,
 *     - true : exécuter la requete.
 * @return bool
 *     true si succès, false en cas d'echec
 **/
function sql_create(
	$nom,
	$champs,
	$cles = array(),
	$autoinc = false,
	$temporary = false,
	$serveur = '',
	$option = true
) {
	$f = sql_serveur('create', $serveur, $option === 'continue' or $option === false);
	if (!is_string($f) or !$f) {
		return false;
	}
	$r = $f($nom, $champs, $cles, $autoinc, $temporary, $serveur, $option !== false);
	if ($r === false) {
		spip_sql_erreur($serveur);
	}

	return $r;
}

/**
 * Crée une base de données
 *
 * @api
 * @param string $nom Nom de la base (sans l'extension de fichier si gestionnaire SQLite)
 * @param string $serveur Nom de la connexion
 * @param bool $option
 *     Peut avoir 3 valeurs :
 *
 *     - false : ne pas l'exécuter mais la retourner,
 *     - true : exécuter la requête
 *     - 'continue' : ne pas échouer en cas de serveur sql indisponible
 * @return bool true si la base est créee.
 **/
function sql_create_base($nom, $serveur = '', $option = true) {
	$f = sql_serveur('create_base', $serveur, $option === 'continue' or $option === false);
	if (!is_string($f) or !$f) {
		return false;
	}
	$r = $f($nom, $serveur, $option !== false);
	if ($r === false) {
		spip_sql_erreur($serveur);
	}

	return $r;
}


/**
 * Crée une vue SQL
 *
 * @api
 * @see sql_drop_view()
 * @see sql_create()
 * @see sql_get_select() Pour obtenir le texte de la requête SELECT pour créer la vue.
 *
 * @param string $nom
 *     Nom de la vue
 * @param string $select_query
 *     Une requête SELECT, idéalement crée avec `sql_get_select(...)`
 * @param string $serveur
 *     Nom du connecteur
 * @param bool|string $option
 *     Peut avoir 3 valeurs :
 *
 *     - false : ne pas l'exécuter mais la retourner,
 *     - true : exécuter la requête
 *     - 'continue' : ne pas échouer en cas de serveur sql indisponible
 * @return bool|string
 *     - true si succès,
 *     - texte de la requête si demandé
 *     - false en cas d'échec.
 **/
function sql_create_view($nom, $select_query, $serveur = '', $option = true) {
	$f = sql_serveur('create_view', $serveur, $option === 'continue' or $option === false);
	if (!is_string($f) or !$f) {
		return false;
	}
	$r = $f($nom, $select_query, $serveur, $option !== false);
	if ($r === false) {
		spip_sql_erreur($serveur);
	}

	return $r;
}

/**
 * Retourne l'instruction SQL pour obtenir le texte d'un champ contenant
 * une balise `<multi>` dans la langue indiquée
 *
 * Cette sélection est mise dans l'alias `multi` (instruction AS multi).
 *
 * @example
 *     ```
 *     $t = sql_multi('chapo', 'fr');
 *     ```
 * @api
 * @param string $sel
 *     Colonne ayant le texte
 * @param string $lang
 *     Langue à extraire
 * @param string $serveur
 *     Nom du connecteur
 * @param bool|string $option
 *     Peut avoir 2 valeurs :
 *
 *     - true : exécuter la requête
 *     - 'continue' : ne pas échouer en cas de serveur sql indisponible
 * @return string
 *     Texte de sélection pour la requête
 */
function sql_multi($sel, $lang, $serveur = '', $option = true) {
	$f = sql_serveur('multi', $serveur, $option === 'continue' or $option === false);
	if (!is_string($f) or !$f) {
		return false;
	}

	return $f($sel, $lang);
}


/**
 * Retourne la dernière erreur connue
 *
 * @api
 * @param string $serveur
 *      Nom du connecteur
 * @return bool|string
 *      Description de l'erreur
 *      False si le serveur est indisponible
 */
function sql_error($serveur = '') {
	$f = sql_serveur('error', $serveur, 'continue');
	if (!is_string($f) or !$f) {
		return false;
	}

	return $f('query inconnue', $serveur);
}

/**
 * Retourne le numéro de la derniere erreur connue
 *
 * @api
 * @param string $serveur
 *      Nom du connecteur
 * @return bool|int
 *      Numéro de l'erreur
 *      False si le serveur est indisponible
 */
function sql_errno($serveur = '') {
	$f = sql_serveur('errno', $serveur, 'continue');
	if (!is_string($f) or !$f) {
		return false;
	}

	return $f($serveur);
}

/**
 * Retourne une explication de requête (Explain) SQL
 *
 * @api
 * @param string $q Texte de la requête
 * @param string $serveur Nom de la connexion
 * @param bool $option
 *     Peut avoir 3 valeurs :
 *
 *     - false : ne pas l'exécuter mais la retourner,
 *     - true : exécuter la requête
 *     - 'continue' : ne pas échouer en cas de serveur sql indisponible
 * @return array           Tableau de l'explication
 */
function sql_explain($q, $serveur = '', $option = true) {
	$f = sql_serveur('explain', $serveur, 'continue');
	if (!is_string($f) or !$f) {
		return false;
	}
	$r = $f($q, $serveur, $option !== false);
	if ($r === false) {
		spip_sql_erreur($serveur);
	}

	return $r;
}

/**
 * Optimise une table SQL
 *
 * @api
 * @param string $table Nom de la table
 * @param string $serveur Nom de la connexion
 * @param bool $option
 *     Peut avoir 3 valeurs :
 *
 *     - false : ne pas l'exécuter mais la retourner,
 *     - true : exécuter la requête
 *     - 'continue' : ne pas échouer en cas de serveur sql indisponible
 * @return bool            Toujours true
 */
function sql_optimize($table, $serveur = '', $option = true) {
	$f = sql_serveur('optimize', $serveur, $option === 'continue' or $option === false);
	if (!is_string($f) or !$f) {
		return false;
	}
	$r = $f($table, $serveur, $option !== false);
	if ($r === false) {
		spip_sql_erreur($serveur);
	}

	return $r;
}

/**
 * Répare une table SQL
 *
 * @api
 * @param string $table Nom de la table SQL
 * @param string $serveur Nom de la connexion
 * @param bool $option
 *     Peut avoir 3 valeurs :
 *
 *     - false : ne pas l'exécuter mais la retourner,
 *     - true : exécuter la requête
 *     - 'continue' : ne pas échouer en cas de serveur sql indisponible
 * @return bool|string
 *     - string Texte de la requête si demandée,
 *     - true si la requête a réussie, false sinon
 */
function sql_repair($table, $serveur = '', $option = true) {
	$f = sql_serveur('repair', $serveur, $option === 'continue' or $option === false);
	if (!is_string($f) or !$f) {
		return false;
	}
	$r = $f($table, $serveur, $option !== false);
	if ($r === false) {
		spip_sql_erreur($serveur);
	}

	return $r;
}


/**
 * Exécute une requête SQL
 *
 * Fonction la plus générale ... et la moins portable
 * À n'utiliser qu'en dernière extrémité
 *
 * @api
 * @param string $ins Requête
 * @param string $serveur Nom de la connexion
 * @param bool $option
 *     Peut avoir 3 valeurs :
 *
 *     - false : ne pas l'exécuter mais la retourner,
 *     - true : exécuter la requête
 *     - 'continue' : ne pas échouer en cas de serveur sql indisponible
 * @return array|resource|string|bool
 *     - string : Texte de la requête si on ne l'exécute pas
 *     - ressource|bool : Si requête exécutée
 *     - array : Tableau décrivant requête et temps d'exécution si var_profile actif pour tracer.
 */
function sql_query($ins, $serveur = '', $option = true) {
	$f = sql_serveur('query', $serveur, $option === 'continue' or $option === false);
	if (!is_string($f) or !$f) {
		return false;
	}
	$r = $f($ins, $serveur, $option !== false);
	if ($r === false) {
		spip_sql_erreur($serveur);
	}

	return $r;
}

/**
 * Retourne la première ligne d'une sélection
 *
 * Retourne la première ligne de résultat d'une sélection
 * comme si l'on appelait successivement `sql_select()` puis `sql_fetch()`
 *
 * @example
 *     ```
 *     $art = sql_fetsel(array('id_rubrique','id_secteur'), 'spip_articles', 'id_article='.sql_quote($id_article));
 *     $id_rubrique = $art['id_rubrique'];
 *     ```
 *
 * @api
 * @uses sql_select()
 * @uses sql_fetch()
 * @see  sql_getfetsel()
 *
 * @param array|string $select
 *    Liste des champs a recuperer (Select)
 * @param array|string $from
 *    Tables a consulter (From)
 * @param array|string $where
 *    Conditions a remplir (Where)
 * @param array|string $groupby
 *    Critere de regroupement (Group by)
 * @param array|string $orderby
 *    Tableau de classement (Order By)
 * @param string $limit
 *    Critere de limite (Limit)
 * @param array $having
 *    Tableau des des post-conditions a remplir (Having)
 * @param string $serveur
 *    Le serveur sollicite (pour retrouver la connexion)
 * @param bool|string $option
 *    Peut avoir 3 valeurs :
 *    - true -> executer la requete.
 *    - continue -> ne pas echouer en cas de serveur sql indisponible.
 *    - false -> ne pas l'executer mais la retourner.
 *
 * @return array
 *     Tableau de la premiere ligne de resultat de la selection tel que
 *     `array('id_rubrique' => 1, 'id_secteur' => 2)`
 *
 **/
function sql_fetsel(
	$select = array(),
	$from = array(),
	$where = array(),
	$groupby = array(),
	$orderby = array(),
	$limit = '',
	$having = array(),
	$serveur = '',
	$option = true
) {
	$q = sql_select($select, $from, $where, $groupby, $orderby, $limit, $having, $serveur, $option);
	if ($option === false) {
		return $q;
	}
	if (!$q) {
		return array();
	}
	$r = sql_fetch($q, $serveur, $option);
	sql_free($q, $serveur, $option);

	return $r;
}


/**
 * Retourne le tableau de toutes les lignes d'une selection
 *
 * Retourne toutes les lignes de resultat d'une selection
 * comme si l'on appelait successivement sql_select() puis while(sql_fetch())
 *
 * @example
 *    ```
 *    $rubs = sql_allfetsel('id_rubrique', 'spip_articles', 'id_secteur='.sql_quote($id_secteur));
 *    // $rubs = array(array('id_rubrique'=>1), array('id_rubrique'=>3, ...)
 *    ```
 *
 * @api
 * @uses sql_select()
 * @uses sql_fetch()
 *
 * @param array|string $select
 *    Liste des champs a recuperer (Select)
 * @param array|string $from
 *    Tables a consulter (From)
 * @param array|string $where
 *    Conditions a remplir (Where)
 * @param array|string $groupby
 *    Critere de regroupement (Group by)
 * @param array|string $orderby
 *    Tableau de classement (Order By)
 * @param string $limit
 *    Critere de limite (Limit)
 * @param array $having
 *    Tableau des des post-conditions a remplir (Having)
 * @param string $serveur
 *    Le serveur sollicite (pour retrouver la connexion)
 * @param bool|string $option
 *    Peut avoir 3 valeurs :
 *    - true -> executer la requete.
 *    - continue -> ne pas echouer en cas de serveur sql indisponible.
 *    - false -> ne pas l'executer mais la retourner.
 *
 * @return array
 *    Tableau de toutes les lignes de resultat de la selection
 *    Chaque entree contient un tableau des elements demandees dans le SELECT.
 *    {@example
 *      ```
 *      array(
 *        array('id_rubrique' => 1, 'id_secteur' => 2)
 *        array('id_rubrique' => 4, 'id_secteur' => 2)
 *        ...
 *      )
 *      ```
 *    }
 *
 **/
function sql_allfetsel(
	$select = array(),
	$from = array(),
	$where = array(),
	$groupby = array(),
	$orderby = array(),
	$limit = '',
	$having = array(),
	$serveur = '',
	$option = true
) {
	$q = sql_select($select, $from, $where, $groupby, $orderby, $limit, $having, $serveur, $option);
	if ($option === false) {
		return $q;
	}

	return sql_fetch_all($q, $serveur, $option);
}


/**
 * Retourne un unique champ d'une selection
 *
 * Retourne dans la premiere ligne de resultat d'une selection
 * un unique champ demande
 *
 * @example
 *     ```
 *     $id_rubrique = sql_getfetsel('id_rubrique', 'spip_articles', 'id_article='.sql_quote($id_article));
 *     ```
 *
 * @api
 * @uses sql_fetsel()
 *
 * @param array|string $select
 *     Liste des champs à récupérer (Select)
 * @param array|string $from
 *     Tables à consulter (From)
 * @param array|string $where
 *     Conditions à remplir (Where)
 * @param array|string $groupby
 *     Critère de regroupement (Group by)
 * @param array|string $orderby
 *     Tableau de classement (Order By)
 * @param string $limit
 *     Critère de limite (Limit)
 * @param array $having
 *     Tableau des des post-conditions à remplir (Having)
 * @param string $serveur
 *     Le serveur sollicité (pour retrouver la connexion)
 * @param bool|string $option
 *     Peut avoir 3 valeurs :
 *
 *     - true -> executer la requete.
 *     - continue -> ne pas echouer en cas de serveur sql indisponible.
 *     - false -> ne pas l'executer mais la retourner.
 *
 * @return mixed
 *     Contenu de l'unique valeur demandee du premier enregistrement retourne
 *
 **/
function sql_getfetsel(
	$select,
	$from = array(),
	$where = array(),
	$groupby = array(),
	$orderby = array(),
	$limit = '',
	$having = array(),
	$serveur = '',
	$option = true
) {
	if (preg_match('/\s+as\s+(\w+)$/i', $select, $c)) {
		$id = $c[1];
	} elseif (!preg_match('/\W/', $select)) {
		$id = $select;
	} else {
		$id = 'n';
		$select .= ' AS n';
	}
	$r = sql_fetsel($select, $from, $where, $groupby, $orderby, $limit, $having, $serveur, $option);
	if ($option === false) {
		return $r;
	}
	if (!$r) {
		return null;
	}

	return $r[$id];
}

/**
 * Retourne le numero de version du serveur SQL
 *
 * @api
 * @param string $serveur
 *    Nom du connecteur
 * @param bool|string $option
 *    Peut avoir 2 valeurs :
 *    - true pour executer la requete.
 *    - continue pour ne pas echouer en cas de serveur sql indisponible.
 *
 * @return string
 *    Numero de version du serveur SQL
 **/
function sql_version($serveur = '', $option = true) {
	$row = sql_fetsel("version() AS n", '', '', '', '', '', '', $serveur);

	return ($row['n']);
}

/**
 * Informe si le moteur SQL prefere utiliser des transactions
 *
 * Cette fonction experimentale est pour l'instant presente pour accelerer certaines
 * insertions multiples en SQLite, en les encadrant d'une transaction.
 * SQLite ne cree alors qu'un verrou pour l'ensemble des insertions
 * et non un pour chaque, ce qui accelere grandement le processus.
 * Evidemment, si une des insertions echoue, rien ne sera enregistre.
 * Pour ne pas perturber les autres moteurs, cette fonction permet
 * de verifier que le moteur prefere utiliser des transactions dans ce cas.
 *
 * @example
 *    ```
 *    if (sql_preferer_transaction()) {
 *      sql_demarrer_transaction();
 *    }
 *    ```
 *
 * @api
 * @see sql_demarrer_transaction()
 * @see sql_terminer_transaction()
 *
 * @param string $serveur
 *    Nom du connecteur
 * @param bool|string $option
 *    Peut avoir 2 valeurs :
 *    - true pour executer la requete.
 *    - continue pour ne pas echouer en cas de serveur sql indisponible.
 *
 * @return bool
 *    Le serveur SQL prefere t'il des transactions pour les insertions multiples ?
 **/
function sql_preferer_transaction($serveur = '', $option = true) {
	$f = sql_serveur('preferer_transaction', $serveur, 'continue');
	if (!is_string($f) or !$f) {
		return false;
	}
	$r = $f($serveur, $option !== false);
	if ($r === false) {
		spip_sql_erreur($serveur);
	}

	return $r;
}

;

/**
 * Démarre une transaction
 *
 * @api
 * @see sql_terminer_transaction() Pour cloturer la transaction
 *
 * @param string $serveur
 *    Nom du connecteur
 * @param bool|string $option
 *    Peut avoir 3 valeurs :
 *
 *    - true pour executer la requete.
 *    - continue pour ne pas echouer en cas de serveur sql indisponible.
 *    - false pour obtenir le code de la requete
 *
 * @return bool
 *      true si la transaction est demarree
 *      false en cas d'erreur
 **/
function sql_demarrer_transaction($serveur = '', $option = true) {
	$f = sql_serveur('demarrer_transaction', $serveur, 'continue');
	if (!is_string($f) or !$f) {
		return false;
	}
	$r = $f($serveur, $option !== false);
	if ($r === false) {
		spip_sql_erreur($serveur);
	}

	return $r;
}

;

/**
 * Termine une transaction
 *
 * @api
 * @see sql_demarrer_transaction() Pour demarrer une transaction
 *
 * @param string $serveur
 *    Nom du connecteur
 * @param bool|string $option
 *    Peut avoir 3 valeurs :
 *
 *    - true pour executer la requete.
 *    - continue pour ne pas echouer en cas de serveur sql indisponible.
 *    - false pour obtenir le code de la requete
 *
 * @return bool
 *      true si la transaction est demarree
 *      false en cas d'erreur
 **/
function sql_terminer_transaction($serveur = '', $option = true) {
	$f = sql_serveur('terminer_transaction', $serveur, 'continue');
	if (!is_string($f) or !$f) {
		return false;
	}
	$r = $f($serveur, $option !== false);
	if ($r === false) {
		spip_sql_erreur($serveur);
	}

	return $r;
}

;


/**
 * Prépare une chaine hexadécimale
 *
 * Prend une chaîne sur l'aphabet hexa
 * et retourne sa représentation numérique attendue par le serveur SQL.
 * Par exemple : FF ==> 0xFF en MySQL mais x'FF' en PG
 *
 * @api
 * @param string $val
 *     Chaine hexadécimale
 * @param string $serveur
 *     Nom du connecteur
 * @param bool|string $option
 *     Peut avoir 2 valeurs :
 *
 *     - true pour exécuter la demande.
 *     - 'continue' pour ne pas échouer en cas de serveur SQL indisponible.
 * @return string
 *     Valeur hexadécimale attendue par le serveur SQL
 **/
function sql_hex($val, $serveur = '', $option = true) {
	$f = sql_serveur('hex', $serveur, $option === 'continue' or $option === false);
	if (!is_string($f) or !$f) {
		return false;
	}

	return $f($val);
}

/**
 * Echapper du contenu
 *
 * Echappe du contenu selon ce qu'attend le type de serveur SQL
 * et en fonction du type de contenu.
 *
 * Permet entre autres de se protéger d'injections SQL.
 *
 * Cette fonction est automatiquement appelée par les fonctions `sql_*q`
 * tel que `sql_instertq` ou `sql_updateq`
 *
 * @api
 * @param string $val
 *     Chaine à echapper
 * @param string $serveur
 *     Nom du connecteur
 * @param string $type
 *     Peut contenir une declaration de type de champ SQL.
 *     Exemple : `int NOT NULL` qui sert alors aussi à calculer le type d'échappement
 * @return string
 *     La chaine echappee
 **/
function sql_quote($val, $serveur = '', $type = '') {
	$f = sql_serveur('quote', $serveur, true);
	if (!is_string($f) or !$f) {
		$f = '_q';
	}

	return $f($val, $type);
}

/**
 * Tester si une date est proche de la valeur d'un champ
 *
 * @api
 * @param string $champ
 *     Nom du champ a tester
 * @param int $interval
 *     Valeur de l'intervalle : -1, 4, ...
 * @param string $unite
 *     Utité utilisée (DAY, MONTH, YEAR, ...)
 * @param string $serveur
 *     Nom du connecteur
 * @param bool|string $option
 *     Peut avoir 2 valeurs :
 *
 *     - true pour exécuter la demande.
 *     - 'continue' pour ne pas échouer en cas de serveur SQL indisponible.
 * @return string|bool
 *     - string : Expression SQL
 *     - false si le serveur SQL est indisponible
 **/
function sql_date_proche($champ, $interval, $unite, $serveur = '', $option = true) {
	$f = sql_serveur('date_proche', $serveur, true);
	if (!is_string($f) or !$f) {
		return false;
	}

	return $f($champ, $interval, $unite);
}

/**
 * Retourne une expression IN pour le gestionnaire de base de données
 *
 * Retourne un code à insérer dans une requête SQL pour récupérer
 * les éléments d'une colonne qui appartiennent à une liste donnée
 *
 * @example
 *     `sql_in('id_rubrique', array(3,4,5))`
 *     retourne approximativement «id_rubrique IN (3,4,5)» selon ce qu'attend
 *     le gestionnaire de base de donnée du connecteur en cours.
 *
 * @api
 * @param string $val
 *     Colonne SQL sur laquelle appliquer le test
 * @param string|array $valeurs
 *     Liste des valeurs possibles (séparés par des virgules si string)
 * @param string $not
 *     - '' sélectionne les éléments correspondant aux valeurs
 *     - 'NOT' inverse en sélectionnant les éléments ne correspondant pas aux valeurs
 * @param string $serveur
 *   Nom du connecteur
 * @param bool|string $option
 *   Peut avoir 2 valeurs :
 *
 *   - continue -> ne pas echouer en cas de serveur sql indisponible
 *   - true ou false -> retourne l'expression
 * @return string
 *     Expression de requête SQL
 **/
function sql_in($val, $valeurs, $not = '', $serveur = '', $option = true) {
	if (is_array($valeurs)) {
		$f = sql_serveur('quote', $serveur, true);
		if (!is_string($f) or !$f) {
			return false;
		}
		$valeurs = join(',', array_map($f, array_unique($valeurs)));
	} elseif (isset($valeurs[0]) and $valeurs[0] === ',') {
		$valeurs = substr($valeurs, 1);
	}
	if (!strlen(trim($valeurs))) {
		return ($not ? "0=0" : '0=1');
	}

	$f = sql_serveur('in', $serveur, $option === 'continue' or $option === false);
	if (!is_string($f) or !$f) {
		return false;
	}

	return $f($val, $valeurs, $not, $serveur, $option !== false);
}


/**
 * Retourne une expression IN pour le gestionnaire de base de données
 * à partir d'une sélection de données
 *
 * Sélectionne les données (comme sql_select()) et prépare avec l'expression IN
 *
 * @see sql_select()
 * @see sql_in()
 * @note
 *   Penser à dire dans la description du serveur
 *   s'il accepte les requêtes imbriquées afin d'optimiser ca
 *
 * @api
 * @param string $in
 *     Colonne SQL sur laquelle appliquer le test
 * @param array|string $select
 *     Liste des champs à récupérer (Select).
 *     La donnée extraite est le premier élément de la sélection.
 * @param array|string $from
 *     Tables a consulter (From)
 * @param array|string $where
 *     Conditions a remplir (Where)
 * @param array|string $groupby
 *     Critere de regroupement (Group by)
 * @param array|string $orderby
 *     Tableau de classement (Order By)
 * @param string $limit
 *     Critere de limite (Limit)
 * @param array $having
 *     Tableau des des post-conditions a remplir (Having)
 * @param string $serveur
 *     Nom du connecteur
 * @return string
 *     Expression de requête SQL
 **/
function sql_in_select(
	$in,
	$select,
	$from = array(),
	$where = array(),
	$groupby = array(),
	$orderby = array(),
	$limit = '',
	$having = array(),
	$serveur = ''
) {
	$liste = array();
	$res = sql_select($select, $from, $where, $groupby, $orderby, $limit, $having, $serveur);
	while ($r = sql_fetch($res)) {
		$liste[] = array_shift($r);
	}
	sql_free($res);

	return sql_in($in, $liste);
}

/**
 * Implémentation sécurisée du saut en avant.
 *
 * Ne dépend pas de la disponibilité de la fonction `sql_seek()`.
 * Ne fait rien pour une valeur négative ou nulle de `$saut`.
 * Retourne la position après le saut
 *
 * @see sql_seek()
 *
 * @param resource $res
 *    Ressource issue d'une selection sql_select
 * @param int $pos
 *   position courante
 * @param int $saut
 *   saut demande
 * @param int $count
 *   position maximale
 *   (nombre de resultat de la requete OU position qu'on ne veut pas depasser)
 * @param string $serveur
 *   Nom du connecteur
 * @param bool|string $option
 *   Peut avoir 2 valeurs :
 *   - true -> executer la requete
 *   - continue -> ne pas echouer en cas de serveur sql indisponible
 *
 * @return int
 *    Position apres le saut.
 */
function sql_skip($res, $pos, $saut, $count, $serveur = '', $option = true) {
	// pas de saut en arriere qu'on ne sait pas faire sans sql_seek
	if (($saut = intval($saut)) <= 0) {
		return $pos;
	}

	$seek = $pos + $saut;
	// si le saut fait depasser le maxi, on libere la resource
	// et on sort
	if ($seek >= $count) {
		sql_free($res, $serveur, $option);

		return $count;
	}

	if (sql_seek($res, $seek)) {
		$pos = $seek;
	} else {
		while ($pos < $seek and sql_fetch($res, $serveur, $option)) {
			$pos++;
		}
	}

	return $pos;
}


/**
 * Teste qu'une description de champ SQL est de type entier
 *
 * @api
 * @see sql_test_date() pour tester les champs de date
 *
 * @param string $type
 *     Description de la colonne SQL
 * @param string $serveur
 *    Nom du connecteur
 * @param bool $option
 *     Inutilisé
 * @return bool
 *     True si le champ est de type entier
 */
function sql_test_int($type, $serveur = '', $option = true) {
	return preg_match('/^(TINYINT|SMALLINT|MEDIUMINT|INT|INTEGER|BIGINT)/i', trim($type));
}

/**
 * Teste qu'une description de champ SQL est de type entier
 *
 * @api
 * @see sql_test_int() pour tester les champs d'entiers
 *
 * @param string $type
 *     Description de la colonne SQL
 * @param string $serveur
 *    Nom du connecteur
 * @param bool $option
 *     Inutilisé
 * @return bool
 *     True si le champ est de type entier
 */
function sql_test_date($type, $serveur = '', $option = true) {
	return preg_match('/^(DATE|DATETIME|TIMESTAMP|TIME)/i', trim($type));
}

/**
 * Formate une date
 *
 * Formater une date Y-m-d H:i:s sans passer par mktime
 * qui ne sait pas gerer les dates < 1970
 *
 * @api
 * @param int $annee Annee
 * @param int $mois Numero du mois
 * @param int $jour Numero du jour dans le mois
 * @param int $h Heures
 * @param int $m Minutes
 * @param int $s Secondes
 * @param string $serveur
 *     Le serveur sollicite (pour retrouver la connexion)
 * @return string
 *     La date formatee
 */
function sql_format_date($annee = 0, $mois = 0, $jour = 0, $h = 0, $m = 0, $s = 0, $serveur = '') {
	$annee = sprintf("%04s", $annee);
	$mois = sprintf("%02s", $mois);

	if ($annee == "0000") {
		$mois = 0;
	}
	if ($mois == "00") {
		$jour = 0;
	}

	return sprintf("%04u", $annee) . '-' . sprintf("%02u", $mois) . '-'
	. sprintf("%02u", $jour) . ' ' . sprintf("%02u", $h) . ':'
	. sprintf("%02u", $m) . ':' . sprintf("%02u", $s);
}


/**
 * Retourne la description de la table SQL
 *
 * Retrouve la description de la table SQL en privilegiant
 * la structure reelle de la base de donnees.
 * En absence, ce qui arrive lors de l'installation, la fonction
 * s'appuie sur la declaration des tables SQL principales ou auxiliaires.
 *
 * @internal Cette fonction devrait disparaître
 *
 * @param string $nom
 *    Nom de la table dont on souhait la description
 * @param string $serveur
 *    Nom du connecteur
 * @return array|bool
 *    Description de la table ou false si elle n'est pas trouvee ou declaree.
 **/
function description_table($nom, $serveur = '') {

	static $trouver_table;

	/* toujours utiliser trouver_table
	 qui renverra la description theorique
	 car sinon on va se comporter differement selon que la table est declaree
	 ou non
	 */
	if (!$trouver_table) {
		$trouver_table = charger_fonction('trouver_table', 'base');
	}
	if ($desc = $trouver_table($nom, $serveur)) {
		return $desc;
	}

	// sauf a l'installation :
	include_spip('base/serial');
	if (isset($GLOBALS['tables_principales'][$nom])) {
		return $GLOBALS['tables_principales'][$nom];
	}

	include_spip('base/auxiliaires');
	if (isset($GLOBALS['tables_auxiliaires'][$nom])) {
		return $GLOBALS['tables_auxiliaires'][$nom];
	}

	return false;
}