PNG  IHDRX cHRMz&u0`:pQ<bKGD pHYsodtIME MeqIDATxw]Wug^Qd˶ 6`!N:!@xI~)%7%@Bh&`lnjVF29gΨ4E$|>cɚ{gk= %,a KX%,a KX%,a KX%,a KX%,a KX%,a KX%, b` ǟzeאfp]<!SJmɤY޲ڿ,%c ~ع9VH.!Ͳz&QynֺTkRR.BLHi٪:l;@(!MԴ=žI,:o&N'Kù\vRmJ雵֫AWic H@" !: Cé||]k-Ha oݜ:y F())u]aG7*JV@J415p=sZH!=!DRʯvɱh~V\}v/GKY$n]"X"}t@ xS76^[bw4dsce)2dU0 CkMa-U5tvLƀ~mlMwfGE/-]7XAƟ`׮g ewxwC4\[~7@O-Q( a*XGƒ{ ՟}$_y3tĐƤatgvێi|K=uVyrŲlLӪuܿzwk$m87k( `múcE)"@rK( z4$D; 2kW=Xb$V[Ru819קR~qloѱDyįݎ*mxw]y5e4K@ЃI0A D@"BDk_)N\8͜9dz"fK0zɿvM /.:2O{ Nb=M=7>??Zuo32 DLD@D| &+֎C #B8ַ`bOb $D#ͮҪtx]%`ES`Ru[=¾!@Od37LJ0!OIR4m]GZRJu$‡c=%~s@6SKy?CeIh:[vR@Lh | (BhAMy=݃  G"'wzn޺~8ԽSh ~T*A:xR[ܹ?X[uKL_=fDȊ؂p0}7=D$Ekq!/t.*2ʼnDbŞ}DijYaȲ(""6HA;:LzxQ‘(SQQ}*PL*fc\s `/d'QXW, e`#kPGZuŞuO{{wm[&NBTiiI0bukcA9<4@SӊH*؎4U/'2U5.(9JuDfrޱtycU%j(:RUbArLֺN)udA':uGQN"-"Is.*+k@ `Ojs@yU/ H:l;@yyTn}_yw!VkRJ4P)~y#)r,D =ě"Q]ci'%HI4ZL0"MJy 8A{ aN<8D"1#IJi >XjX֔#@>-{vN!8tRݻ^)N_╗FJEk]CT՟ YP:_|H1@ CBk]yKYp|og?*dGvzنzӴzjֺNkC~AbZƷ`.H)=!QͷVTT(| u78y֮}|[8-Vjp%2JPk[}ԉaH8Wpqhwr:vWª<}l77_~{s۴V+RCģ%WRZ\AqHifɤL36: #F:p]Bq/z{0CU6ݳEv_^k7'>sq*+kH%a`0ԣisqにtү04gVgW΂iJiS'3w.w}l6MC2uԯ|>JF5`fV5m`Y**Db1FKNttu]4ccsQNnex/87+}xaUW9y>ͯ骵G{䩓Գ3+vU}~jJ.NFRD7<aJDB1#ҳgSb,+CS?/ VG J?|?,2#M9}B)MiE+G`-wo߫V`fio(}S^4e~V4bHOYb"b#E)dda:'?}׮4繏`{7Z"uny-?ǹ;0MKx{:_pÚmFמ:F " .LFQLG)Q8qN q¯¯3wOvxDb\. BKD9_NN &L:4D{mm o^tֽ:q!ƥ}K+<"m78N< ywsard5+вz~mnG)=}lYݧNj'QJS{S :UYS-952?&O-:W}(!6Mk4+>A>j+i|<<|;ر^߉=HE|V#F)Emm#}/"y GII웻Jі94+v뾧xu~5C95~ūH>c@덉pʃ1/4-A2G%7>m;–Y,cyyaln" ?ƻ!ʪ<{~h~i y.zZB̃/,雋SiC/JFMmBH&&FAbϓO^tubbb_hZ{_QZ-sύodFgO(6]TJA˯#`۶ɟ( %$&+V'~hiYy>922 Wp74Zkq+Ovn錄c>8~GqܲcWꂎz@"1A.}T)uiW4="jJ2W7mU/N0gcqܗOO}?9/wìXžΏ0 >֩(V^Rh32!Hj5`;O28؇2#ݕf3 ?sJd8NJ@7O0 b־?lldщ̡&|9C.8RTWwxWy46ah嘦mh٤&l zCy!PY?: CJyв]dm4ǜҐR޻RլhX{FƯanшQI@x' ao(kUUuxW_Ñ줮[w8 FRJ(8˼)_mQ _!RJhm=!cVmm ?sFOnll6Qk}alY}; "baӌ~M0w,Ggw2W:G/k2%R,_=u`WU R.9T"v,<\Ik޽/2110Ӿxc0gyC&Ny޽JҢrV6N ``یeA16"J³+Rj*;BϜkZPJaÍ<Jyw:NP8/D$ 011z֊Ⱳ3ι֘k1V_"h!JPIΣ'ɜ* aEAd:ݺ>y<}Lp&PlRfTb1]o .2EW\ͮ]38؋rTJsǏP@芎sF\> P^+dYJLbJ C-xϐn> ι$nj,;Ǖa FU *择|h ~izť3ᤓ`K'-f tL7JK+vf2)V'-sFuB4i+m+@My=O҈0"|Yxoj,3]:cо3 $#uŘ%Y"y죯LebqtҢVzq¼X)~>4L׶m~[1_k?kxֺQ`\ |ٛY4Ѯr!)N9{56(iNq}O()Em]=F&u?$HypWUeB\k]JɩSع9 Zqg4ZĊo oMcjZBU]B\TUd34ݝ~:7ڶSUsB0Z3srx 7`:5xcx !qZA!;%͚7&P H<WL!džOb5kF)xor^aujƍ7 Ǡ8/p^(L>ὴ-B,{ۇWzֺ^k]3\EE@7>lYBȝR.oHnXO/}sB|.i@ɥDB4tcm,@ӣgdtJ!lH$_vN166L__'Z)y&kH;:,Y7=J 9cG) V\hjiE;gya~%ks_nC~Er er)muuMg2;֫R)Md) ,¶ 2-wr#F7<-BBn~_(o=KO㭇[Xv eN_SMgSҐ BS헃D%g_N:/pe -wkG*9yYSZS.9cREL !k}<4_Xs#FmҶ:7R$i,fi!~' # !6/S6y@kZkZcX)%5V4P]VGYq%H1!;e1MV<!ϐHO021Dp= HMs~~a)ަu7G^];git!Frl]H/L$=AeUvZE4P\.,xi {-~p?2b#amXAHq)MWǾI_r`S Hz&|{ +ʖ_= (YS(_g0a03M`I&'9vl?MM+m~}*xT۲(fY*V4x@29s{DaY"toGNTO+xCAO~4Ϳ;p`Ѫ:>Ҵ7K 3}+0 387x\)a"/E>qpWB=1 ¨"MP(\xp߫́A3+J] n[ʼnӼaTbZUWb={~2ooKױӰp(CS\S筐R*JغV&&"FA}J>G֐p1ٸbk7 ŘH$JoN <8s^yk_[;gy-;߉DV{c B yce% aJhDȶ 2IdйIB/^n0tNtџdcKj4϶v~- CBcgqx9= PJ) dMsjpYB] GD4RDWX +h{y`,3ꊕ$`zj*N^TP4L:Iz9~6s) Ga:?y*J~?OrMwP\](21sZUD ?ܟQ5Q%ggW6QdO+\@ ̪X'GxN @'4=ˋ+*VwN ne_|(/BDfj5(Dq<*tNt1х!MV.C0 32b#?n0pzj#!38}޴o1KovCJ`8ŗ_"]] rDUy޲@ Ȗ-;xџ'^Y`zEd?0„ DAL18IS]VGq\4o !swV7ˣι%4FѮ~}6)OgS[~Q vcYbL!wG3 7띸*E Pql8=jT\꘿I(z<[6OrR8ºC~ډ]=rNl[g|v TMTղb-o}OrP^Q]<98S¤!k)G(Vkwyqyr޽Nv`N/e p/~NAOk \I:G6]4+K;j$R:Mi #*[AȚT,ʰ,;N{HZTGMoּy) ]%dHء9Պ䠬|<45,\=[bƟ8QXeB3- &dҩ^{>/86bXmZ]]yޚN[(WAHL$YAgDKp=5GHjU&99v簪C0vygln*P)9^͞}lMuiH!̍#DoRBn9l@ xA/_v=ȺT{7Yt2N"4!YN`ae >Q<XMydEB`VU}u]嫇.%e^ánE87Mu\t`cP=AD/G)sI"@MP;)]%fH9'FNsj1pVhY&9=0pfuJ&gޤx+k:!r˭wkl03׼Ku C &ѓYt{.O.zҏ z}/tf_wEp2gvX)GN#I ݭ߽v/ .& и(ZF{e"=V!{zW`, ]+LGz"(UJp|j( #V4, 8B 0 9OkRrlɱl94)'VH9=9W|>PS['G(*I1==C<5"Pg+x'K5EMd؞Af8lG ?D FtoB[je?{k3zQ vZ;%Ɠ,]E>KZ+T/ EJxOZ1i #T<@ I}q9/t'zi(EMqw`mYkU6;[t4DPeckeM;H}_g pMww}k6#H㶏+b8雡Sxp)&C $@'b,fPߑt$RbJ'vznuS ~8='72_`{q纶|Q)Xk}cPz9p7O:'|G~8wx(a 0QCko|0ASD>Ip=4Q, d|F8RcU"/KM opKle M3#i0c%<7׿p&pZq[TR"BpqauIp$ 8~Ĩ!8Սx\ւdT>>Z40ks7 z2IQ}ItԀ<-%S⍤};zIb$I 5K}Q͙D8UguWE$Jh )cu4N tZl+[]M4k8֦Zeq֮M7uIqG 1==tLtR,ƜSrHYt&QP윯Lg' I,3@P'}'R˪e/%-Auv·ñ\> vDJzlӾNv5:|K/Jb6KI9)Zh*ZAi`?S {aiVDԲuy5W7pWeQJk֤#5&V<̺@/GH?^τZL|IJNvI:'P=Ϛt"¨=cud S Q.Ki0 !cJy;LJR;G{BJy޺[^8fK6)=yʊ+(k|&xQ2`L?Ȓ2@Mf 0C`6-%pKpm')c$׻K5[J*U[/#hH!6acB JA _|uMvDyk y)6OPYjœ50VT K}cǻP[ $:]4MEA.y)|B)cf-A?(e|lɉ#P9V)[9t.EiQPDѠ3ϴ;E:+Օ t ȥ~|_N2,ZJLt4! %ա]u {+=p.GhNcŞQI?Nd'yeh n7zi1DB)1S | S#ًZs2|Ɛy$F SxeX{7Vl.Src3E℃Q>b6G ўYCmtկ~=K0f(=LrAS GN'ɹ9<\!a`)֕y[uՍ[09` 9 +57ts6}b4{oqd+J5fa/,97J#6yν99mRWxJyѡyu_TJc`~W>l^q#Ts#2"nD1%fS)FU w{ܯ R{ ˎ󅃏џDsZSQS;LV;7 Od1&1n$ N /.q3~eNɪ]E#oM~}v֯FڦwyZ=<<>Xo稯lfMFV6p02|*=tV!c~]fa5Y^Q_WN|Vs 0ҘދU97OI'N2'8N֭fgg-}V%y]U4 峧p*91#9U kCac_AFңĪy뚇Y_AiuYyTTYЗ-(!JFLt›17uTozc. S;7A&&<ԋ5y;Ro+:' *eYJkWR[@F %SHWP 72k4 qLd'J "zB6{AC0ƁA6U.'F3:Ȅ(9ΜL;D]m8ڥ9}dU "v!;*13Rg^fJyShyy5auA?ɩGHRjo^]׽S)Fm\toy 4WQS@mE#%5ʈfFYDX ~D5Ϡ9tE9So_aU4?Ѽm%&c{n>.KW1Tlb}:j uGi(JgcYj0qn+>) %\!4{LaJso d||u//P_y7iRJ߬nHOy) l+@$($VFIQ9%EeKʈU. ia&FY̒mZ=)+qqoQn >L!qCiDB;Y<%} OgBxB!ØuG)WG9y(Ą{_yesuZmZZey'Wg#C~1Cev@0D $a@˲(.._GimA:uyw֬%;@!JkQVM_Ow:P.s\)ot- ˹"`B,e CRtaEUP<0'}r3[>?G8xU~Nqu;Wm8\RIkբ^5@k+5(By'L&'gBJ3ݶ!/㮻w҅ yqPWUg<e"Qy*167΃sJ\oz]T*UQ<\FԎ`HaNmڜ6DysCask8wP8y9``GJ9lF\G g's Nn͵MLN֪u$| /|7=]O)6s !ĴAKh]q_ap $HH'\1jB^s\|- W1:=6lJBqjY^LsPk""`]w)󭃈,(HC ?䔨Y$Sʣ{4Z+0NvQkhol6C.婧/u]FwiVjZka&%6\F*Ny#8O,22+|Db~d ~Çwc N:FuuCe&oZ(l;@ee-+Wn`44AMK➝2BRՈt7g*1gph9N) *"TF*R(#'88pm=}X]u[i7bEc|\~EMn}P瘊J)K.0i1M6=7'_\kaZ(Th{K*GJyytw"IO-PWJk)..axӝ47"89Cc7ĐBiZx 7m!fy|ϿF9CbȩV 9V-՛^pV̌ɄS#Bv4-@]Vxt-Z, &ֺ*diؠ2^VXbs֔Ìl.jQ]Y[47gj=幽ex)A0ip׳ W2[ᎇhuE^~q흙L} #-b۸oFJ_QP3r6jr+"nfzRJTUqoaۍ /$d8Mx'ݓ= OՃ| )$2mcM*cЙj}f };n YG w0Ia!1Q.oYfr]DyISaP}"dIӗթO67jqR ҊƐƈaɤGG|h;t]䗖oSv|iZqX)oalv;۩meEJ\!8=$4QU4Xo&VEĊ YS^E#d,yX_> ۘ-e\ "Wa6uLĜZi`aD9.% w~mB(02G[6y.773a7 /=o7D)$Z 66 $bY^\CuP. (x'"J60׿Y:Oi;F{w佩b+\Yi`TDWa~|VH)8q/=9!g߆2Y)?ND)%?Ǐ`k/sn:;O299yB=a[Ng 3˲N}vLNy;*?x?~L&=xyӴ~}q{qE*IQ^^ͧvü{Huu=R|>JyUlZV, B~/YF!Y\u_ݼF{_C)LD]m {H 0ihhadd nUkf3oٺCvE\)QJi+֥@tDJkB$1!Đr0XQ|q?d2) Ӣ_}qv-< FŊ߫%roppVBwü~JidY4:}L6M7f٬F "?71<2#?Jyy4뷢<_a7_=Q E=S1И/9{+93֮E{ǂw{))?maÆm(uLE#lïZ  ~d];+]h j?!|$F}*"4(v'8s<ŏUkm7^7no1w2ؗ}TrͿEk>p'8OB7d7R(A 9.*Mi^ͳ; eeUwS+C)uO@ =Sy]` }l8^ZzRXj[^iUɺ$tj))<sbDJfg=Pk_{xaKo1:-uyG0M ԃ\0Lvuy'ȱc2Ji AdyVgVh!{]/&}}ċJ#%d !+87<;qN޼Nفl|1N:8ya  8}k¾+-$4FiZYÔXk*I&'@iI99)HSh4+2G:tGhS^繿 Kتm0 вDk}֚+QT4;sC}rՅE,8CX-e~>G&'9xpW,%Fh,Ry56Y–hW-(v_,? ; qrBk4-V7HQ;ˇ^Gv1JVV%,ik;D_W!))+BoS4QsTM;gt+ndS-~:11Sgv!0qRVh!"Ȋ(̦Yl.]PQWgٳE'`%W1{ndΗBk|Ž7ʒR~,lnoa&:ü$ 3<a[CBݮwt"o\ePJ=Hz"_c^Z.#ˆ*x z̝grY]tdkP*:97YľXyBkD4N.C_[;F9`8& !AMO c `@BA& Ost\-\NX+Xp < !bj3C&QL+*&kAQ=04}cC!9~820G'PC9xa!w&bo_1 Sw"ܱ V )Yl3+ס2KoXOx]"`^WOy :3GO0g;%Yv㐫(R/r (s } u B &FeYZh0y> =2<Ϟc/ -u= c&׭,.0"g"7 6T!vl#sc>{u/Oh Bᾈ)۴74]x7 gMӒ"d]U)}" v4co[ ɡs 5Gg=XR14?5A}D "b{0$L .\4y{_fe:kVS\\O]c^W52LSBDM! C3Dhr̦RtArx4&agaN3Cf<Ԉp4~ B'"1@.b_/xQ} _߃҉/gٓ2Qkqp0շpZ2fԫYz< 4L.Cyυι1t@鎫Fe sYfsF}^ V}N<_`p)alٶ "(XEAVZ<)2},:Ir*#m_YӼ R%a||EƼIJ,,+f"96r/}0jE/)s)cjW#w'Sʯ5<66lj$a~3Kʛy 2:cZ:Yh))+a߭K::N,Q F'qB]={.]h85C9cr=}*rk?vwV렵ٸW Rs%}rNAkDv|uFLBkWY YkX מ|)1!$#3%y?pF<@<Rr0}: }\J [5FRxY<9"SQdE(Q*Qʻ)q1E0B_O24[U'],lOb ]~WjHޏTQ5Syu wq)xnw8~)c 쫬gٲߠ H% k5dƝk> kEj,0% b"vi2Wس_CuK)K{n|>t{P1򨾜j>'kEkƗBg*H%'_aY6Bn!TL&ɌOb{c`'d^{t\i^[uɐ[}q0lM˕G:‚4kb祔c^:?bpg… +37stH:0}en6x˟%/<]BL&* 5&fK9Mq)/iyqtA%kUe[ڛKN]Ě^,"`/ s[EQQm?|XJ߅92m]G.E΃ח U*Cn.j_)Tѧj̿30ڇ!A0=͜ar I3$C^-9#|pk!)?7.x9 @OO;WƝZBFU keZ75F6Tc6"ZȚs2y/1 ʵ:u4xa`C>6Rb/Yм)^=+~uRd`/|_8xbB0?Ft||Z\##|K 0>>zxv8۴吅q 8ĥ)"6>~\8:qM}#͚'ĉ#p\׶ l#bA?)|g g9|8jP(cr,BwV (WliVxxᡁ@0Okn;ɥh$_ckCgriv}>=wGzβ KkBɛ[˪ !J)h&k2%07δt}!d<9;I&0wV/ v 0<H}L&8ob%Hi|޶o&h1L|u֦y~󛱢8fٲUsւ)0oiFx2}X[zVYr_;N(w]_4B@OanC?gĦx>мgx>ΛToZoOMp>40>V Oy V9iq!4 LN,ˢu{jsz]|"R޻&'ƚ{53ўFu(<٪9:΋]B;)B>1::8;~)Yt|0(pw2N%&X,URBK)3\zz&}ax4;ǟ(tLNg{N|Ǽ\G#C9g$^\}p?556]/RP.90 k,U8/u776s ʪ_01چ|\N 0VV*3H鴃J7iI!wG_^ypl}r*jɤSR 5QN@ iZ#1ٰy;_\3\BQQ x:WJv츟ٯ$"@6 S#qe딇(/P( Dy~TOϻ<4:-+F`0||;Xl-"uw$Цi󼕝mKʩorz"mϺ$F:~E'ҐvD\y?Rr8_He@ e~O,T.(ފR*cY^m|cVR[8 JҡSm!ΆԨb)RHG{?MpqrmN>߶Y)\p,d#xۆWY*,l6]v0h15M˙MS8+EdI='LBJIH7_9{Caз*Lq,dt >+~ّeʏ?xԕ4bBAŚjﵫ!'\Ը$WNvKO}ӽmSşذqsOy?\[,d@'73'j%kOe`1.g2"e =YIzS2|zŐƄa\U,dP;jhhhaxǶ?КZ՚.q SE+XrbOu%\GتX(H,N^~]JyEZQKceTQ]VGYqnah;y$cQahT&QPZ*iZ8UQQM.qo/T\7X"u?Mttl2Xq(IoW{R^ ux*SYJ! 4S.Jy~ BROS[V|žKNɛP(L6V^|cR7i7nZW1Fd@ Ara{詑|(T*dN]Ko?s=@ |_EvF]׍kR)eBJc" MUUbY6`~V޴dJKß&~'d3i WWWWWW
Current Directory: /opt/alt/php82/usr/include/php/ext/swoole/ext-src
Viewing File: /opt/alt/php82/usr/include/php/ext/swoole/ext-src/php_swoole_mysql_proto.h
/* +----------------------------------------------------------------------+ | Swoole | +----------------------------------------------------------------------+ | This source file is subject to version 2.0 of the Apache license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.apache.org/licenses/LICENSE-2.0.html | | If you did not receive a copy of the Apache2.0 license and are unable| | to obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Twosee <twose@qq.com> | | Author: Tianfeng Han <rango@swoole.com> | +----------------------------------------------------------------------+ */ #pragma once #include "php_swoole_cxx.h" #include "swoole_util.h" #ifdef SW_USE_OPENSSL #ifndef OPENSSL_NO_RSA #define SW_MYSQL_RSA_SUPPORT #include <openssl/err.h> #include <openssl/rsa.h> #include <openssl/pem.h> #endif #endif enum sw_mysql_command { SW_MYSQL_COM_NULL = -1, SW_MYSQL_COM_SLEEP = 0, SW_MYSQL_COM_QUIT, SW_MYSQL_COM_INIT_DB, SW_MYSQL_COM_QUERY = 3, SW_MYSQL_COM_FIELD_LIST, SW_MYSQL_COM_CREATE_DB, SW_MYSQL_COM_DROP_DB, SW_MYSQL_COM_REFRESH, SW_MYSQL_COM_SHUTDOWN, SW_MYSQL_COM_STATISTICS, SW_MYSQL_COM_PROCESS_INFO, SW_MYSQL_COM_CONNECT, SW_MYSQL_COM_PROCESS_KILL, SW_MYSQL_COM_DEBUG, SW_MYSQL_COM_PING, SW_MYSQL_COM_TIME, SW_MYSQL_COM_DELAYED_INSERT, SW_MYSQL_COM_CHANGE_USER, SW_MYSQL_COM_BINLOG_DUMP, SW_MYSQL_COM_TABLE_DUMP, SW_MYSQL_COM_CONNECT_OUT, SW_MYSQL_COM_REGISTER_SLAVE, SW_MYSQL_COM_STMT_PREPARE, SW_MYSQL_COM_STMT_EXECUTE, SW_MYSQL_COM_STMT_SEND_LONG_DATA, SW_MYSQL_COM_STMT_CLOSE, SW_MYSQL_COM_STMT_RESET, SW_MYSQL_COM_SET_OPTION, SW_MYSQL_COM_STMT_FETCH, SW_MYSQL_COM_DAEMON, SW_MYSQL_COM_END }; enum sw_mysql_handshake_state { SW_MYSQL_HANDSHAKE_WAIT_REQUEST, SW_MYSQL_HANDSHAKE_WAIT_SWITCH, SW_MYSQL_HANDSHAKE_WAIT_SIGNATURE, SW_MYSQL_HANDSHAKE_WAIT_RSA, SW_MYSQL_HANDSHAKE_WAIT_RESULT, SW_MYSQL_HANDSHAKE_COMPLETED, }; #define SW_MYSQL_AUTH_SIGNATRUE_PACKET_LENGTH 2 enum sw_mysql_auth_signature { SW_MYSQL_AUTH_SIGNATURE_ERROR = 0x00, // get signature failed SW_MYSQL_AUTH_SIGNATURE = 0x01, SW_MYSQL_AUTH_SIGNATURE_RSA_PREPARED = 0x02, SW_MYSQL_AUTH_SIGNATURE_SUCCESS = 0x03, SW_MYSQL_AUTH_SIGNATURE_FULL_AUTH_REQUIRED = 0x04, // rsa required }; enum sw_mysql_command_flag { SW_MYSQL_COMMAND_FLAG_QUERY = 1 << 4, SW_MYSQL_COMMAND_FLAG_EXECUTE = 1 << 5, }; enum sw_mysql_state { SW_MYSQL_STATE_CLOSED = 0, SW_MYSQL_STATE_IDLE = 1, SW_MYSQL_STATE_QUERY = 2 | SW_MYSQL_COMMAND_FLAG_QUERY, SW_MYSQL_STATE_QUERY_FETCH = 3 | SW_MYSQL_COMMAND_FLAG_QUERY, SW_MYSQL_STATE_QUERY_MORE_RESULTS = 4 | SW_MYSQL_COMMAND_FLAG_QUERY, SW_MYSQL_STATE_PREPARE = 5 | SW_MYSQL_COMMAND_FLAG_QUERY, SW_MYSQL_STATE_EXECUTE = 6 | SW_MYSQL_COMMAND_FLAG_EXECUTE, SW_MYSQL_STATE_EXECUTE_FETCH = 7 | SW_MYSQL_COMMAND_FLAG_EXECUTE, SW_MYSQL_STATE_EXECUTE_MORE_RESULTS = 8 | SW_MYSQL_COMMAND_FLAG_EXECUTE, }; enum sw_mysql_packet_types { SW_MYSQL_PACKET_OK = 0x0, SW_MYSQL_PACKET_AUTH_SIGNATURE_REQUEST = 0x01, /* not defined in protocol */ SW_MYSQL_PACKET_RAW_DATA, SW_MYSQL_PACKET_GREETING, SW_MYSQL_PACKET_LOGIN, SW_MYSQL_PACKET_AUTH_SWITCH_RESPONSE, SW_MYSQL_PACKET_AUTH_SIGNATURE_RESPONSE, SW_MYSQL_PACKET_LCB, // length coded binary SW_MYSQL_PACKET_FIELD, SW_MYSQL_PACKET_ROW_DATA, SW_MYSQL_PACKET_PREPARE_STATEMENT, /* ======================= */ SW_MYSQL_PACKET_NULL = 0xfb, SW_MYSQL_PACKET_EOF = 0xfe, SW_MYSQL_PACKET_AUTH_SWITCH_REQUEST = 0xfe, SW_MYSQL_PACKET_ERR = 0xff }; enum sw_mysql_field_types { SW_MYSQL_TYPE_DECIMAL, SW_MYSQL_TYPE_TINY, SW_MYSQL_TYPE_SHORT, SW_MYSQL_TYPE_LONG, SW_MYSQL_TYPE_FLOAT, SW_MYSQL_TYPE_DOUBLE, SW_MYSQL_TYPE_NULL, SW_MYSQL_TYPE_TIMESTAMP, SW_MYSQL_TYPE_LONGLONG, SW_MYSQL_TYPE_INT24, SW_MYSQL_TYPE_DATE, SW_MYSQL_TYPE_TIME, SW_MYSQL_TYPE_DATETIME, SW_MYSQL_TYPE_YEAR, SW_MYSQL_TYPE_NEWDATE, SW_MYSQL_TYPE_VARCHAR, SW_MYSQL_TYPE_BIT, SW_MYSQL_TYPE_JSON = 245, SW_MYSQL_TYPE_NEWDECIMAL, SW_MYSQL_TYPE_ENUM, SW_MYSQL_TYPE_SET, SW_MYSQL_TYPE_TINY_BLOB, SW_MYSQL_TYPE_MEDIUM_BLOB, SW_MYSQL_TYPE_LONG_BLOB, SW_MYSQL_TYPE_BLOB, SW_MYSQL_TYPE_VAR_STRING, SW_MYSQL_TYPE_STRING, SW_MYSQL_TYPE_GEOMETRY }; // ref: https://dev.mysql.com/doc/dev/mysql-server/8.0.0/group__group__cs__capabilities__flags.html // use regex: "\#define[ ]+(CLIENT_[A-Z_\d]+)[ ]+(\(?[\dA-Z <]+\)?)\n[ ]+?[ ]+([\s\S ]+?\.) More\.\.\.\n?" // to "SW_MYSQL_$1 = $2, /* $3 */" enum sw_mysql_client_capability_flags { SW_MYSQL_CLIENT_LONG_PASSWORD = 1, /* Use the improved version of Old Password Authentication. */ SW_MYSQL_CLIENT_FOUND_ROWS = 2, /* Send found rows instead of affected rows in EOF_Packet. */ SW_MYSQL_CLIENT_LONG_FLAG = 4, /* Get all column flags. */ SW_MYSQL_CLIENT_CONNECT_WITH_DB = 8, /* Database (schema) name can be specified on connect in Handshake Response Packet. */ SW_MYSQL_CLIENT_NO_SCHEMA = 16, /* Don't allow database.table.column. */ SW_MYSQL_CLIENT_COMPRESS = 32, /* Compression protocol supported. */ SW_MYSQL_CLIENT_ODBC = 64, /* Special handling of ODBC behavior. */ SW_MYSQL_CLIENT_LOCAL_FILES = 128, /* Can use LOAD DATA LOCAL. */ SW_MYSQL_CLIENT_IGNORE_SPACE = 256, /* Ignore spaces before '('. */ SW_MYSQL_CLIENT_PROTOCOL_41 = 512, /* New 4.1 protocol. */ SW_MYSQL_CLIENT_INTERACTIVE = 1024, /* This is an interactive client. */ SW_MYSQL_CLIENT_SSL = 2048, /* Use SSL encryption for the session. */ SW_MYSQL_CLIENT_IGNORE_SIGPIPE = 4096, /* Client only flag. */ SW_MYSQL_CLIENT_TRANSACTIONS = 8192, /* Client knows about transactions. */ SW_MYSQL_CLIENT_RESERVED = 16384, /* flag for 4.1 protocol. */ SW_MYSQL_CLIENT_SECURE_CONNECTION = 32768, /* swoole custom name for RESERVED2. */ SW_MYSQL_CLIENT_RESERVED2 = 32768, /* flag for 4.1 authentication. */ SW_MYSQL_CLIENT_MULTI_STATEMENTS = (1UL << 16), /* Enable/disable multi-stmt support. */ SW_MYSQL_CLIENT_MULTI_RESULTS = (1UL << 17), /* Enable/disable multi-results. */ SW_MYSQL_CLIENT_PS_MULTI_RESULTS = (1UL << 18), /* Multi-results and OUT parameters in PS-protocol. */ SW_MYSQL_CLIENT_PLUGIN_AUTH = (1UL << 19), /* Client supports plugin authentication. */ SW_MYSQL_CLIENT_CONNECT_ATTRS = (1UL << 20), /* Client supports connection attributes. */ SW_MYSQL_CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA = (1UL << 21), /* Enable authentication response packet to be larger than 255 bytes. */ SW_MYSQL_CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS = (1UL << 22), /* Don't close the connection for a user account with expired password. */ SW_MYSQL_CLIENT_SESSION_TRACK = (1UL << 23), /* Capable of handling server state change information. */ SW_MYSQL_CLIENT_DEPRECATE_EOF = (1UL << 24), /* Client no longer needs EOF_Packet and will use OK_Packet instead. */ SW_MYSQL_CLIENT_SSL_VERIFY_SERVER_CERT = (1UL << 30), /* Verify server certificate. */ SW_MYSQL_CLIENT_REMEMBER_OPTIONS = (1UL << 31) /* Don't reset the options after an unsuccessful connect. */ }; // ref: https://dev.mysql.com/doc/internals/en/status-flags.html enum sw_mysql_server_status_flags { SW_MYSQL_SERVER_STATUS_IN_TRANS = 0x0001, // a transaction is active SW_MYSQL_SERVER_STATUS_AUTOCOMMIT = 0x0002, //auto-commit is enabled SW_MYSQL_SERVER_MORE_RESULTS_EXISTS = 0x0008, SW_MYSQL_SERVER_STATUS_NO_GOOD_INDEX_USED = 0x0010, SW_MYSQL_SERVER_STATUS_NO_INDEX_USED = 0x0020, SW_MYSQL_SERVER_STATUS_CURSOR_EXISTS = 0x0040, // Used by Binary Protocol Resultset to signal that COM_STMT_FETCH must be used to fetch the row-data. SW_MYSQL_SERVER_STATUS_LAST_ROW_SENT = 0x0080, SW_MYSQL_SERVER_STATUS_DB_DROPPED = 0x0100, SW_MYSQL_SERVER_STATUS_NO_BACKSLASH_ESCAPES = 0x0200, SW_MYSQL_SERVER_STATUS_METADATA_CHANGED = 0x0400, SW_MYSQL_SERVER_QUERY_WAS_SLOW = 0x0800, SW_MYSQL_SERVER_PS_OUT_PARAMS = 0x1000, SW_MYSQL_SERVER_STATUS_IN_TRANS_READONLY = 0x2000, // in a read-only transaction SW_MYSQL_SERVER_SESSION_STATE_CHANGED = 0x4000 // connection state information has changed }; #define SW_MYSQL_NO_RSA_ERROR "MySQL8 caching_sha2_password authentication plugin need enable OpenSSL support" #define SW_MYSQL_NOT_NULL_FLAG 1 #define SW_MYSQL_PRI_KEY_FLAG 2 #define SW_MYSQL_UNIQUE_KEY_FLAG 4 #define SW_MYSQL_MULTIPLE_KEY_FLAG 8 #define SW_MYSQL_BLOB_FLAG 16 #define SW_MYSQL_UNSIGNED_FLAG 32 #define SW_MYSQL_ZEROFILL_FLAG 64 #define SW_MYSQL_BINARY_FLAG 128 #define SW_MYSQL_ENUM_FLAG 256 #define SW_MYSQL_AUTO_INCREMENT_FLAG 512 #define SW_MYSQL_TIMESTAMP_FLAG 1024 #define SW_MYSQL_SET_FLAG 2048 #define SW_MYSQL_NO_DEFAULT_VALUE_FLAG 4096 #define SW_MYSQL_ON_UPDATE_NOW_FLAG 8192 #define SW_MYSQL_PART_KEY_FLAG 16384 #define SW_MYSQL_GROUP_FLAG 32768 #define SW_MYSQL_NUM_FLAG 32768 /* int<3> payload_length + int<1> sequence_id */ #define SW_MYSQL_PACKET_HEADER_SIZE 4 #define SW_MYSQL_PACKET_TYPE_OFFSET 5 #define SW_MYSQL_PACKET_EOF_MAX_SIZE 9 #define SW_MYSQL_PACKET_PREPARED_OK_SIZE 12 #define SW_MYSQL_MAX_PACKET_BODY_SIZE 0x00ffffff #define SW_MYSQL_MAX_PACKET_SIZE (SW_MYSQL_PACKET_HEADER_SIZE + SW_MYSQL_MAX_PACKET_BODY_SIZE) // nonce: a number or bit string used only once, in security engineering // other names on doc: challenge/scramble/salt #define SW_MYSQL_NONCE_LENGTH 20 // clang-format off #define sw_mysql_uint2korr2korr(A) (uint16_t) (((uint16_t) ((uchar) (A)[0])) +\ ((uint16_t) ((uchar) (A)[1]) << 8)) #define sw_mysql_uint2korr3korr(A) (uint32_t) (((uint32_t) ((uchar) (A)[0])) +\ (((uint32_t) ((uchar) (A)[1])) << 8) +\ (((uint32_t) ((uchar) (A)[2])) << 16)) #define sw_mysql_uint2korr4korr(A) (uint32_t) (((uint32_t) ((uchar) (A)[0])) +\ (((uint32_t) ((uchar) (A)[1])) << 8) +\ (((uint32_t) ((uchar) (A)[2])) << 16) +\ (((uint32_t) ((uchar) (A)[3])) << 24)) #define sw_mysql_uint2korr8korr(A) ((uint64_t)(((uint32_t) ((uchar) (A)[0])) +\ (((uint32_t) ((uchar) (A)[1])) << 8) +\ (((uint32_t) ((uchar) (A)[2])) << 16) +\ (((uint32_t) ((uchar) (A)[3])) << 24)) +\ (((uint64_t) (((uint32_t) ((uchar) (A)[4])) +\ (((uint32_t) ((uchar) (A)[5])) << 8) +\ (((uint32_t) ((uchar) (A)[6])) << 16) +\ (((uint32_t) ((uchar) (A)[7])) << 24))) << 32)) #define sw_mysql_int1store(T,A) do { *((int8_t*) (T)) = (int8_t)(A); } while(0) #define sw_mysql_int2store(T,A) do { uint32_t def_temp= (uint32_t) (A) ;\ *((uchar*) (T)) = (uchar)(def_temp); \ *((uchar*) (T+1)) = (uchar)((def_temp >> 8)); } while (0) #define sw_mysql_int3store(T,A) do { /*lint -save -e734 */\ *(((char *)(T))) = (char) ((A));\ *(((char *)(T))+1) = (char) (((A) >> 8));\ *(((char *)(T))+2) = (char) (((A) >> 16)); \ /*lint -restore */} while (0) #define sw_mysql_int4store(T,A) do { \ *(((char *)(T))) = (char) ((A));\ *(((char *)(T))+1) = (char) (((A) >> 8));\ *(((char *)(T))+2) = (char) (((A) >> 16));\ *(((char *)(T))+3) = (char) (((A) >> 24)); } while (0) #define sw_mysql_int5store(T,A) do { \ *(((char *)(T))) = (char)((A));\ *(((char *)(T))+1) = (char)(((A) >> 8));\ *(((char *)(T))+2) = (char)(((A) >> 16));\ *(((char *)(T))+3) = (char)(((A) >> 24)); \ *(((char *)(T))+4) = (char)(((A) >> 32)); } while (0) /* Based on int5store() from Andrey Hristov */ #define sw_mysql_int6store(T,A) do { \ *(((char *)(T))) = (char)((A));\ *(((char *)(T))+1) = (char)(((A) >> 8));\ *(((char *)(T))+2) = (char)(((A) >> 16));\ *(((char *)(T))+3) = (char)(((A) >> 24)); \ *(((char *)(T))+4) = (char)(((A) >> 32)); \ *(((char *)(T))+5) = (char)(((A) >> 40)); } while (0) // clang-format on #define sw_mysql_int8store(T,A) do { \ uint32_t def_temp= (uint32_t) (A), def_temp2= (uint32_t) ((A) >> 32); \ sw_mysql_int4store((T),def_temp); \ sw_mysql_int4store((T+4),def_temp2); } while (0) #define sw_mysql_doublestore(T,A) do { \ double def_temp = (double) A; \ memcpy(T, &def_temp, sizeof(double)); \ } while (0) #if defined(SW_DEBUG) && defined(SW_LOG_TRACE_OPEN) #define swMysqlPacketDump(length, number, data, title) \ if (SW_LOG_TRACE >= sw_logger()->get_level() && (SW_TRACE_MYSQL_CLIENT & SwooleG.trace_flags)) \ { \ swoole_debug("+----------+------------+-------------------------------------------------------+"); \ swoole_debug("| P#%-6u | L%-9u | %-10u %42s |", number, SW_MYSQL_PACKET_HEADER_SIZE + length, length, title); \ swoole_hex_dump(data, length); \ } #else #define swMysqlPacketDump(length, number, data, title) #endif namespace swoole { namespace mysql { //-----------------------------------namespace begin-------------------------------------------- char get_charset(const char *name); uint8_t get_static_type_size(uint8_t type); inline uint8_t read_lcb_size(const char *p) { switch ((uchar) p[0]) { case 251: return 1; case 252: return 3; case 253: return 4; case 254: return 9; default: return 1; } } inline uint8_t read_lcb(const char *p, uint64_t *length, bool *nul) { switch ((uchar) p[0]) { case 251: /* fb : 1 octet */ *length = 0; *nul = true; return 1; case 252: /* fc : 2 octets */ *length = sw_mysql_uint2korr2korr(p + 1); *nul = false; return 3; case 253: /* fd : 3 octets */ *length = sw_mysql_uint2korr3korr(p + 1); *nul = false; return 4; case 254: /* fe : 8 octets */ *length = sw_mysql_uint2korr8korr(p + 1); *nul = false; return 9; default: *length = (uchar) p[0]; *nul = false; return 1; } } inline uint8_t read_lcb(const char *p, uint32_t *length, bool *nul) { uint64_t _r; uint8_t ret = read_lcb(p, &_r, nul); *length = _r; return ret; } inline uint8_t write_lcb(char *p, uint64_t length, bool nul = false) { if (nul) { sw_mysql_int1store(p++, 251); return 1; } if (length <= 250) { sw_mysql_int1store(p, length); return 1; } else if (length <= 0xffff) { sw_mysql_int1store(p++, 252); sw_mysql_int2store(p, length); return 3; } else if (length <= 0xffffff) { sw_mysql_int1store(p++, 253); sw_mysql_int3store(p, length); return 4; } else { sw_mysql_int1store(p++, 254); sw_mysql_int8store(p, length); return 9; } } class packet { public: static inline uint32_t get_length(const char *data) { return sw_mysql_uint2korr3korr(data); } static inline uint32_t get_number(const char *data) { return (uint8_t) data[3]; } static inline void set_length(char *buffer, uint32_t length) { buffer[0] = length; buffer[1] = length >> 8; buffer[2] = length >> 16; } static inline void set_number(char *buffer, uint8_t number) { buffer[3] = number; } static inline void set_header(char *buffer, uint32_t length, uint8_t number) { set_length(buffer, length); set_number(buffer, number); } }; class server_packet : public packet { public: struct header { uint32_t length :24; uint32_t number :8; header() : length(0), number(0) { } } header; server_packet() { } server_packet(const char *data) { parse(data); } inline void parse(const char *data) { header.length = packet::get_length(data); header.number = packet::get_number(data); } static inline uint8_t parse_type(const char *data) { if (sw_unlikely(!data)) { return SW_MYSQL_PACKET_NULL; } return (uint8_t) data[SW_MYSQL_PACKET_HEADER_SIZE]; } static inline bool is_eof(const char *data) { return (uint8_t) data[SW_MYSQL_PACKET_HEADER_SIZE] == SW_MYSQL_PACKET_EOF; } static inline bool is_ok(const char *data) { return (uint8_t) data[SW_MYSQL_PACKET_HEADER_SIZE] == SW_MYSQL_PACKET_OK; } static inline bool is_err(const char *data) { return (uint8_t) data[SW_MYSQL_PACKET_HEADER_SIZE] == SW_MYSQL_PACKET_ERR; } }; class server_status { public: int16_t status = 0; void operator =(uint16_t status) { this->status = status; } inline bool more_results_exists() { bool b = !!(status & SW_MYSQL_SERVER_MORE_RESULTS_EXISTS); swoole_trace_log(SW_TRACE_MYSQL_CLIENT, "More results exist = %u", b); return b; } }; class client_packet : public packet { public: client_packet(size_t body_size = 1024 - SW_MYSQL_PACKET_HEADER_SIZE) { SW_ASSERT(body_size > 0); if (body_size <= 4) { data.header = stack_buffer; } else { data.header = new char[SW_MEM_ALIGNED_SIZE(SW_MYSQL_PACKET_HEADER_SIZE + body_size)](); } data.body = data.header + SW_MYSQL_PACKET_HEADER_SIZE; } inline const char* get_data() { return data.header; } inline uint32_t get_data_length() { return SW_MYSQL_PACKET_HEADER_SIZE + get_length(); } inline uint32_t get_length() { return sw_mysql_uint2korr3korr(data.header); } inline uint8_t get_number() { return (uint8_t) data.header[3]; } inline const char* get_body() { return data.body; } inline void set_header(uint32_t length, uint8_t number) { packet::set_header(data.header, length, number); } ~client_packet() { if (data.header != stack_buffer) { delete[] data.header; } } protected: struct { char *header = nullptr; char *body = nullptr; } data; char stack_buffer[SW_MYSQL_PACKET_HEADER_SIZE + 4] = {}; }; class command_packet : public client_packet { public: command_packet(enum sw_mysql_command command, const char *sql = nullptr, size_t length = 0) : client_packet(1 + length) { set_command(command); set_header(1 + length, 0); if (length > 0) { memcpy(data.body + 1, sql, length); } }; inline void set_command(enum sw_mysql_command command) { data.body[0] = (char) command; } }; class err_packet : public server_packet { public: uint16_t code; std::string msg; char sql_state[5 + 1]; err_packet(const char *data); }; class ok_packet : public server_packet { public: uint64_t affected_rows = 0; uint64_t last_insert_id = 0; mysql::server_status server_status; unsigned int warning_count = 0; ok_packet() { } ok_packet(const char *data); }; class eof_packet : public server_packet { public: uint16_t warning_count; mysql::server_status server_status; eof_packet(const char *data); }; class raw_data_packet : public server_packet { public: const char *body; raw_data_packet(const char *data) : server_packet(data), body(data + SW_MYSQL_PACKET_HEADER_SIZE) { swMysqlPacketDump(header.length, header.number, data, "Protocol::RawData"); } }; class greeting_packet : public server_packet { public: uint8_t protocol_version = 0; std::string server_version = ""; int connection_id = 0; char auth_plugin_data[SW_MYSQL_NONCE_LENGTH + 1] = {}; // nonce + '\0' uint8_t auth_plugin_data_length = 0; char filler = 0; int capability_flags = 0; char charset = SW_MYSQL_DEFAULT_CHARSET; mysql::server_status status_flags; char reserved[10] = {}; std::string auth_plugin_name = ""; greeting_packet(const char *data); }; class login_packet : public client_packet { public: login_packet( greeting_packet *greeting_packet, const std::string &user, const std::string &password, std::string database, char charset ); }; class auth_switch_request_packet : public server_packet { public: std::string auth_method_name = "mysql_native_password"; char auth_method_data[SW_MYSQL_NONCE_LENGTH + 1] = {}; auth_switch_request_packet(const char *data); }; class auth_switch_response_packet : public client_packet { public: auth_switch_response_packet(auth_switch_request_packet *req, const std::string &password); }; class auth_signature_request_packet : public server_packet { public: char data[2] = {}; auth_signature_request_packet(const char *data) :server_packet(data) { swMysqlPacketDump(header.length, header.number, data, "Protocol::AuthSignatureRequest"); memcpy(&this->data, data + SW_MYSQL_PACKET_HEADER_SIZE, 2); } inline bool is_full_auth_required() { return data[1] == SW_MYSQL_AUTH_SIGNATURE_FULL_AUTH_REQUIRED; } inline bool is_vaild() { return data[0] == SW_MYSQL_AUTH_SIGNATURE && (data[1] == SW_MYSQL_AUTH_SIGNATURE_SUCCESS || data[1] == SW_MYSQL_AUTH_SIGNATURE_FULL_AUTH_REQUIRED); } }; class auth_signature_prepared_packet : public client_packet { public: auth_signature_prepared_packet(uint8_t number) : client_packet(1) { set_header(1, number); data.body[0] = SW_MYSQL_AUTH_SIGNATURE_RSA_PREPARED; } }; class auth_signature_response_packet : public client_packet { public: auth_signature_response_packet(raw_data_packet *raw_data_pakcet, const std::string &password, const char *auth_plugin_data); }; class lcb_packet : public server_packet { public: uint32_t length = 0; bool nul = 0; lcb_packet(const char *data) : server_packet(data) { swMysqlPacketDump(header.length, header.number, data, "Protocol::LengthCodedBinary"); bytes_length = read_lcb(data + SW_MYSQL_PACKET_HEADER_SIZE, &length, &nul); swoole_trace_log(SW_TRACE_MYSQL_CLIENT, "binary_length=%u, nul=%u", header.length, nul); } bool is_vaild() { return header.length == bytes_length; } private: uint8_t bytes_length; }; class field_packet : public server_packet { public: char *catalog = nullptr; /* Catalog for table */ uint32_t catalog_length = 0; char *database = nullptr; /* Database for table */ uint32_t database_length = 0; char *table = nullptr; /* Table of column if column was a field */ uint32_t table_length = 0; char *org_table = nullptr; /* Org table name, if table was an alias */ uint32_t org_table_length = 0; char *name = nullptr; /* Name of column */ uint32_t name_length = 0; char *org_name = nullptr; /* Original column name, if an alias */ uint32_t org_name_length = 0; char charset = 0; uint64_t length = 0; /* Width of column (create length) */ uint8_t type = 0; /* Type of field. See mysql_com.h for types */ uint32_t flags = 0; /* Div flags */ uint32_t decimals = 0; /* Number of decimals in field */ char *def = nullptr; /* Default value (set by mysql_list_fields) */ uint32_t def_length = 0; void *extension = nullptr; field_packet() { } field_packet(const char *data) { parse(data); } void parse(const char *data); ~field_packet() { if (body) { delete[] body; } } protected: char *body = nullptr; }; typedef field_packet param_packet; class row_data { public: char stack_buffer[32]; struct { uint64_t length; // binary code length bool nul; // is nul? } text; row_data(const char *data) { next_packet(data); } inline void next_packet(const char *data) { read_ptr = packet_body = data + SW_MYSQL_PACKET_HEADER_SIZE; packet_eof = packet_body + packet::get_length(data); } inline bool eof() { return read_ptr == packet_eof; } inline const char* read(size_t length) { if (sw_likely(read_ptr + length <= packet_eof)) { const char *p = read_ptr; read_ptr += length; return p; } return nullptr; } inline uint32_t recv(char *buf, size_t size) { uint32_t readable_length = packet_eof - read_ptr; uint32_t read_bytes = SW_MIN(readable_length, size); if (sw_likely(read_bytes > 0)) { memcpy(buf, read_ptr, read_bytes); read_ptr += read_bytes; } return read_bytes; } protected: const char *packet_body; const char *packet_eof; const char *read_ptr; }; class row_data_text { public: uint64_t length = 0; bool nul = false; const char *body = nullptr; row_data_text(const char **pp) { body = *pp + read_lcb(*pp, &length, &nul); *pp = body + length; swoole_trace_log( SW_TRACE_MYSQL_CLIENT, "text[%" PRIu64 "]: %.*s%s", length, (int) SW_MIN(64, length), body, nul ? "null" : ((length > 64 /*|| length > readable_length*/) ? "..." : "") ); } }; inline std::string datetime(const char *p, uint8_t length, uint32_t decimals) { uint16_t y = 0; uint8_t m = 0, d = 0, h = 0, i = 0, s = 0; uint32_t sp = 0; if (length != 0) { y = sw_mysql_uint2korr2korr(p); m = *(uint8_t *) (p + 2); d = *(uint8_t *) (p + 3); if (length > 4) { h = *(uint8_t *) (p + 4); i = *(uint8_t *) (p + 5); s = *(uint8_t *) (p + 6); } if (length > 7) { sp = sw_mysql_uint2korr4korr(p + 7); } } if (decimals > 0 && decimals < 7) { return swoole::std_string::format( "%04u-%02u-%02u %02u:%02u:%02u.%0*u", y, m, d, h, i, s, decimals, (uint32_t) (sp / ::pow(10, (double) (6 - decimals))) ); } else { return swoole::std_string::format( "%04u-%02u-%02u %02u:%02u:%02u", y, m, d, h, i, s ); } } inline std::string time(const char *p, uint8_t length, uint32_t decimals) { bool neg = false; uint32_t d = 0, sp = 0; uint8_t h = 0, m = 0, s = 0; if (length != 0) { neg = (bool) *((uint8_t *) p); d = sw_mysql_uint2korr4korr(p + 1); h = *(uint8_t *) (p + 5); m = *(uint8_t *) (p + 6); s = *(uint8_t *) (p + 7); if (length > 8) { sp = sw_mysql_uint2korr4korr(p + 8); } if (d != 0) { /* Convert days to hours at once */ h += d * 24; } } if (decimals > 0 && decimals < 7) { return swoole::std_string::format( "%s%02u:%02u:%02u.%0*u", (neg ? "-" : ""), h, m, s, decimals, (uint32_t) (sp / ::pow(10, (double) (6 - decimals))) ); } else { return swoole::std_string::format( "%s%02u:%02u:%02u", (neg ? "-" : ""), h, m, s ); } } inline std::string date(const char *p, uint8_t length) { uint16_t y = 0; uint8_t m = 0, d = 0; if (length != 0) { y = sw_mysql_uint2korr2korr(p); m = *(uint8_t *) (p + 2); d = *(uint8_t *) (p + 3); } return swoole::std_string::format("%04u-%02u-%02u", y, m, d); } inline std::string year(const char *p, uint8_t length) { uint16_t y = 0; if (length != 0) { y = sw_mysql_uint2korr2korr(p); } return swoole::std_string::format("%04u", y); } class result_info { public: ok_packet ok; inline void alloc_fields(uint32_t length) { clear_fields(); if (sw_likely(length != 0)) { fields.info = new field_packet[length]; fields.length = length; } else { fields.length = 0; fields.info = nullptr; } } inline uint32_t get_fields_length() { return fields.length; } inline field_packet* get_fields(uint32_t index) { return fields.info; } inline field_packet* get_field(uint32_t index) { return &fields.info[index]; } inline void set_field(uint32_t index, const char *data) { fields.info[index].parse(data); } inline void clear_fields() { if (fields.length > 0) { delete[] fields.info; } } ~result_info() { clear_fields(); } protected: struct { uint32_t length = 0; field_packet *info = nullptr; } fields; }; class statement : public server_packet { public: uint32_t id = 0; uint16_t field_count = 0; uint16_t param_count = 0; uint16_t warning_count = 0; statement() { } statement(const char* data) : server_packet(data) { swMysqlPacketDump(header.length, header.number, data, "COM_STMT_PREPARE_OK_Packet"); // skip the packet header data += SW_MYSQL_PACKET_HEADER_SIZE; // status (1) -- [00] OK SW_ASSERT(data[0] == SW_MYSQL_PACKET_OK); data += 1; // statement_id (4) -- statement-id id = sw_mysql_uint2korr4korr(data); data += 4; // num_columns (2) -- number of columns field_count = sw_mysql_uint2korr2korr(data); data += 2; // num_params (2) -- number of params param_count = sw_mysql_uint2korr2korr(data); data += 2; // reserved_1 (1) -- [00] filler data += 1; // warning_count (2) -- number of warnings warning_count = sw_mysql_uint2korr2korr(data); swoole_trace_log( SW_TRACE_MYSQL_CLIENT, "statement_id=%u, field_count=%u, param_count=%u, warning_count=%u", id, field_count, param_count, warning_count ); } }; class null_bitmap { public: static uint32_t get_size(uint32_t field_length) { return ((field_length + 9) / 8) + 1; } null_bitmap(const char *p, uint32_t size) : size(size) { map = new char[size]; memcpy(map, p, size); swoole_trace_log(SW_TRACE_MYSQL_CLIENT, "null_count=%u", size); } inline bool is_null(size_t i) { return ((map + 1)[((i + 2) / 8)] & (0x01 << ((i + 2) % 8))) != 0; } ~null_bitmap() { delete[] map; } protected: uint32_t size; char *map; }; //-----------------------------------namespace end-------------------------------------------- }}