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/ami-ubuntu backup december/maintenance/ecrire/req/
Upload File :
Current File : /home/ami/.trash/guhisha ibyambere.1/ami-ubuntu backup december/maintenance/ecrire/req/mysql.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.   *
\***************************************************************************/

/**
 * Ce fichier contient les fonctions gérant
 * les instructions SQL pour MySQL
 *
 * Ces instructions utilisent la librairie PHP Mysqli
 *
 * @package SPIP\Core\SQL\MySQL
 */

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

if (!defined('_MYSQL_NOPLANES')) {
	define('_MYSQL_NOPLANES', true);
}

/**
 * Crée la première connexion à un serveur MySQL via MySQLi
 *
 * @param string $host Chemin du serveur
 * @param int $port Port de connexion
 * @param string $login Nom d'utilisateur
 * @param string $pass Mot de passe
 * @param string $db Nom de la base
 * @param string $prefixe Préfixe des tables SPIP
 * @return array|bool
 *     - false si la connexion a échoué
 *     - tableau décrivant la connexion sinon
 */
function req_mysql_dist($host, $port, $login, $pass, $db = '', $prefixe = '') {
	if (!charger_php_extension('mysqli')) {
		return false;
	}
	if ($port) {
		$link = @mysqli_connect($host, $login, $pass, '', $port);
	} else {
		$link = @mysqli_connect($host, $login, $pass);
	}

	if (!$link) {
		spip_log('Echec mysqli_connect. Erreur : ' . mysqli_connect_error(), 'mysql.' . _LOG_HS);

		return false;
	}
	$last = '';
	if (!$db) {
		$ok = $link;
		$db = 'spip';
	} else {
		$ok = mysqli_select_db($link, $db);
		if (defined('_MYSQL_SET_SQL_MODE')
			or defined('_MYSQL_SQL_MODE_TEXT_NOT_NULL') // compatibilite
		) {
			mysqli_query($link, $last = "set sql_mode=''");
		}
	}

	spip_log("Connexion MySQLi vers $host, base $db, prefixe $prefixe " . ($ok ? "operationnelle" : 'impossible'),
		_LOG_DEBUG);

	return !$ok ? false : array(
		'db' => $db,
		'last' => $last,
		'prefixe' => $prefixe ? $prefixe : $db,
		'link' => $link,
		'total_requetes' => 0,
	);
}


$GLOBALS['spip_mysql_functions_1'] = array(
	'alter' => 'spip_mysql_alter',
	'count' => 'spip_mysql_count',
	'countsel' => 'spip_mysql_countsel',
	'create' => 'spip_mysql_create',
	'create_base' => 'spip_mysql_create_base',
	'create_view' => 'spip_mysql_create_view',
	'date_proche' => 'spip_mysql_date_proche',
	'delete' => 'spip_mysql_delete',
	'drop_table' => 'spip_mysql_drop_table',
	'drop_view' => 'spip_mysql_drop_view',
	'errno' => 'spip_mysql_errno',
	'error' => 'spip_mysql_error',
	'explain' => 'spip_mysql_explain',
	'fetch' => 'spip_mysql_fetch',
	'seek' => 'spip_mysql_seek',
	'free' => 'spip_mysql_free',
	'hex' => 'spip_mysql_hex',
	'in' => 'spip_mysql_in',
	'insert' => 'spip_mysql_insert',
	'insertq' => 'spip_mysql_insertq',
	'insertq_multi' => 'spip_mysql_insertq_multi',
	'listdbs' => 'spip_mysql_listdbs',
	'multi' => 'spip_mysql_multi',
	'optimize' => 'spip_mysql_optimize',
	'query' => 'spip_mysql_query',
	'quote' => 'spip_mysql_quote',
	'replace' => 'spip_mysql_replace',
	'replace_multi' => 'spip_mysql_replace_multi',
	'repair' => 'spip_mysql_repair',
	'select' => 'spip_mysql_select',
	'selectdb' => 'spip_mysql_selectdb',
	'set_charset' => 'spip_mysql_set_charset',
	'get_charset' => 'spip_mysql_get_charset',
	'showbase' => 'spip_mysql_showbase',
	'showtable' => 'spip_mysql_showtable',
	'update' => 'spip_mysql_update',
	'updateq' => 'spip_mysql_updateq',

	// association de chaque nom http d'un charset aux couples MySQL
	'charsets' => array(
		'cp1250' => array('charset' => 'cp1250', 'collation' => 'cp1250_general_ci'),
		'cp1251' => array('charset' => 'cp1251', 'collation' => 'cp1251_general_ci'),
		'cp1256' => array('charset' => 'cp1256', 'collation' => 'cp1256_general_ci'),
		'iso-8859-1' => array('charset' => 'latin1', 'collation' => 'latin1_swedish_ci'),
//'iso-8859-6'=>array('charset'=>'latin1','collation'=>'latin1_swedish_ci'),
		'iso-8859-9' => array('charset' => 'latin5', 'collation' => 'latin5_turkish_ci'),
//'iso-8859-15'=>array('charset'=>'latin1','collation'=>'latin1_swedish_ci'),
		'utf-8' => array('charset' => 'utf8', 'collation' => 'utf8_general_ci')
	)
);


/**
 * Retrouver un link d'une connexion MySQL via MySQLi
 *
 * @param string $serveur Nom du serveur
 * @return Object Information de connexion pour mysqli
 */
function _mysql_link($serveur = '') {
	$link = &$GLOBALS['connexions'][$serveur ? $serveur : 0]['link'];

	return $link;
}


/**
 * Définit un charset pour la connexion avec Mysql
 *
 * @param string $charset Charset à appliquer
 * @param string $serveur Nom de la connexion
 * @param bool $requeter inutilisé
 * @return resource       Ressource de résultats pour fetch()
 */
function spip_mysql_set_charset($charset, $serveur = '', $requeter = true) {
	$connexion = &$GLOBALS['connexions'][$serveur ? strtolower($serveur) : 0];
	spip_log("changement de charset sql : " . "SET NAMES " . _q($charset), _LOG_DEBUG);

	return mysqli_query($connexion['link'], $connexion['last'] = "SET NAMES " . _q($charset));
}


/**
 * Teste si le charset indiqué est disponible sur le serveur SQL
 *
 * @param array|string $charset Nom du charset à tester.
 * @param string $serveur Nom de la connexion
 * @param bool $requeter inutilisé
 * @return array                Description du charset (son nom est dans 'charset')
 */
function spip_mysql_get_charset($charset = array(), $serveur = '', $requeter = true) {
	$connexion = &$GLOBALS['connexions'][$serveur ? strtolower($serveur) : 0];
	$connexion['last'] = $c = "SHOW CHARACTER SET"
		. (!$charset ? '' : (" LIKE " . _q($charset['charset'])));

	return spip_mysql_fetch(mysqli_query($connexion['link'], $c), null, $serveur);
}


/**
 * Exécute une requête Mysql (obsolète, ne plus utiliser)
 *
 * @deprecated Utiliser sql_query() ou autres
 *
 * @param string $query Requête
 * @param string $serveur Nom de la connexion
 * @param bool $requeter Exécuter la requête, sinon la retourner
 * @return Resource        Ressource pour fetch()
 **/
function spip_query_db($query, $serveur = '', $requeter = true) {
	return spip_mysql_query($query, $serveur, $requeter);
}


/**
 * Exécute une requête MySQL, munie d'une trace à la demande
 *
 * @param string $query Requête
 * @param string $serveur Nom de la connexion
 * @param bool $requeter Exécuter la requête, sinon la retourner
 * @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 spip_mysql_query($query, $serveur = '', $requeter = true) {

	$connexion = &$GLOBALS['connexions'][$serveur ? strtolower($serveur) : 0];
	$prefixe = $connexion['prefixe'];
	$link = $connexion['link'];
	$db = $connexion['db'];

	$query = _mysql_traite_query($query, $db, $prefixe);

	// renvoyer la requete inerte si demandee
	if (!$requeter) {
		return $query;
	}

	if (isset($_GET['var_profile'])) {
		include_spip('public/tracer');
		$t = trace_query_start();
	} else {
		$t = 0;
	}

	$connexion['last'] = $query;
	$connexion['total_requetes']++;

	// ajouter un debug utile dans log/mysql-slow.log ?
	$debug = '';
	if (defined('_DEBUG_SLOW_QUERIES') and _DEBUG_SLOW_QUERIES) {
		if (isset($GLOBALS['debug']['aucasou'])) {
			list(, $id, , $infos) = $GLOBALS['debug']['aucasou'];
			$debug .= "BOUCLE$id @ " . $infos[0] . " | ";
		}
		$debug .= $_SERVER['REQUEST_URI'] . ' + ' . $GLOBALS['ip'];
		$debug = ' /* ' . mysqli_real_escape_string(str_replace('*/', '@/', $debug)) . ' */';
	}

	$r = mysqli_query($link, $query . $debug);

	//Eviter de propager le GoneAway sur les autres requetes d'un même processus PHP
	if ($e = spip_mysql_errno($serveur)) {  // Log d'un Gone Away
		if ($e == 2006) { //Si Gone Away on relance une connexion vierge
			//Fermer la connexion defaillante
			mysqli_close($connexion['link']);
			unset($GLOBALS['connexions'][$serveur ? strtolower($serveur) : 0]);
			//Relancer une connexion vierge
			spip_connect($serveur);
			$connexion = &$GLOBALS['connexions'][$serveur ? strtolower($serveur) : 0];
			$link = $connexion['link'];
			//On retente au cas où
			$r = mysqli_query($link, $query . $debug);
		}
	}

	if ($e = spip_mysql_errno($serveur))  // Log de l'erreur eventuelle
	{
		$e .= spip_mysql_error($query, $serveur);
	} // et du fautif
	return $t ? trace_query_end($query, $t, $r, $e, $serveur) : $r;
}

/**
 * Modifie une structure de table MySQL
 *
 * @param string $query Requête SQL (sans 'ALTER ')
 * @param string $serveur Nom de la connexion
 * @param bool $requeter Exécuter la requête, sinon la retourner
 * @return array|bool|string
 *     - string : Texte de la requête si on ne l'exécute pas
 *     - 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 spip_mysql_alter($query, $serveur = '', $requeter = true) {
	// ici on supprime les ` entourant le nom de table pour permettre
	// la transposition du prefixe, compte tenu que les plugins ont la mauvaise habitude
	// d'utiliser ceux-ci, copie-colle de phpmyadmin
	$query = preg_replace(",^TABLE\s*`([^`]*)`,i", "TABLE \\1", $query);

	return spip_mysql_query("ALTER " . $query, $serveur, $requeter); # i.e. que PG se debrouille
}


/**
 * Optimise une table MySQL
 *
 * @param string $table Nom de la table
 * @param string $serveur Nom de la connexion
 * @param bool $requeter inutilisé
 * @return bool            Toujours true
 */
function spip_mysql_optimize($table, $serveur = '', $requeter = true) {
	spip_mysql_query("OPTIMIZE TABLE " . $table);

	return true;
}


/**
 * Retourne une explication de requête (Explain) MySQL
 *
 * @param string $query Texte de la requête
 * @param string $serveur Nom de la connexion
 * @param bool $requeter inutilisé
 * @return array           Tableau de l'explication
 */
function spip_mysql_explain($query, $serveur = '', $requeter = true) {
	if (strpos(ltrim($query), 'SELECT') !== 0) {
		return array();
	}
	$connexion = &$GLOBALS['connexions'][$serveur ? strtolower($serveur) : 0];
	$prefixe = $connexion['prefixe'];
	$link = $connexion['link'];
	$db = $connexion['db'];

	$query = 'EXPLAIN ' . _mysql_traite_query($query, $db, $prefixe);
	$r = mysqli_query($link, $query);

	return spip_mysql_fetch($r, null, $serveur);
}


/**
 * Exécute une requête de sélection avec MySQL
 *
 * Instance de sql_select (voir ses specs).
 *
 * @see sql_select()
 * @note
 *     Les `\n` et `\t` sont utiles au debusqueur.
 *
 * @param string|array $select Champs sélectionnés
 * @param string|array $from Tables sélectionnées
 * @param string|array $where Contraintes
 * @param string|array $groupby Regroupements
 * @param string|array $orderby Tris
 * @param string $limit Limites de résultats
 * @param string|array $having Contraintes posts sélections
 * @param string $serveur Nom de la connexion
 * @param bool $requeter Exécuter la requête, sinon la retourner
 * @return array|bool|resource|string
 *     - string : Texte de la requête si on ne l'exécute pas
 *     - ressource si requête exécutée, ressource pour fetch()
 *     - false si la requête exécutée a ratée
 *     - array  : Tableau décrivant requête et temps d'exécution si var_profile actif pour tracer.
 */
function spip_mysql_select(
	$select,
	$from,
	$where = '',
	$groupby = '',
	$orderby = '',
	$limit = '',
	$having = '',
	$serveur = '',
	$requeter = true
) {


	$from = (!is_array($from) ? $from : spip_mysql_select_as($from));
	$query =
		calculer_mysql_expression('SELECT', $select, ', ')
		. calculer_mysql_expression('FROM', $from, ', ')
		. calculer_mysql_expression('WHERE', $where)
		. calculer_mysql_expression('GROUP BY', $groupby, ',')
		. calculer_mysql_expression('HAVING', $having)
		. ($orderby ? ("\nORDER BY " . spip_mysql_order($orderby)) : '')
		. ($limit ? "\nLIMIT $limit" : '');

	// renvoyer la requete inerte si demandee
	if ($requeter === false) {
		return $query;
	}
	$r = spip_mysql_query($query, $serveur, $requeter);

	return $r ? $r : $query;
}


/**
 * Prépare une clause order by
 *
 * Regroupe en texte les éléments si un tableau est donné
 *
 * @note
 *   0+x avec un champ x commencant par des chiffres est converti par MySQL
 *   en le nombre qui commence x. Pas portable malheureusement, on laisse pour le moment.
 *
 * @param string|array $orderby Texte du orderby à préparer
 * @return string Texte du orderby préparé
 */
function spip_mysql_order($orderby) {
	return (is_array($orderby)) ? join(", ", $orderby) : $orderby;
}


/**
 * Prépare une clause WHERE pour MySQL
 *
 * Retourne une chaîne avec les bonnes parenthèses pour la
 * contrainte indiquée, au format donnée par le compilateur
 *
 * @param array|string $v
 *     Description des contraintes
 *     - string : Texte du where
 *     - sinon tableau : A et B peuvent être de type string ou array,
 *       OP et C sont de type string :
 *       - array(A) : A est le texte du where
 *       - array(OP, A) : contrainte OP( A )
 *       - array(OP, A, B) : contrainte (A OP B)
 *       - array(OP, A, B, C) : contrainte (A OP (B) : C)
 * @return string
 *     Contrainte pour clause WHERE
 */
function calculer_mysql_where($v) {
	if (!is_array($v)) {
		return $v;
	}

	$op = array_shift($v);
	if (!($n = count($v))) {
		return $op;
	} else {
		$arg = calculer_mysql_where(array_shift($v));
		if ($n == 1) {
			return "$op($arg)";
		} else {
			$arg2 = calculer_mysql_where(array_shift($v));
			if ($n == 2) {
				return "($arg $op $arg2)";
			} else {
				return "($arg $op ($arg2) : $v[0])";
			}
		}
	}
}

/**
 * Calcule un expression pour une requête, en cumulant chaque élément
 * avec l'opérateur de liaison ($join) indiqué
 *
 * Renvoie grosso modo "$expression join($join, $v)"
 *
 * @param string $expression Mot clé de l'expression, tel que "WHERE" ou "ORDER BY"
 * @param array|string $v Données de l'expression
 * @param string $join Si les données sont un tableau, elles seront groupées par cette jointure
 * @return string            Texte de l'expression, une partie donc, du texte la requête.
 */
function calculer_mysql_expression($expression, $v, $join = 'AND') {
	if (empty($v)) {
		return '';
	}

	$exp = "\n$expression ";

	if (!is_array($v)) {
		return $exp . $v;
	} else {
		if (strtoupper($join) === 'AND') {
			return $exp . join("\n\t$join ", array_map('calculer_mysql_where', $v));
		} else {
			return $exp . join($join, $v);
		}
	}
}


/**
 * Renvoie des `nom AS alias`
 *
 * @param array $args
 * @return string Sélection de colonnes pour une clause SELECT
 */
function spip_mysql_select_as($args) {
	$res = '';
	foreach ($args as $k => $v) {
		if (substr($k, -1) == '@') {
			// c'est une jointure qui se refere au from precedent
			// pas de virgule
			$res .= '  ' . $v;
		} else {
			if (!is_numeric($k)) {
				$p = strpos($v, " ");
				if ($p) {
					$v = substr($v, 0, $p) . " AS `$k`" . substr($v, $p);
				} else {
					$v .= " AS `$k`";
				}
			}
			$res .= ', ' . $v;
		}
	}

	return substr($res, 2);
}


/**
 * Changer les noms des tables ($table_prefix)
 *
 * TODO: Quand tous les appels SQL seront abstraits on pourra l'améliorer
 */
define('_SQL_PREFIXE_TABLE_MYSQL', '/([,\s])spip_/S');


/**
 * Prépare le texte d'une requête avant son exécution
 *
 * Change les préfixes de tables SPIP par ceux véritables
 *
 * @param string $query Requête à préparer
 * @param string $db Nom de la base de donnée
 * @param string $prefixe Préfixe de tables à appliquer
 * @return string           Requête préparée
 */
function _mysql_traite_query($query, $db = '', $prefixe = '') {

	if ($GLOBALS['mysql_rappel_nom_base'] and $db) {
		$pref = '`' . $db . '`.';
	} else {
		$pref = '';
	}

	if ($prefixe) {
		$pref .= $prefixe . "_";
	}

	if (!preg_match('/\s(SET|VALUES|WHERE|DATABASE)\s/i', $query, $regs)) {
		$suite = '';
	} else {
		$suite = strstr($query, $regs[0]);
		$query = substr($query, 0, -strlen($suite));
		// propager le prefixe en cas de requete imbriquee
		// il faut alors echapper les chaine avant de le faire, pour ne pas risquer de
		// modifier une requete qui est en fait juste du texte dans un champ
		if (stripos($suite, "SELECT") !== false) {
			list($suite, $textes) = query_echappe_textes($suite);
			if (preg_match('/^(.*?)([(]\s*SELECT\b.*)$/si', $suite, $r)) {
				$suite = $r[1] . _mysql_traite_query($r[2], $db, $prefixe);
			}
			$suite = query_reinjecte_textes($suite, $textes);
		}
	}
	$r = preg_replace(_SQL_PREFIXE_TABLE_MYSQL, '\1' . $pref, $query) . $suite;

	// en option, remplacer les emoji (que mysql ne sait pas gérer) en &#128169;
	if (defined('_MYSQL_NOPLANES') and _MYSQL_NOPLANES and lire_meta('charset_sql_connexion') == 'utf8') {
		include_spip('inc/charsets');
		$r = utf8_noplanes($r);
	}

	#spip_log("_mysql_traite_query: " . substr($r,0, 50) . ".... $db, $prefixe", _LOG_DEBUG);
	return $r;
}

/**
 * Sélectionne une base de données
 *
 * @param string $db
 *     Nom de la base à utiliser
 * @param string $serveur
 *     Nom du connecteur
 * @param bool $requeter
 *     Inutilisé
 *
 * @return bool
 *     - True cas de succès.
 *     - False en cas d'erreur.
 **/
function spip_mysql_selectdb($db, $serveur = '', $requeter = true) {
	$link = _mysql_link($serveur);
	$ok = mysqli_select_db($link, $db);
	if (!$ok) {
		spip_log('Echec mysqli_selectdb. Erreur : ' . mysqli_error($link), 'mysql.' . _LOG_CRITIQUE);
	}

	return $ok;
}


/**
 * Retourne les bases de données accessibles
 *
 * Retourne un tableau du nom de toutes les bases de données
 * accessibles avec les permissions de l'utilisateur SQL
 * de cette connexion.
 *
 * Attention on n'a pas toujours les droits !
 *
 * @param string $serveur
 *     Nom du connecteur
 * @param bool $requeter
 *     Inutilisé
 * @return array
 *     Liste de noms de bases de données
 **/
function spip_mysql_listdbs($serveur = '', $requeter = true) {
	$dbs = array();
	if ($res = spip_mysql_query("SHOW DATABASES", $serveur)) {
		while ($row = mysqli_fetch_assoc($res)) {
			$dbs[] = $row['Database'];
		}
	}

	return $dbs;
}


/**
 * Crée une table SQL
 *
 * Crée une table SQL nommee `$nom` à partir des 2 tableaux `$champs` et `$cles`
 *
 * @note Le nom des caches doit être inferieur à 64 caractères
 *
 * @param string $nom Nom de la table SQL
 * @param array $champs Couples (champ => description SQL)
 * @param array $cles Couples (type de clé => champ(s) de la clé)
 * @param bool $autoinc True pour ajouter un auto-incrément sur la Primary Key
 * @param bool $temporary True pour créer une table temporaire
 * @param string $serveur Nom de la connexion
 * @param bool $requeter inutilisé
 * @return array|null|resource|string
 *     - null si champs ou cles n'est pas un tableau
 *     - true si la requête réussie, false sinon.
 */
function spip_mysql_create(
	$nom,
	$champs,
	$cles,
	$autoinc = false,
	$temporary = false,
	$serveur = '',
	$requeter = true
) {

	$query = '';
	$keys = '';
	$s = '';
	$p = '';

	// certains plugins declarent les tables  (permet leur inclusion dans le dump)
	// sans les renseigner (laisse le compilo recuperer la description)
	if (!is_array($champs) || !is_array($cles)) {
		return;
	}

	$res = spip_mysql_query("SELECT version() as v", $serveur);
	if (($row = mysqli_fetch_array($res)) && (version_compare($row['v'], '5.0', '>='))) {
		spip_mysql_query("SET sql_mode=''", $serveur);
	}

	foreach ($cles as $k => $v) {
		$keys .= "$s\n\t\t$k ($v)";
		if ($k == "PRIMARY KEY") {
			$p = $v;
		}
		$s = ",";
	}
	$s = '';

	$character_set = "";
	if (@$GLOBALS['meta']['charset_sql_base']) {
		$character_set .= " CHARACTER SET " . $GLOBALS['meta']['charset_sql_base'];
	}
	if (@$GLOBALS['meta']['charset_collation_sql_base']) {
		$character_set .= " COLLATE " . $GLOBALS['meta']['charset_collation_sql_base'];
	}

	foreach ($champs as $k => $v) {
		$v = _mysql_remplacements_definitions_table($v);
		if (preg_match(',([a-z]*\s*(\(\s*[0-9]*\s*\))?(\s*binary)?),i', $v, $defs)) {
			if (preg_match(',(char|text),i', $defs[1])
				and !preg_match(',(binary|CHARACTER|COLLATE),i', $v)
			) {
				$v = $defs[1] . $character_set . ' ' . substr($v, strlen($defs[1]));
			}
		}

		$query .= "$s\n\t\t$k $v"
			. (($autoinc && ($p == $k) && preg_match(',\b(big|small|medium)?int\b,i', $v))
				? " auto_increment"
				: ''
			);
		$s = ",";
	}
	$temporary = $temporary ? 'TEMPORARY' : '';
	$q = "CREATE $temporary TABLE IF NOT EXISTS $nom ($query" . ($keys ? ",$keys" : '') . ")"
		. " ENGINE=MyISAM"
		. ($character_set ? " DEFAULT $character_set" : "")
		. "\n";

	return spip_mysql_query($q, $serveur);
}


/**
 * Adapte pour Mysql la déclaration SQL d'une colonne d'une table
 *
 * @param string $query
 *     Définition SQL d'un champ de table
 * @return string
 *     Définition SQL adaptée pour MySQL d'un champ de table
 */
function _mysql_remplacements_definitions_table($query) {
	// quelques remplacements
	$num = "(\s*\([0-9]*\))?";
	$enum = "(\s*\([^\)]*\))?";

	$remplace = array(
		'/VARCHAR(\s*[^\s\(])/is' => 'VARCHAR(255)\\1',
	);

	$query = preg_replace(array_keys($remplace), $remplace, $query);

	return $query;
}


/**
 * Crée une base de données MySQL
 *
 * @param string $nom Nom de la base
 * @param string $serveur Nom de la connexion
 * @param bool $requeter Exécuter la requête, sinon la retourner
 * @return bool true si la base est créee.
 **/
function spip_mysql_create_base($nom, $serveur = '', $requeter = true) {
	return spip_mysql_query("CREATE DATABASE `$nom`", $serveur, $requeter);
}


/**
 * Crée une vue SQL nommée `$nom`
 *
 * @param string $nom
 *    Nom de la vue à creer
 * @param string $query_select
 *     Texte de la requête de sélection servant de base à la vue
 * @param string $serveur
 *     Nom du connecteur
 * @param bool $requeter
 *     Effectuer la requete, sinon la retourner
 * @return bool|string
 *     - true si la vue est créée
 *     - false si erreur ou si la vue existe déja
 *     - string texte de la requête si $requeter vaut false
 */
function spip_mysql_create_view($nom, $query_select, $serveur = '', $requeter = true) {
	if (!$query_select) {
		return false;
	}
	// vue deja presente
	if (sql_showtable($nom, false, $serveur)) {
		spip_log("Echec creation d'une vue sql ($nom) car celle-ci existe deja (serveur:$serveur)", _LOG_ERREUR);

		return false;
	}

	$query = "CREATE VIEW $nom AS " . $query_select;

	return spip_mysql_query($query, $serveur, $requeter);
}


/**
 * Supprime une table SQL
 *
 * @param string $table Nom de la table SQL
 * @param string $exist True pour ajouter un test d'existence avant de supprimer
 * @param string $serveur Nom de la connexion
 * @param bool $requeter Exécuter la requête, sinon la retourner
 * @return bool|string
 *     - string Texte de la requête si demandé
 *     - true si la requête a réussie, false sinon
 */
function spip_mysql_drop_table($table, $exist = '', $serveur = '', $requeter = true) {
	if ($exist) {
		$exist = " IF EXISTS";
	}

	return spip_mysql_query("DROP TABLE$exist $table", $serveur, $requeter);
}

/**
 * Supprime une vue SQL
 *
 * @param string $view 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 $requeter Exécuter la requête, sinon la retourner
 * @return bool|string
 *     - string Texte de la requête si demandé
 *     - true si la requête a réussie, false sinon
 */
function spip_mysql_drop_view($view, $exist = '', $serveur = '', $requeter = true) {
	if ($exist) {
		$exist = " IF EXISTS";
	}

	return spip_mysql_query("DROP VIEW$exist $view", $serveur, $requeter);
}

/**
 * Retourne une ressource de la liste des tables de la base de données
 *
 * @param string $match
 *     Filtre sur tables à récupérer
 * @param string $serveur
 *     Connecteur de la base
 * @param bool $requeter
 *     true pour éxecuter la requête
 *     false pour retourner le texte de la requête.
 * @return ressource
 *     Ressource à utiliser avec sql_fetch()
 **/
function spip_mysql_showbase($match, $serveur = '', $requeter = true) {
	return spip_mysql_query("SHOW TABLES LIKE " . _q($match), $serveur, $requeter);
}

/**
 * Répare une table SQL
 *
 * Utilise `REPAIR TABLE ...` de MySQL
 *
 * @param string $table Nom de la table SQL
 * @param string $serveur Nom de la connexion
 * @param bool $requeter Exécuter la requête, sinon la retourner
 * @return bool|string
 *     - string Texte de la requête si demandée,
 *     - true si la requête a réussie, false sinon
 */
function spip_mysql_repair($table, $serveur = '', $requeter = true) {
	return spip_mysql_query("REPAIR TABLE `$table`", $serveur, $requeter);
}


define('_MYSQL_RE_SHOW_TABLE', '/^[^(),]*\(((?:[^()]*\((?:[^()]*\([^()]*\))?[^()]*\)[^()]*)*[^()]*)\)[^()]*$/');
/**
 * Obtient la description d'une table ou vue MySQL
 *
 * Récupère la définition d'une table ou d'une vue avec colonnes, indexes, etc.
 * au même format que la définition des tables SPIP, c'est à dire
 * un tableau avec les clés
 *
 * - `field` (tableau colonne => description SQL) et
 * - `key` (tableau type de clé => colonnes)
 *
 * @param string $nom_table Nom de la table SQL
 * @param string $serveur Nom de la connexion
 * @param bool $requeter Exécuter la requête, sinon la retourner
 * @return array|string
 *     - chaîne vide si pas de description obtenue
 *     - string Texte de la requête si demandé
 *     - array description de la table sinon
 */
function spip_mysql_showtable($nom_table, $serveur = '', $requeter = true) {
	$s = spip_mysql_query("SHOW CREATE TABLE `$nom_table`", $serveur, $requeter);
	if (!$s) {
		return '';
	}
	if (!$requeter) {
		return $s;
	}

	list(, $a) = mysqli_fetch_array($s, MYSQLI_NUM);
	if (preg_match(_MYSQL_RE_SHOW_TABLE, $a, $r)) {
		$desc = $r[1];
		// extraction d'une KEY éventuelle en prenant garde de ne pas
		// relever un champ dont le nom contient KEY (ex. ID_WHISKEY)
		if (preg_match("/^(.*?),([^,]*\sKEY[ (].*)$/s", $desc, $r)) {
			$namedkeys = $r[2];
			$desc = $r[1];
		} else {
			$namedkeys = "";
		}

		$fields = array();
		foreach (preg_split("/,\s*`/", $desc) as $v) {
			preg_match("/^\s*`?([^`]*)`\s*(.*)/", $v, $r);
			$fields[strtolower($r[1])] = $r[2];
		}
		$keys = array();

		foreach (preg_split('/\)\s*(,|$)/', $namedkeys) as $v) {
			if (preg_match("/^\s*([^(]*)\(([^(]*(\(\d+\))?)$/", $v, $r)) {
				$k = str_replace("`", '', trim($r[1]));
				$t = strtolower(str_replace("`", '', $r[2]));
				if ($k && !isset($keys[$k])) {
					$keys[$k] = $t;
				} else {
					$keys[] = $t;
				}
			}
		}
		spip_mysql_free($s);

		return array('field' => $fields, 'key' => $keys);
	}

	$res = spip_mysql_query("SHOW COLUMNS FROM `$nom_table`", $serveur);
	if ($res) {
		$nfields = array();
		$nkeys = array();
		while ($val = spip_mysql_fetch($res)) {
			$nfields[$val["Field"]] = $val['Type'];
			if ($val['Null'] == 'NO') {
				$nfields[$val["Field"]] .= ' NOT NULL';
			}
			if ($val['Default'] === '0' || $val['Default']) {
				if (preg_match('/[A-Z_]/', $val['Default'])) {
					$nfields[$val["Field"]] .= ' DEFAULT ' . $val['Default'];
				} else {
					$nfields[$val["Field"]] .= " DEFAULT '" . $val['Default'] . "'";
				}
			}
			if ($val['Extra']) {
				$nfields[$val["Field"]] .= ' ' . $val['Extra'];
			}
			if ($val['Key'] == 'PRI') {
				$nkeys['PRIMARY KEY'] = $val["Field"];
			} else {
				if ($val['Key'] == 'MUL') {
					$nkeys['KEY ' . $val["Field"]] = $val["Field"];
				} else {
					if ($val['Key'] == 'UNI') {
						$nkeys['UNIQUE KEY ' . $val["Field"]] = $val["Field"];
					}
				}
			}
		}
		spip_mysql_free($res);

		return array('field' => $nfields, 'key' => $nkeys);
	}

	return "";
}


/**
 * Rècupère une ligne de résultat
 *
 * Récupère la ligne suivante d'une ressource de résultat
 *
 * @param Ressource $r Ressource de résultat (issu de sql_select)
 * @param string $t Structure de résultat attendu (défaut MYSQLI_ASSOC)
 * @param string $serveur Nom de la connexion
 * @param bool $requeter Inutilisé
 * @return array           Ligne de résultat
 */
function spip_mysql_fetch($r, $t = '', $serveur = '', $requeter = true) {
	if (!$t) {
		$t = MYSQLI_ASSOC;
	}
	if ($r) {
		return mysqli_fetch_array($r, $t);
	}
}

/**
 * Place le pointeur de résultat sur la position indiquée
 *
 * @param Ressource $r Ressource de résultat
 * @param int $row_number Position. Déplacer le pointeur à cette ligne
 * @param string $serveur Nom de la connexion
 * @param bool $requeter Inutilisé
 * @return bool True si déplacement réussi, false sinon.
 **/
function spip_mysql_seek($r, $row_number, $serveur = '', $requeter = true) {
	if ($r and mysqli_num_rows($r)) {
		return mysqli_data_seek($r, $row_number);
	}
}


/**
 * Retourne le nombre de lignes d'une sélection
 *
 * @param array|string $from Tables à consulter (From)
 * @param array|string $where Conditions a remplir (Where)
 * @param array|string $groupby Critère de regroupement (Group by)
 * @param array $having Tableau des des post-conditions à remplir (Having)
 * @param string $serveur Nom de la connexion
 * @param bool $requeter Exécuter la requête, sinon la retourner
 * @return int|string
 *     - String Texte de la requête si demandé
 *     - int Nombre de lignes (0 si la requête n'a pas réussie)
 **/
function spip_mysql_countsel(
	$from = array(),
	$where = array(),
	$groupby = '',
	$having = array(),
	$serveur = '',
	$requeter = true
) {
	$c = !$groupby ? '*' : ('DISTINCT ' . (is_string($groupby) ? $groupby : join(',', $groupby)));

	$r = spip_mysql_select("COUNT($c)", $from, $where, '', '', '', $having, $serveur, $requeter);
	if (!$requeter) {
		return $r;
	}
	if (!$r instanceof mysqli_result) {
		return 0;
	}
	list($c) = mysqli_fetch_array($r, MYSQLI_NUM);
	mysqli_free_result($r);

	return $c;
}


/**
 * Retourne la dernière erreur generée
 *
 * @note
 *   Bien spécifier le serveur auquel on s'adresse,
 *   mais à l'install la globale n'est pas encore complètement définie.
 *
 * @uses sql_error_backtrace()
 *
 * @param string $query
 *     Requête qui était exécutée
 * @param string $serveur
 *     Nom de la connexion
 * @param bool $requeter
 *     Inutilisé
 * @return string
 *     Erreur eventuelle
 **/
function spip_mysql_error($query = '', $serveur = '', $requeter = true) {
	$link = $GLOBALS['connexions'][$serveur ? strtolower($serveur) : 0]['link'];
	$s = mysqli_error($link);
	if ($s) {
		$trace = debug_backtrace();
		if ($trace[0]['function'] != "spip_mysql_error") {
			spip_log("$s - $query - " . sql_error_backtrace(), 'mysql.' . _LOG_ERREUR);
		}
	}

	return $s;
}


/**
 * Retourne le numero de la dernière erreur SQL
 *
 * @param string $serveur
 *     Nom de la connexion
 * @param bool $requeter
 *     Inutilisé
 * @return int
 *     0, pas d'erreur. Autre, numéro de l'erreur.
 **/
function spip_mysql_errno($serveur = '', $requeter = true) {
	$link = $GLOBALS['connexions'][$serveur ? $serveur : 0]['link'];
	$s = mysqli_errno($link);
	// 2006 MySQL server has gone away
	// 2013 Lost connection to MySQL server during query
	if (in_array($s, array(2006, 2013))) {
		define('spip_interdire_cache', true);
	}
	if ($s) {
		spip_log("Erreur mysql $s", _LOG_ERREUR);
	}

	return $s;
}


/**
 * Retourne le nombre de lignes d’une ressource de sélection obtenue
 * avec `sql_select()`
 *
 * @param Ressource $r Ressource de résultat
 * @param string $serveur Nom de la connexion
 * @param bool $requeter Inutilisé
 * @return int               Nombre de lignes
 */
function spip_mysql_count($r, $serveur = '', $requeter = true) {
	if ($r) {
		return mysqli_num_rows($r);
	}
}


/**
 * Libère une ressource de résultat
 *
 * Indique à MySQL 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 $r Ressource de résultat
 * @param string $serveur Nom de la connexion
 * @param bool $requeter Inutilisé
 * @return bool              True si réussi
 */
function spip_mysql_free($r, $serveur = '', $requeter = true) {
	return (($r instanceof mysqli_result) ? mysqli_free_result($r) : false);
}


/**
 * Insère une ligne dans une table
 *
 * @param string $table
 *     Nom de la table SQL
 * @param string $champs
 *     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 $requeter
 *     Exécuter la requête, sinon la retourner
 * @return bool|string|int|array
 *     - 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,
 *     - Tableau de description de la requête et du temps d'exécution, si var_profile activé
 **/
function spip_mysql_insert($table, $champs, $valeurs, $desc = array(), $serveur = '', $requeter = true) {

	$connexion = &$GLOBALS['connexions'][$serveur ? strtolower($serveur) : 0];
	$prefixe = $connexion['prefixe'];
	$link = $connexion['link'];
	$db = $connexion['db'];

	if ($prefixe) {
		$table = preg_replace('/^spip/', $prefixe, $table);
	}

	$query = "INSERT INTO $table $champs VALUES $valeurs";
	if (!$requeter) {
		return $query;
	}

	if (isset($_GET['var_profile'])) {
		include_spip('public/tracer');
		$t = trace_query_start();
	} else {
		$t = 0;
	}

	$connexion['last'] = $query;
	#spip_log($query, 'mysql.'._LOG_DEBUG);
	$r = false;
	if (mysqli_query($link, $query)) {
		$r = mysqli_insert_id($link);
	} else {
		if ($e = spip_mysql_errno($serveur))  // Log de l'erreur eventuelle
		{
			$e .= spip_mysql_error($query, $serveur);
		} // et du fautif
	}

	return $t ? trace_query_end($query, $t, $r, $e, $serveur) : $r;

	// return $r ? $r : (($r===0) ? -1 : 0); pb avec le multi-base.
}

/**
 * Insère une ligne dans une table, en protégeant chaque valeur
 *
 * @param string $table
 *     Nom de la table SQL
 * @param string $couples
 *    Couples (colonne => 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 $requeter
 *     Exécuter la requête, sinon la retourner
 * @return bool|string|int|array
 *     - 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,
 *     - Tableau de description de la requête et du temps d'exécution, si var_profile activé
 **/
function spip_mysql_insertq($table, $couples = array(), $desc = array(), $serveur = '', $requeter = true) {

	if (!$desc) {
		$desc = description_table($table, $serveur);
	}
	if (!$desc) {
		$couples = array();
	}
	$fields = isset($desc['field']) ? $desc['field'] : array();

	foreach ($couples as $champ => $val) {
		$couples[$champ] = spip_mysql_cite($val, $fields[$champ]);
	}

	return spip_mysql_insert($table, "(" . join(',', array_keys($couples)) . ")", "(" . join(',', $couples) . ")", $desc,
		$serveur, $requeter);
}


/**
 * Insère plusieurs lignes d'un coup dans une table
 *
 * @param string $table
 *     Nom de la table SQL
 * @param array $tab_couples
 *     Tableau de tableaux associatifs (colonne => 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 $requeter
 *     Exécuter la requête, sinon la retourner
 * @return bool|string
 *     - True en cas de succès,
 *     - Texte de la requête si demandé,
 *     - False en cas d'erreur.
 **/
function spip_mysql_insertq_multi($table, $tab_couples = array(), $desc = array(), $serveur = '', $requeter = true) {

	if (!$desc) {
		$desc = description_table($table, $serveur);
	}
	if (!$desc) {
		$tab_couples = array();
	}
	$fields = isset($desc['field']) ? $desc['field'] : array();

	$cles = "(" . join(',', array_keys(reset($tab_couples))) . ')';
	$valeurs = array();
	$r = false;

	// Quoter et Inserer par groupes de 100 max pour eviter un debordement de pile
	foreach ($tab_couples as $couples) {
		foreach ($couples as $champ => $val) {
			$couples[$champ] = spip_mysql_cite($val, $fields[$champ]);
		}
		$valeurs[] = '(' . join(',', $couples) . ')';
		if (count($valeurs) >= 100) {
			$r = spip_mysql_insert($table, $cles, join(', ', $valeurs), $desc, $serveur, $requeter);
			$valeurs = array();
		}
	}
	if (count($valeurs)) {
		$r = spip_mysql_insert($table, $cles, join(', ', $valeurs), $desc, $serveur, $requeter);
	}

	return $r; // dans le cas d'une table auto_increment, le dernier insert_id
}

/**
 * Met à jour des enregistrements d'une table SQL
 *
 * @param string $table
 *     Nom de la table
 * @param array $champs
 *     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 $requeter
 *     Exécuter la requête, sinon la retourner
 * @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 spip_mysql_update($table, $champs, $where = '', $desc = array(), $serveur = '', $requeter = true) {
	$set = array();
	foreach ($champs as $champ => $val) {
		$set[] = $champ . "=$val";
	}
	if (!empty($set)) {
		return spip_mysql_query(
			calculer_mysql_expression('UPDATE', $table, ',')
			. calculer_mysql_expression('SET', $set, ',')
			. calculer_mysql_expression('WHERE', $where),
			$serveur, $requeter);
	}
}

/**
 * Met à jour des enregistrements d'une table SQL et protège chaque valeur
 *
 * Protège chaque valeur transmise avec sql_quote(), adapté au type
 * de champ attendu par la table SQL
 *
 * @note
 *   Les valeurs sont des constantes à mettre entre apostrophes
 *   sauf les expressions de date lorsqu'il s'agit de fonctions SQL (NOW etc)
 *
 * @param string $table
 *     Nom de la table
 * @param array $champs
 *     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 $requeter
 *     Exécuter la requête, sinon la retourner
 * @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 spip_mysql_updateq($table, $champs, $where = '', $desc = array(), $serveur = '', $requeter = true) {

	if (!$champs) {
		return;
	}
	if (!$desc) {
		$desc = description_table($table, $serveur);
	}
	if (!$desc) {
		$champs = array();
	} else {
		$fields = $desc['field'];
	}
	$set = array();
	foreach ($champs as $champ => $val) {
		$set[] = $champ . '=' . spip_mysql_cite($val, @$fields[$champ]);
	}

	return spip_mysql_query(
		calculer_mysql_expression('UPDATE', $table, ',')
		. calculer_mysql_expression('SET', $set, ',')
		. calculer_mysql_expression('WHERE', $where),
		$serveur, $requeter);
}

/**
 * Supprime des enregistrements d'une table
 *
 * @param string $table Nom de la table SQL
 * @param string|array $where Conditions à vérifier
 * @param string $serveur Nom du connecteur
 * @param bool $requeter Exécuter la requête, sinon la retourner
 * @return bool|string
 *     - int : nombre de suppressions réalisées,
 *     - Texte de la requête si demandé,
 *     - False en cas d'erreur.
 **/
function spip_mysql_delete($table, $where = '', $serveur = '', $requeter = true) {
	$res = spip_mysql_query(
		calculer_mysql_expression('DELETE FROM', $table, ',')
		. calculer_mysql_expression('WHERE', $where),
		$serveur, $requeter);
	if (!$requeter) {
		return $res;
	}
	if ($res) {
		$link = _mysql_link($serveur);

		return mysqli_affected_rows($link);
	} else {
		return false;
	}
}


/**
 * 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 updateq ou insertq.
 *
 * @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 $requeter
 *     Exécuter la requête, sinon la retourner
 * @return bool|string
 *     - true si réussite
 *     - Texte de la requête si demandé,
 *     - False en cas d'erreur.
 **/
function spip_mysql_replace($table, $couples, $desc = array(), $serveur = '', $requeter = true) {
	return spip_mysql_query("REPLACE $table (" . join(',', array_keys($couples)) . ') VALUES (' . join(',',
			array_map('_q', $couples)) . ')', $serveur, $requeter);
}


/**
 * 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 insertq_multi et sql_updateq
 *
 * @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 $requeter
 *     Exécuter la requête, sinon la retourner
 * @return bool|string
 *     - true si réussite
 *     - Texte de la requête si demandé,
 *     - False en cas d'erreur.
 **/
function spip_mysql_replace_multi($table, $tab_couples, $desc = array(), $serveur = '', $requeter = true) {
	$cles = "(" . join(',', array_keys($tab_couples[0])) . ')';
	$valeurs = array();
	foreach ($tab_couples as $couples) {
		$valeurs[] = '(' . join(',', array_map('_q', $couples)) . ')';
	}
	$valeurs = implode(', ', $valeurs);

	return spip_mysql_query("REPLACE $table $cles VALUES $valeurs", $serveur, $requeter);
}


/**
 * 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).
 *
 * @param string $objet Colonne ayant le texte
 * @param string $lang Langue à extraire
 * @return string       Texte de sélection pour la requête
 */
function spip_mysql_multi($objet, $lang) {
	$lengthlang = strlen("[$lang]");
	$posmulti = "INSTR(" . $objet . ", '<multi>')";
	$posfinmulti = "INSTR(" . $objet . ", '</multi>')";
	$debutchaine = "LEFT(" . $objet . ", $posmulti-1)";
	$finchaine = "RIGHT(" . $objet . ", CHAR_LENGTH(" . $objet . ") -(7+$posfinmulti))";
	$chainemulti = "TRIM(SUBSTRING(" . $objet . ", $posmulti+7, $posfinmulti -(7+$posmulti)))";
	$poslang = "INSTR($chainemulti,'[" . $lang . "]')";
	$poslang = "IF($poslang=0,INSTR($chainemulti,']')+1,$poslang+$lengthlang)";
	$chainelang = "TRIM(SUBSTRING(" . $objet . ", $posmulti+7+$poslang-1,$posfinmulti -($posmulti+7+$poslang-1) ))";
	$posfinlang = "INSTR(" . $chainelang . ", '[')";
	$chainelang = "IF($posfinlang>0,LEFT($chainelang,$posfinlang-1),$chainelang)";
	//$chainelang = "LEFT($chainelang,$posfinlang-1)";
	$retour = "(TRIM(IF($posmulti = 0 , " .
		"     TRIM(" . $objet . "), " .
		"     CONCAT( " .
		"          $debutchaine, " .
		"          IF( " .
		"               $poslang = 0, " .
		"                     $chainemulti, " .
		"               $chainelang" .
		"          ), " .
		"          $finchaine" .
		"     ) " .
		"))) AS multi";

	return $retour;
}

/**
 * Prépare une chaîne hexadécimale
 *
 * Par exemple : FF ==> 0xFF en MySQL
 *
 * @param string $v
 *     Chaine hexadecimale
 * @return string
 *     Valeur hexadécimale pour MySQL
 **/
function spip_mysql_hex($v) {
	return "0x" . $v;
}

/**
 * Échapper une valeur selon son type ou au mieux
 * comme le fait `_q()` mais pour MySQL avec ses spécificités
 *
 * @param string|array|number $v
 *     Texte, nombre ou tableau à échapper
 * @param string $type
 *     Description du type attendu
 *    (par exemple description SQL de la colonne recevant la donnée)
 * @return string|number
 *    Donnée prête à être utilisée par le gestionnaire SQL
 */
function spip_mysql_quote($v, $type = '') {
	if ($type) {
		if (!is_array($v)) {
			return spip_mysql_cite($v, $type);
		}
		// si c'est un tableau, le parcourir en propageant le type
		foreach ($v as $k => $r) {
			$v[$k] = spip_mysql_quote($r, $type);
		}

		return $v;
	}
	// si on ne connait pas le type, s'en remettre a _q :
	// on ne fera pas mieux
	else {
		return _q($v);
	}
}

/**
 * Tester si une date est proche de la valeur d'un champ
 *
 * @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, ...)
 * @return string
 *     Expression SQL
 **/
function spip_mysql_date_proche($champ, $interval, $unite) {
	return '('
	. $champ
	. (($interval <= 0) ? '>' : '<')
	. (($interval <= 0) ? 'DATE_SUB' : 'DATE_ADD')
	. '('
	. sql_quote(date('Y-m-d H:i:s'))
	. ', INTERVAL '
	. (($interval > 0) ? $interval : (0 - $interval))
	. ' '
	. $unite
	. '))';
}


/**
 * Retourne une expression IN pour le gestionnaire de base de données
 *
 * IN (...) est limité à 255 éléments, d'où cette fonction assistante
 *
 * @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 $requeter
 *     Inutilisé
 * @return string
 *     Expression de requête SQL
 **/
function spip_mysql_in($val, $valeurs, $not = '', $serveur = '', $requeter = true) {
	$n = $i = 0;
	$in_sql = "";
	while ($n = strpos($valeurs, ',', $n + 1)) {
		if ((++$i) >= 255) {
			$in_sql .= "($val $not IN (" .
				substr($valeurs, 0, $n) .
				"))\n" .
				($not ? "AND\t" : "OR\t");
			$valeurs = substr($valeurs, $n + 1);
			$i = $n = 0;
		}
	}
	$in_sql .= "($val $not IN ($valeurs))";

	return "($in_sql)";
}


/**
 * Retourne une expression IN pour le gestionnaire de base de données
 *
 * Pour compatibilité. Ne plus utiliser.
 *
 * @deprecated Utiliser sql_in()
 *
 * @param string $val Nom de la colonne
 * @param string|array $valeurs Valeurs
 * @param string $not NOT pour inverser
 * @return string               Expression de requête SQL
 */
function calcul_mysql_in($val, $valeurs, $not = '') {
	if (is_array($valeurs)) {
		$valeurs = join(',', array_map('_q', $valeurs));
	} elseif ($valeurs[0] === ',') {
		$valeurs = substr($valeurs, 1);
	}
	if (!strlen(trim($valeurs))) {
		return ($not ? "0=0" : '0=1');
	}

	return spip_mysql_in($val, $valeurs, $not);
}


/**
 * Renvoie les bons echappements (mais pas sur les fonctions comme NOW())
 *
 * @param string|number $v Texte ou nombre à échapper
 * @param string $type Type de donnée attendue, description SQL de la colonne de destination
 * @return string|number     Texte ou nombre échappé
 */
function spip_mysql_cite($v, $type) {
	if (is_null($v)
		and stripos($type, "NOT NULL") === false
	) {
		return 'NULL';
	} // null php se traduit en NULL SQL
	if (sql_test_date($type) and preg_match('/^\w+\(/', $v)) {
		return $v;
	}
	if (sql_test_int($type)) {
		if (is_numeric($v) or (ctype_xdigit(substr($v, 2))
				and $v[0] == '0' and $v[1] == 'x')
		) {
			return $v;
		} // si pas numerique, forcer le intval
		else {
			return intval($v);
		}
	}

	return ("'" . addslashes($v) . "'");
}


// Ces deux fonctions n'ont pas d'equivalent exact PostGres
// et ne sont la que pour compatibilite avec les extensions de SPIP < 1.9.3

/**
 * Poser un verrou SQL local
 *
 * Changer de nom toutes les heures en cas de blocage MySQL (ca arrive)
 *
 * @deprecated Pas d'équivalence actuellement en dehors de MySQL
 * @see spip_release_lock()
 *
 * @param string $nom
 *     Inutilisé. Le nom est calculé en fonction de la connexion principale
 * @param int $timeout
 * @return string|bool
 *     - Nom du verrou si réussite,
 *     - false sinon
 */
function spip_get_lock($nom, $timeout = 0) {

	define('_LOCK_TIME', intval(time() / 3600 - 316982));

	$connexion = &$GLOBALS['connexions'][0];
	$bd = $connexion['db'];
	$prefixe = $connexion['prefixe'];
	$nom = "$bd:$prefixe:$nom" . _LOCK_TIME;

	$connexion['last'] = $q = "SELECT GET_LOCK(" . _q($nom) . ", $timeout) AS n";
	$q = @sql_fetch(mysql_query($q));
	if (!$q) {
		spip_log("pas de lock sql pour $nom", _LOG_ERREUR);
	}

	return $q['n'];
}


/**
 * Relâcher un verrou SQL local
 *
 * @deprecated Pas d'équivalence actuellement en dehors de MySQL
 * @see spip_get_lock()
 *
 * @param string $nom
 *     Inutilisé. Le nom est calculé en fonction de la connexion principale
 * @return string|bool
 *     True si réussite, false sinon.
 */
function spip_release_lock($nom) {

	$connexion = &$GLOBALS['connexions'][0];
	$bd = $connexion['db'];
	$prefixe = $connexion['prefixe'];
	$nom = "$bd:$prefixe:$nom" . _LOCK_TIME;

	$connexion['last'] = $q = "SELECT RELEASE_LOCK(" . _q($nom) . ")";
	mysqli_query(_mysql_link(), $q);
}


/**
 * Teste si on a les fonctions MySQLi (pour l'install)
 *
 * @return bool
 *     True si on a les fonctions, false sinon
 */
function spip_versions_mysql() {
	charger_php_extension('mysqli');

	return function_exists('mysqli_query');
}


/**
 * Tester si mysql ne veut pas du nom de la base dans les requêtes
 *
 * @param string $server_db
 * @return string
 *     - chaîne vide si nom de la base utile
 *     - chaîne : code compilé pour le faire désactiver par SPIP sinon
 */
function test_rappel_nom_base_mysql($server_db) {
	$GLOBALS['mysql_rappel_nom_base'] = true;
	sql_delete('spip_meta', "nom='mysql_rappel_nom_base'", $server_db);
	$ok = spip_query("INSERT INTO spip_meta (nom,valeur) VALUES ('mysql_rappel_nom_base', 'test')", $server_db);

	if ($ok) {
		sql_delete('spip_meta', "nom='mysql_rappel_nom_base'", $server_db);

		return '';
	} else {
		$GLOBALS['mysql_rappel_nom_base'] = false;

		return "\$GLOBALS['mysql_rappel_nom_base'] = false; " .
		"/* echec de test_rappel_nom_base_mysql a l'installation. */\n";
	}
}

/**
 * Teste si on peut changer les modes de MySQL
 *
 * @link http://dev.mysql.com/doc/refman/5.0/fr/server-sql-mode.html
 *
 * @param string $server_db Nom de la connexion
 * @return string
 *     - chaîne vide si on ne peut pas appliquer de mode
 *     - chaîne : code compilé pour l'indiquer le résultat du test à SPIP
 */
function test_sql_mode_mysql($server_db) {
	$res = sql_select("version() as v", '', '', '', '', '', '', $server_db);
	$row = sql_fetch($res, $server_db);
	if (version_compare($row['v'], '5.0.0', '>=')) {
		defined('_MYSQL_SET_SQL_MODE') || define('_MYSQL_SET_SQL_MODE', true);

		return "defined('_MYSQL_SET_SQL_MODE') || define('_MYSQL_SET_SQL_MODE',true);\n";
	}

	return '';
}